Просмотр исходного кода

feat: 添加痕迹物证导入及地图配置

bill 1 неделя назад
Родитель
Сommit
3d4767050b

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
public/icons/map.svg


+ 4 - 0
src/core/components/image/image.vue

@@ -87,4 +87,8 @@ const { shape, tData, data, operateMenus, describes } = useComponentStatus<
   ],
   debug: true,
 });
+
+if (props.data.key === "kankan-floor-cover") {
+  operateMenus[1].hide = false
+}
 </script>

+ 1 - 0
src/core/components/line-icon/temp-icon.vue

@@ -35,6 +35,7 @@ const rangInner = computed(() => line.value && isRangInner(line.value, props.dat
 
 const data = computed(() => {
   if (mat.value) {
+    console.log(props.data);
     const iconData = {
       ...props.data,
       mat: mat.value,

+ 2 - 0
src/core/hook/use-component.ts

@@ -54,6 +54,7 @@ export const useComponentMenus = <T extends DrawItem>(
   const operateMenus: Array<{
     icon?: any;
     label?: string;
+    hide?: boolean,
     handler: () => void;
   }> = shallowReactive([]);
 
@@ -69,6 +70,7 @@ export const useComponentMenus = <T extends DrawItem>(
     }),
     reactive({
       label: "隐藏",
+      hide: true,
       handler() {
         data.value.hide = true;
         emit("updateShape", { ...data.value });

+ 1 - 1
src/core/hook/use-global-vars.ts

@@ -468,7 +468,7 @@ export const useMountMenusFilter = installGlobalVar(() => {
 });
 
 export const useMouseMenusFilter = installGlobalVar(() => {
-  type Menu = { icon?: any; label?: string; handler: () => void };
+  type Menu = { icon?: any; hide?: boolean, label?: string; handler: () => void };
   const propsFilter = getFilters<Menu[]>();
   return {
     setMenusFilter: propsFilter.setFilter,

+ 6 - 4
src/core/html-mount/propertys/hover-operate.vue

@@ -9,9 +9,11 @@
         ref="layout"
       >
         <ElMenu>
-          <ElMenuItem v-for="menu in menus" @click="clickHandler(menu.handler)">
-            <span class="menu-item">{{ menu.label }}</span>
-          </ElMenuItem>
+          <template v-for="menu in menus">
+            <ElMenuItem v-if="!menu.hide" @click="clickHandler(menu.handler)">
+              <span class="menu-item">{{ menu.label }}</span>
+            </ElMenuItem>
+          </template>
         </ElMenu>
       </div>
     </transition>
@@ -34,7 +36,7 @@ import { useStore } from "@/core/store/index.ts";
 const props = defineProps<{
   target: DC<EntityShape> | undefined;
   data?: Record<string, any>;
-  menus: Array<{ icon?: any; label?: string; handler: () => void }>;
+  menus: Array<{ icon?: any; label?: string; handler: () => void; hide?: boolean }>;
 }>();
 const emit = defineEmits<{
   (e: "show" | "hide"): void;

+ 1 - 1
src/example/components/header/actions.ts

@@ -91,7 +91,7 @@ export const getHeaderActions = (draw: Draw) => {
         }
         return true
       }),
-      text: "显示全部",
+      text: "显示底图",
       icon: "a-visible",
     }),
     expose: reactive({

+ 4 - 0
src/example/constant.ts

@@ -205,3 +205,7 @@ export const styleIconMap = {
   "style-16": "danke_o",
   "style-17": "chelunhenji_o",
 };
+
+export const traceIconMap = {
+  
+}

+ 2 - 1
src/example/dialog/ai/ai.vue

@@ -41,6 +41,7 @@ const scene = ref<Scene>();
 const options = {
   [SCENE_TYPE.mesh]: [
     { value: "signage", label: "指示牌" },
+    { value: "traces", label: "痕迹物证" },
     // { value: "hot", label: "多媒体标签" },
   ],
   [SCENE_TYPE.cloud]: [{ value: "hot", label: "热点" }],
@@ -59,7 +60,7 @@ watch(scene, () => {
   if (!scene.value) {
     syncTags.value = [];
   } else {
-    syncTags.value = [options[scene.value.type][0].value];
+    syncTags.value = options[scene.value.type].map((item) => item.value);
     if (scene.value.type === SCENE_TYPE.mesh) {
       getFloors(scene.value).then((data) => {
         if (token === curToken) {

+ 30 - 14
src/example/dialog/basemap/leaflet/index.vue

@@ -51,9 +51,17 @@
     </div>
 
     <div class="map" ref="mapEle">
-      <div class="tiles-select">
-        <el-dropdown placement="bottom-end">
-          <icon name="close" size="30px" color="#000" />
+      <div class="tiles-select" v-if="tileGroups.length > 1">
+        <el-select v-model="groupIndex" style="width: 100px">
+          <el-option
+            :label="group.name"
+            :value="ndx"
+            v-for="(group, ndx) in tileGroups"
+          />
+        </el-select>
+
+        <!-- <el-dropdown placement="bottom-end">
+          <icon name="floor" size="30px" color="#fff" class="tiles-select-icon" />
           <template #dropdown>
             <el-dropdown-menu>
               <el-dropdown-item
@@ -64,7 +72,7 @@
               </el-dropdown-item>
             </el-dropdown-menu>
           </template>
-        </el-dropdown>
+        </el-dropdown> -->
       </div>
     </div>
   </div>
@@ -219,8 +227,13 @@ defineExpose({ submit });
 .tiles-select {
   position: absolute;
   z-index: 9999;
-  right: 0px;
-  top: 0px;
+  right: 20px;
+  top: 20px;
+}
+
+.tiles-select-icon {
+  filter: drop-shadow(0 0 3px rgba(0, 0, 0, 1));
+  // box-shadow: 0 0 3px #000;
 }
 
 .latlng-result {
@@ -255,23 +268,22 @@ defineExpose({ submit });
 
 .name-result {
   margin-top: 10px;
-  border: 1px solid #d9d9d9;
   border-radius: 2px;
-  max-height: 600px;
+  max-height: 560px;
   overflow-y: auto;
 
   .address-item {
-    padding: 15px 6px;
-    margin: 0 10px;
+    padding: 16px 0px;
     display: flex;
-    align-items: center;
     justify-content: center;
     flex-direction: column;
-    color: #999;
+    color: rgba(0, 0, 0, 0.45);
+    font-size: 14px;
+    line-height: 22px;
     span {
       font-size: 14px;
-      font-weight: bold;
-      color: #333;
+      color: #000;
+      margin-bottom: 4px;
     }
     cursor: pointer;
 
@@ -285,6 +297,10 @@ defineExpose({ submit });
     }
   }
 }
+
+.input-with-select {
+  --el-fill-color-light: #ffffff;
+}
 </style>
 
 <style lang="scss">

+ 17 - 20
src/example/fuse/enter-shared.ts

@@ -4,7 +4,6 @@ import type { StoreData } from "@/core/store/store";
 import { token, params, urlUpdateQuery, urlGetQuery } from "../env";
 import { genLoading } from "../loadding";
 import { tempStrFill } from "@/utils/shared";
-import { gdSearch } from "../dialog/basemap/leaflet/mock";
 import { latlngStrTransform } from "../dialog/basemap/leaflet/useLeaflet";
 
 export const SCENE_TYPE = {
@@ -74,29 +73,27 @@ export const postFile = (url: string, data: Record<string, any>) => {
 };
 
 export const login = (isBack = true) => {
-  if (import.meta.env.VITE_LOGIN_VIEW) {
-    const p: any = { ...params.value };
-    delete p.token;
+  const p: any = { ...params.value };
+  delete p.token;
 
-    const cur = urlUpdateQuery(location.href, p, true);
-    let link = tempStrFill(import.meta.env.VITE_LOGIN_VIEW, {
-      redirect: escape(cur),
-    });
+  const cur = urlUpdateQuery(location.href, p, true);
+  let link = tempStrFill(import.meta.env.VITE_LOGIN_VIEW, {
+    redirect: escape(cur),
+  });
 
-    if (!isBack) {
-      let url: URL;
-      try {
-        url = new URL(link);
-      } catch {
-        url = new URL(link, location.origin);
-      }
-      url.searchParams.delete("redirect");
-      const query = urlGetQuery(url.toString());
-      delete query["redirect"];
-      link = urlUpdateQuery(url.toString(), query, true);
+  if (!isBack) {
+    let url: URL;
+    try {
+      url = new URL(link);
+    } catch {
+      url = new URL(link, location.origin);
     }
-    location.replace(link);
+    url.searchParams.delete("redirect");
+    const query = urlGetQuery(url.toString());
+    delete query["redirect"];
+    link = urlUpdateQuery(url.toString(), query, true);
   }
+  location.replace(link);
 };
 
 const after = async (fet: Promise<Response>) => {

+ 29 - 5
src/example/fuse/enter.ts

@@ -5,17 +5,40 @@ import { asyncTimeout } from "@/utils/shared";
 
 window.platform = { ...platform };
 
+let isLoging = false;
+window.platform.login = (isBack = true) => {
+  if (isLoging) {
+    throw "登录中";
+  }
+  isLoging = true;
+  if (import.meta.env.DEV) {
+    platform
+      .post("/service/manage/login", {
+        password: "JwiuK95dExMjM0NTY=7nHGf5ySQWSuC4G1An",
+        username: "super-admin",
+        userName: "super-admin",
+      })
+      .then((res) => {
+        params.value.token = res.token;
+        setTimeout(() => location.reload(), 1000);
+        isLoging = false;
+      });
+    return;
+  }
+  return platform.login(isBack);
+};
+
 // 场景码+楼层 转绘图id
 const sceneTransform = async (m: string, subGroup: string = "0") => {
   const data = await platform.get("fusion/caseOverview/info", {
     num: m,
     subGroup,
   });
-  preventReload();
-  if (data.id) {
+  if (data?.id) {
     params.value.overviewId = data.id;
     delete params.value.m;
     delete params.value.floor;
+    preventReload();
   }
   await asyncTimeout(10);
 };
@@ -30,15 +53,16 @@ if (window.platform.sceneDraw) {
     import(import.meta.env.VITE_ENTRY_EXAMPLE);
   });
 
+  console.log(subgroup)
   window.platform.saveOverviewData = async (id: any, data: any) => {
     const result = await platform.saveOverviewData(id, {
       ...data,
       num: m,
       subGroup: subgroup,
     });
-    const key = `${m}-${subgroup}-draw-kankan-cover`
-    localStorage.setItem(key, data.kankanCover)
-    return result
+    const key = `${m}-${subgroup}-draw-kankan-cover`;
+    localStorage.setItem(key, data.kankanCover);
+    return result;
   };
 } else {
   /* @vite-ignore */

+ 1 - 1
src/example/fuse/views/overview/index.vue

@@ -82,7 +82,7 @@ const initScene = async (draw: Draw) => {
     {
       scene,
       floorName: floor.name,
-      syncs: ["signage"],
+      syncs: ["signage", "traces"],
     },
     draw
   );

+ 1 - 1
src/example/fuse/views/tabulation/slide.vue

@@ -52,7 +52,7 @@ const menus = reactive([
   paper,
   {
     value: uuid(),
-    icon: "drawing",
+    icon: "map",
     name: "地图",
     handler: async () => {
       const result = await selectMap({

+ 2 - 0
src/example/platform/platform-draw.ts

@@ -96,7 +96,9 @@ const getCoverShapes = (cover: SceneResource["cover"]) => {
     url: cover.thumb,
     mat: mat.m,
     width,
+    key: 'kankan-floor-cover',
     height,
+    lock: true,
     cornerRadius: 0,
     zIndex: -2,
   };

+ 151 - 14
src/example/platform/resource-swkk.ts

@@ -10,8 +10,17 @@ import {
 } from "./platform-resource";
 import { lineLen, Pos, zeroEq } from "@/utils/math";
 import { aiIconMap, getIconItem, styleIconMap } from "../constant";
-import { MathUtils, Object3D, Quaternion, Vector3 } from "three";
+import {
+  Euler,
+  MathUtils,
+  Matrix4,
+  Matrix4Tuple,
+  Object3D,
+  Quaternion,
+  Vector3,
+} from "three";
 import { extractConnectedSegments } from "@/utils/polygon";
+import { getImage } from "@/utils/resource";
 
 const fetchResource = genCache(
   (scene: Scene) => scene.m,
@@ -32,17 +41,26 @@ const fetchResource = genCache(
     });
     version = config.version;
 
-    const [userFloorpan, floorplan, hots, billboards, ais, cadInfo, cad] =
-      await Promise.all([
-        get("/user/floorplan.json"),
-        get("/data/floorplan.json", { floors: [] }),
-        get("/user/hot.json", []),
-        get("/user/billboards.json", []),
-        get("/data/floorplan/ai.json", []),
-        get("/data/floorplan/info.json", { floors: [] }),
-        get("/data/floorplan_cad.json", { floors: [] }),
-      ]);
-      
+    const [
+      userFloorpan,
+      floorplan,
+      hots,
+      billboards,
+      ais,
+      cadInfo,
+      cad,
+      traces,
+    ] = await Promise.all([
+      get("/user/floorplan.json"),
+      get("/data/floorplan.json", { floors: [] }),
+      get("/user/hot.json", []),
+      get("/user/billboards.json", []),
+      get("/data/floorplan/ai.json", []),
+      get("/data/floorplan/info.json", { floors: [] }),
+      get("/data/floorplan_cad.json", { floors: [] }),
+      get("/user/evidence.json", { floors: [] }),
+    ]);
+
     return {
       userFloorpan,
       hots,
@@ -52,6 +70,7 @@ const fetchResource = genCache(
       cad,
       cadInfo,
       config,
+      traces,
     };
   },
   150000
@@ -164,6 +183,116 @@ export const getHotTaggingInfos = async (scene: Scene, scale: number) => {
   return infos;
 };
 
+const getTraceAttri = async (icon: string, trace: any) => {
+  const size = {
+    width:  trace.visiSetting.scale,
+    height: trace.visiSetting.scale,
+  };
+  const attrib: any = {
+    url: icon,
+    size,
+    angle: trace.visiSetting.angle,
+  };
+  
+  if (trace.iconType === 2 || !trace.tag3d?.object) {
+    return attrib;
+  }
+  const getPath = (children: any, name: string): any[] | undefined => {
+    for (const item of children) {
+      if (item.name === name) {
+        return [item];
+      } else if (item.children) {
+        const childPath = getPath(item.children, name);
+        if (childPath) {
+          return [item, ...childPath];
+        }
+      }
+    }
+  };
+  const path = getPath([trace.tag3d.object], "sprite");
+
+  if (!path) return attrib;
+
+  const mat = new Matrix4();
+  for (const node of path) {
+    mat.multiply(new Matrix4(...(node.matrix as Matrix4Tuple)));
+  }
+  const position = new Vector3();
+  const quat = new Quaternion();
+  const scale = new Vector3();
+  mat.decompose(position, quat, scale);
+
+  const euler = new Euler().setFromQuaternion(quat, 'XYZ')
+  return {
+    ...attrib,
+    angle: MathUtils.radToDeg(euler.y),
+  };
+};
+
+// 痕迹物证
+export const getTraceTaggingInfos = async (
+  scene: Scene,
+  scale: number,
+  floorIndex: number
+) => {
+  const { traces } = await fetchResource(scene);
+  const infos: TaggingInfo[] = [];
+  const reqs: Promise<any>[] = [];
+
+  for (const trace of traces) {
+    if (
+      !validNum(trace.position.x) ||
+      !validNum(trace.position.z) ||
+      ("floorIndex" in trace && trace.floorIndex !== floorIndex) ||
+      trace.iconType === 0
+    )
+      continue;
+
+    const isSys = trace.icon.indexOf("/") > -1;
+    const icon = isSys
+      ? trace.icon.substring(trace.lastIndexOf("/") + 1)
+      : trace.icon;
+    const styleMap = (styleIconMap as any)[icon];
+
+    if (!icon) continue;
+
+    const getIcon = isSys
+      ? styleMap
+        ? Promise.resolve(`./icons/${styleMap}.svg`)
+        : getSceneApi("./", `./traces/${icon}.svg`)
+      : getSceneApi("oss", `/scene_edit_data/${scene.m}/user/${icon}`);
+
+    const name = (styleMap && getIconItem(styleMap)?.name) || "";
+    const getAttr = getIcon.then(async (url) => getTraceAttri(url, trace));
+
+    reqs.push(
+      getAttr
+        .then((attr) => ({
+          url: attr.url,
+          name,
+          position: {
+            x: trace.position.x * scale,
+            y: trace.position.z * scale,
+            z:
+              trace.position.y < 0
+                ? Math.ceil(trace.position.y * scale * 10) / 10
+                : Math.floor(trace.position.y * scale * 10) / 10,
+          },
+          rotate: attr.angle,
+          size: {
+            width: attr.size.width * scale,
+            height: attr.size.height * scale,
+          },
+        }))
+        .then((info) => infos.push(info))
+        .catch(() => {})
+    );
+  }
+  await Promise.all(reqs);
+
+  return infos;
+};
+
 const getBillYaw = (bill: any) => {
   function isLieDown(quaternion: Quaternion) {
     let direction = new Vector3(0, 0, -1).applyQuaternion(quaternion);
@@ -215,7 +344,6 @@ export const getBillTaggingInfos = async (
     )
       continue;
 
-      console.log(bill.subgroup , subgroup)
     const styleMap = (styleIconMap as any)[bill.icon];
     const getIcon =
       bill.icon.indexOf("style-") === 0
@@ -423,9 +551,10 @@ export const getResource = async ({
   scale,
 }: ResourceArgs) => {
   const data = await fetchResource(scene);
-  const floor = data.floorplan.floors.find(
+  const floorIndex = data.floorplan.floors.findIndex(
     (item: any) => item.name === floorName
   );
+  const floor = data.floorplan.floors[floorIndex];
   const key = floor.subgroup;
   const taggings: TaggingInfo[] = [];
   const wallTaggings: WallTaggingInfo[] = [];
@@ -459,6 +588,14 @@ export const getResource = async ({
       getBillTaggingInfos(scene, scale, key).then((ts) => taggings.push(...ts))
     );
   }
+  console.error(syncs);
+  if (syncs.includes("traces")) {
+    reqs.push(
+      getTraceTaggingInfos(scene, scale, floorIndex).then((ts) =>
+        taggings.push(...ts)
+      )
+    );
+  }
 
   await Promise.all(reqs);