bill преди 2 години
родител
ревизия
c10dec64d1
променени са 77 файла, в които са добавени 256 реда и са изтрити 5979 реда
  1. 2 1
      package.json
  2. 17 0
      server/mock.ts
  3. 1 0
      server/test/SS-t-P1d6CwREny2/attach/SS-t-P1d6CwREny2
  4. 0 139
      src/components/control-panl/ctrl.vue
  5. 0 29
      src/components/control-panl/index.ts
  6. 0 182
      src/components/control-panl/index.vue
  7. 0 185
      src/components/control-panl/style.scss
  8. 0 84
      src/components/edit-hot-item/constant.ts
  9. 0 355
      src/components/edit-hot-item/index.vue
  10. 0 99
      src/components/edit-hot-item/link-manage.vue
  11. 0 43
      src/components/edit-hot-item/metas-manage.vue
  12. 0 158
      src/components/edit-hot-item/metas-upload.vue
  13. 0 328
      src/components/edit-hot-item/style.scss
  14. 0 124
      src/components/edit-hot-item/styles-manage.vue
  15. 2 2
      src/components/main-panel/index.vue
  16. 2 0
      src/dbo/attach.ts
  17. 14 0
      src/dbo/main.ts
  18. 0 263
      src/guide/index.ts
  19. 0 39
      src/guide/mount.ts
  20. 1 55
      src/hook/useLaser.ts
  21. 1 1
      src/main.ts
  22. 0 0
      src/main.vue
  23. 0 40
      src/preset/app.vue
  24. 0 237
      src/preset/main.vue
  25. 0 35
      src/preset/mobile.scss
  26. 0 15
      src/preset/pc.scss
  27. 0 200
      src/preset/preset.ts
  28. 0 196
      src/preset/style.scss
  29. 0 159
      src/preset/traffic-main.vue
  30. 1 31
      src/router/info.ts
  31. 4 11
      src/sdk/carry/instance.ts
  32. 0 2
      src/sdk/carry/setup.vue
  33. 1 17
      src/sdk/types/store.ts
  34. 1 0
      src/store/fixPoint.ts
  35. 0 140
      src/store/hot.ts
  36. 1 17
      src/store/index.ts
  37. 2 80
      src/store/measure.ts
  38. 0 105
      src/store/setting.ts
  39. 0 70
      src/store/setup.ts
  40. 38 0
      src/store/sync.ts
  41. 0 21
      src/views/hotspot/constant.ts
  42. 0 31
      src/views/hotspot/hot-item/index.vue
  43. 0 53
      src/views/hotspot/hot-item/style.scss
  44. 0 184
      src/views/hotspot/index.vue
  45. 0 11
      src/views/hotspot/style.scss
  46. 0 65
      src/views/hotspot/view-hots/index.vue
  47. 0 43
      src/views/hotspot/view-hots/style.scss
  48. 0 169
      src/views/measure/constant.ts
  49. 0 238
      src/views/measure/control.vue
  50. 0 214
      src/views/measure/index.vue
  51. 0 11
      src/views/measure/share/constant.ts
  52. 0 122
      src/views/measure/share/index.vue
  53. 0 41
      src/views/measure/share/item.vue
  54. 0 126
      src/views/measure/share/pdf.vue
  55. 0 142
      src/views/measure/share/style.scss
  56. 0 138
      src/views/measure/style.scss
  57. 0 278
      src/views/measure/tree-manage.vue
  58. 0 43
      src/views/query/constant.ts
  59. 0 151
      src/views/query/index.vue
  60. 0 3
      src/views/query/style.scss
  61. 6 5
      src/views/scene/container.vue
  62. 25 4
      src/views/scene/covers/fixPoint.vue
  63. 79 3
      src/views/scene/covers/fixPoints.vue
  64. 6 3
      src/views/scene/covers/measure.vue
  65. 22 15
      src/views/scene/index.vue
  66. 1 1
      src/views/scene/menus/actions.ts
  67. 0 229
      src/views/setup/index.vue
  68. 0 71
      src/views/setup/style.scss
  69. BIN
      src/views/sys/err/img/archive.png
  70. BIN
      src/views/sys/err/img/del.png
  71. BIN
      src/views/sys/err/img/err.png
  72. BIN
      src/views/sys/err/img/run.png
  73. BIN
      src/views/sys/err/img/serveErr.png
  74. BIN
      src/views/sys/err/img/un.png
  75. 0 94
      src/views/sys/err/index.vue
  76. 0 27
      src/views/sys/err/style.scss
  77. 29 1
      yarn.lock

+ 2 - 1
package.json

@@ -11,6 +11,7 @@
   "dependencies": {
     "@types/express": "^4.17.17",
     "axios": "^1.3.5",
+    "body-parser": "^1.20.2",
     "coordtransform": "^2.1.2",
     "driver.js": "^0.9.8",
     "html2canvas": "^1.4.1",
@@ -32,4 +33,4 @@
     "vite": "^4.2.0",
     "vue-tsc": "^1.2.0"
   }
-}
+}

+ 17 - 0
server/mock.ts

@@ -1,5 +1,7 @@
 import express from "express";
 import path from "path";
+import bodyParser from 'body-parser'
+import * as fs from "fs";
 
 const staticDir = path.resolve(__dirname, "test");
 
@@ -12,7 +14,22 @@ export async function createServer(port: number) {
 
   const app = express();
   app.use(express.static(staticDir));
+  app.use(bodyParser())
   app.listen(port);
   startup = true;
+
+  app.use((req, res, next) => {
+    const paths = req.url.split("/")
+    const scene = paths[1]
+    const filename = paths[paths.length - 1]
+    const p = path.resolve(staticDir, scene, "./attach", filename)
+
+
+    console.log(p, req.body)
+    fs.writeFileSync(p, JSON.stringify(req.body))
+    res.json({code: 0, msg: 'ok'})
+  })
+
+
   console.log("模拟环境已开启");
 }

+ 1 - 0
server/test/SS-t-P1d6CwREny2/attach/SS-t-P1d6CwREny2

@@ -0,0 +1 @@
+{}

+ 0 - 139
src/components/control-panl/ctrl.vue

@@ -1,139 +0,0 @@
-<template>
-  <div
-    class="ctrl"
-    :class="{
-      active: active,
-      disabled: props.ctrl.disabled,
-      'in-click': props.ctrl.inClick,
-      'include-text': props.ctrl.text,
-      'include-icon': props.ctrl.icon,
-      'fun-ctrl': true
-    }"
-    v-if="!('show' in props.ctrl && !props.ctrl.show)"
-    @click.stop="emit('click', ctrl)"
-    ref="ctrlRef"
-  >
-    <template v-if="props.ctrl.icon">
-      <ui-guide
-        :msg="props.ctrl.guide"
-        class="control-icon-guide"
-        :mark="props.ctrl.key"
-        type="right"
-        v-if="props.ctrl.key"
-        :floatClass="os.isPc ? '' : 'control-guide'"
-      >
-        <template #content="{ show }">
-          <ui-icon
-            :svg="props.ctrl.type === 'svg'"
-            class="icon"
-            :tip="show ? '' : props.ctrl.desc"
-            :type="
-              props.ctrl.activeIcon && active
-                ? props.ctrl.activeIcon
-                : props.ctrl.icon
-            "
-            v-if="props.ctrl.icon"
-          />
-        </template>
-      </ui-guide>
-      <ui-icon
-        v-else
-        :svg="props.ctrl.type === 'svg'"
-        @click.stop="emit('click', props.ctrl)"
-        class="icon"
-        :tip="props.ctrl.desc"
-        :type="
-          props.ctrl.activeIcon && active
-            ? props.ctrl.activeIcon
-            : props.ctrl.icon
-        "
-      />
-    </template>
-    <span v-if="props.ctrl.text" class="text">{{ props.ctrl.text }}</span>
-
-    <ui-floating
-      v-if="props.ctrl.children"
-      :mount="mountEl"
-      dire="right-top"
-      :refer="ctrlRef"
-      width="160px"
-      :class="{ show: active || showChild }"
-      class="ctrl-child-float"
-      @mouseenter="showChild = true"
-      @mouseleave="showChild = false"
-    >
-      <div class="child-ctrls">
-        <div v-for="ctrl in props.ctrl.children">
-          <Ctrl
-            :ctrl="ctrl"
-            :activeCtrls="activeCtrls"
-            @click="data => emit('click', data)"
-          />
-        </div>
-      </div>
-    </ui-floating>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import { Ctrl as CtrlType } from './index'
-import { os } from '@/utils'
-import { computed, ref } from 'vue'
-
-const props = defineProps<{
-  ctrl: CtrlType
-  activeCtrls: CtrlType[]
-}>()
-const emit = defineEmits<{ (e: 'click', data: CtrlType): void }>()
-const active = computed(() => props.activeCtrls?.includes(props.ctrl))
-const mountEl = document.body
-const ctrlRef = ref<HTMLElement>()
-const showChild = ref(false)
-</script>
-<script lang="ts">
-export default {
-  name: 'Ctrl'
-}
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>
-
-<style lang="scss">
-.control-icon-guide {
-  .guide-bubble {
-    margin-left: 40px !important;
-  }
-
-  .default-msg {
-    font-size: 12px;
-  }
-}
-
-.control-guide {
-  margin-left: 30px;
-  margin-top: -10px;
-}
-
-.ctrl-child-float {
-  position: absolute;
-  top: 0;
-  left: 100%;
-  display: block;
-  width: 160px;
-  background: rgba(26, 26, 26, 0.8);
-  box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3),
-    inset 0 0 1px rgb(255 255 255 / 90);
-  border-radius: 4px;
-  border: 1px solid #000000;
-  transform: scaleY(0) translateX(10px);
-  transform-origin: top center;
-  transition: transform 0.3s ease;
-  z-index: 999999 !important;
-
-  &.show {
-    transform: scaleY(1) translateX(10px);
-  }
-}
-</style>

+ 0 - 29
src/components/control-panl/index.ts

@@ -1,29 +0,0 @@
-import ControlPanl from './index.vue'
-
-export type Ctrl = {
-    text?: string
-    icon?: string
-    activeIcon?: string
-    makeup?: boolean
-    show?: boolean
-    def?: boolean
-    inClick?: boolean
-    disabled?: boolean
-    desc?: string
-    type?: string
-    key?: string; 
-    guide?: string
-    children?: Omit<Ctrl, 'children'>[]
-}
-
-
-
-export type GroupAtom<T extends Ctrl = any> = {
-    apart?: boolean
-    label?: string
-    makeup?: boolean
-    ctrls: Array<T>
-}
-export type Group<T extends Ctrl = any> = readonly GroupAtom<T>[]
-
-export default ControlPanl

+ 0 - 182
src/components/control-panl/index.vue

@@ -1,182 +0,0 @@
-<template>
-  <transition name="fade">
-    <div
-      class="control-panl"
-      :class="{ full, pc: os.isPc && !os.isTablet, 'strengthen-right': full }"
-      v-if="!hide"
-    >
-      <div class="control-layer">
-        <div
-          class="panl pub-panl start"
-          v-if="!(os.isPc && !os.isTablet)"
-          @click="useEmitLeave()"
-        >
-          <div class="include-icon" style="text-align: center">
-            <ui-icon type="close"></ui-icon>
-          </div>
-        </div>
-
-        <div :class="{ ['scroll-view']: !(os.isPc && !os.isTablet) }">
-          <div
-            class="panl"
-            v-for="(groupItem, i) in group"
-            :class="{ apart: groupItem.apart }"
-          >
-            <p v-if="groupItem.label">{{ groupItem.label }}</p>
-            <VCtrl
-              v-for="ctrl in groupItem.ctrls"
-              :activeCtrls="modelValue"
-              :ctrl="ctrl"
-              @click="(ctrl) => clickHandler(ctrl)"
-            />
-          </div>
-        </div>
-
-        <div
-          class="panl pub-panl end"
-          :class="{ active: !disabledMap.tool, 'fun-ctrl': true }"
-          v-if="!os.isPc"
-          @click="disabledMap.tool = !disabledMap.tool"
-        >
-          <div class="include-icon nav-ctrl">
-            <ui-icon type="list"></ui-icon>
-            <span>{{ count }}</span>
-          </div>
-        </div>
-      </div>
-    </div>
-  </transition>
-</template>
-
-<script lang="ts" setup>
-import { ref, watchEffect, onActivated, onDeactivated, onUnmounted } from "vue";
-import { Group, Ctrl } from "./index";
-import { os } from "@/utils";
-import { disabledMap, boxWidthStack, useEmitLeave, controlFullStack } from "@/hook";
-import VCtrl from "./ctrl.vue";
-
-const props = defineProps<{
-  group: Group;
-  show: boolean;
-  modelValue: Array<Ctrl>;
-  full?: boolean;
-  count?: number;
-}>();
-
-const updateHide = (show = props.show) => {
-  if (show) {
-    setTimeout(() => (hide.value = false));
-  } else {
-    setTimeout(() => (hide.value = true));
-  }
-};
-
-const hide = ref(true);
-
-watchEffect(() => updateHide());
-onActivated(updateHide);
-onDeactivated(() => updateHide(false));
-
-const emit = defineEmits<{
-  (e: "update:modelValue", data: any, oldData: Array<Ctrl>): void;
-  (e: "select", data: Ctrl): void;
-}>();
-
-const clickHandler = (ctrl: Ctrl) => {
-  if (ctrl.inClick) {
-    return emit("select", ctrl);
-  }
-
-  const newRuns = [...props.modelValue];
-  const index = newRuns.indexOf(ctrl);
-  if (~index) {
-    newRuns.splice(index, 1);
-  } else if (ctrl.makeup) {
-    newRuns.push(ctrl);
-  } else {
-    const makeupRuns = newRuns.filter((item) => item.makeup);
-    const ctrlGroups = props.group.find((group) => group.ctrls.includes(ctrl));
-    const anewRuns = newRuns.filter((item) => {
-      const currentGroups = props.group.find((group) => group.ctrls.includes(item));
-      return currentGroups !== ctrlGroups && (currentGroups.makeup || ctrlGroups.makeup);
-    });
-    newRuns.length = 0;
-    newRuns.push(...Array.from(new Set([...makeupRuns, ...anewRuns])), ctrl);
-  }
-  emit("update:modelValue", newRuns, props.modelValue);
-};
-
-watchEffect(() => {
-  if (!props.show) {
-    emit(
-      "update:modelValue",
-      props.group.reduce((t, c) => [...t, ...c.ctrls.filter((ctrl) => ctrl.def)], []),
-      []
-    );
-  }
-});
-
-watchEffect(() => {
-  if (props.modelValue.some((item) => "show" in item && !item.show)) {
-    emit(
-      "update:modelValue",
-      props.modelValue.filter((item) => !("show" in item && !item.show)),
-      []
-    );
-  }
-});
-
-if (!os.isPc) {
-  let inset = false;
-  let boxWidth = ref("calc(100% - 60px)");
-  const sysWidth = boxWidthStack.current.value;
-
-  watchEffect(() => {
-    if (props.show) {
-      boxWidth.value = sysWidth.value.includes("calc")
-        ? "calc(100% - 60px)"
-        : sysWidth.value;
-      if (!inset) {
-        boxWidthStack.push(boxWidth);
-        inset = true;
-      }
-    } else if (inset) {
-      boxWidthStack.pop();
-      inset = false;
-    }
-  });
-} else {
-  let isShow;
-  watchEffect(() => {
-    if (isShow === props.show) {
-      return;
-    }
-    if (props.show) {
-      controlFullStack.push(ref(props.full));
-    } else if (controlFullStack.length.value > 1) {
-      controlFullStack.pop();
-    }
-    isShow = props.show;
-  });
-
-  onUnmounted(() => {
-    if (isShow || isShow !== props.show) {
-      controlFullStack.pop();
-    }
-  });
-}
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>
-
-<style lang="scss">
-.control-panl .icon .tip {
-  width: 68px;
-  word-break: break-all;
-  white-space: normal;
-  text-align: center;
-  padding: 10px 4px;
-}
-</style>

+ 0 - 185
src/components/control-panl/style.scss

@@ -1,185 +0,0 @@
-.control-panl {
-  position: absolute;
-  width: 70px;
-  &.pc {
-    padding: 10px 0;
-  }
-  &:not(.pc) {
-    width: 60px;
-    padding: 10px 0;
-  }
-  margin-left: 0;
-
-  &.full {
-    top: calc(var(--header-top) + var(--editor-head-height));
-    bottom: 0;
-    left: 0;
-    overflow-y: auto;
-
-    &.pc .control-layer {
-      padding: 0 10px;
-      max-height: 100%;
-    }
-
-    &:not(.pc) .control-layer {
-      padding: 0 5px;
-      height: 100%;
-      display: flex;
-      flex-direction: column;
-      padding-top: var(--padding-top);
-
-      .pub-panl {
-        flex: none;
-        &.start {
-          margin-bottom: 20px;
-        }
-
-        &.end {
-          margin-top: 20px;
-
-          &.active {
-            color: #00c8af;
-          }
-        }
-
-        .nav-ctrl {
-          position: relative;
-          .icon {
-            position: relative;
-            z-index: 1;
-          }
-
-          span {
-            top: 0;
-            right: 0;
-            position: absolute;
-            width: 22px;
-            height: 18px;
-            border-radius: 9px;
-            text-align: center;
-            line-height: 18px;
-            color: #fff;
-            font-size: 12px;
-            background-color: rgba(0, 200, 175, 1);
-            z-index: 9999;
-          }
-        }
-      }
-
-      .scroll-view {
-        flex: 1;
-        overflow-y: auto;
-        width: calc(100% + 10px);
-        margin-left: -5px;
-        padding: 0 4px;
-      }
-    }
-  }
-
-  &:not(.full) {
-    left: 10px;
-    top: 50%;
-    transform: translateY(-50%) translateX(0);
-    border-radius: 10px;
-    padding: 10px;
-    &:not(.pc) {
-      padding: 5px;
-    }
-  }
-
-  backdrop-filter: blur(4px);
-  background: var(--editor-menu-back);
-  pointer-events: all;
-  z-index: 20;
-
-  .panl {
-    color: #999999;
-    &:not(:first-of-type) {
-      margin-top: 20px;
-    }
-
-    &.apart {
-      border-top: 1px solid rgba(255, 255, 255, 0.16);
-      padding-top: 20px;
-      margin-top: 20px;
-    }
-
-    p {
-      font-size: 12px;
-      text-align: center;
-      margin: 10px 0;
-    }
-  }
-}
-
-.child-ctrls {
-  width: 160px;
-  display: grid;
-  grid-template: auto / repeat(3, 1fr);
-  align-items: center;
-  justify-items: center;
-  justify-content: center;
-  align-content: center;
-  > div {
-    border: 1px solid rgba(255, 255, 255, 0.1);
-  }
-}
-
-.ctrl {
-  margin-bottom: 1px;
-  width: 50px;
-  height: 40px;
-  border-radius: 4px;
-  cursor: pointer;
-  transition: background-color 0.3s ease, color 0.3s ease;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  user-select: none;
-  // background-color: rgba(255,255,255,.1);
-
-  &.fun-ctrl {
-    color: #fff !important;
-    &:hover {
-      color: #00c8af !important;
-    }
-  }
-
-  &.include-text.include-icon {
-    .icon {
-      flex: 1;
-      font-size: 16px;
-      text-align: center;
-    }
-    .text {
-      text-align: center;
-      flex: 1;
-      font-size: 12px;
-    }
-  }
-
-  &:not(.include-text) {
-    font-size: 20px;
-  }
-
-  &:not(.include-icon) {
-    font-size: 16px;
-  }
-
-  &.active {
-    background-color: rgba(var(--colors-primary-base-fill), 0.16);
-  }
-  &.active i {
-    color: var(--colors-primary-base) !important;
-  }
-}
-
-.fade-enter-active,
-.fade-leave-active {
-  transition: opacity 0.2s ease, margin-left 0.2s ease;
-}
-.fade-enter-from,
-.fade-leave-to {
-  opacity: 0;
-  margin-left: -70px;
-}

+ 0 - 84
src/components/edit-hot-item/constant.ts

@@ -1,84 +0,0 @@
-import { HotAtom, HotType, HotStyleAtom, styles } from '@/store/hot'
-import { nextTick, ref, watch, watchEffect } from 'vue'
-import { ui18n } from '@/lang'
-
-export type ServerMeta = HotAtom['meta'][number]
-export type LocalMeta = { file: File; preview: ServerMeta }
-export type MetaAtom = LocalMeta | ServerMeta
-export type Meta = Array<MetaAtom>
-export type Metas = { [key in HotType]: Meta }
-export type LocalStyleAtomIcon = { file: File; preview: string }
-export type LocalStyleAtom = Omit<HotStyleAtom, 'icon'> & { icon: LocalStyleAtomIcon }
-export type StyleAtom = HotStyleAtom | LocalStyleAtom
-
-export type Custom = {
-    [keyof in HotType]?: {
-        icon: string
-        name: string
-        upload?: boolean
-        uploadPlace?: string
-        accept?: string
-        scale?: string
-        multiple?: boolean
-        maxSize?: number
-        maxNum?: number
-        othPlaceholder?: string
-    }
-}
-
-export const custom: Custom = {
-    IMAGE: {
-        icon: 'pic',
-        upload: true,
-        uploadPlace: ui18n.t('hotspot.meta.image.place'),
-        accept: `.jpg, .png`,
-        multiple: true,
-        name: ui18n.t('hotspot.meta.image.title'),
-        maxSize: 5 * 1024 * 1024,
-        maxNum: 9,
-        othPlaceholder: ui18n.t('hotspot.meta.image.desc'),
-    },
-    VIDEO: {
-        icon: 'video',
-        upload: true,
-        uploadPlace:ui18n.t('hotspot.meta.video.place'),
-        accept: `.mp4, .mov`,
-        multiple: false,
-        name: ui18n.t('hotspot.meta.video.title'),
-        maxSize: 20 * 1024 * 1024,
-        othPlaceholder: ui18n.t('hotspot.meta.video.desc'),
-    },
-    AUDIO: {
-        icon: 'music',
-        upload: true,
-        uploadPlace: ui18n.t('hotspot.meta.audio.place'),
-        accept: '.mp3, .wav',
-        multiple: false,
-        name: ui18n.t('hotspot.meta.audio.title'),
-        maxSize: 5 * 1024 * 1024,
-        othPlaceholder: ui18n.t('hotspot.meta.audio.desc'),
-    },
-    WEB: {
-        icon: 'web',
-        name: ui18n.t('hotspot.meta.web.title'),
-    },
-}
-
-export const selectStyle = ref(null)
-
-watch(
-    styles,
-    (newv, olv) => {
-        const index = olv ? olv.indexOf(selectStyle.value) : -1
-        if (~index) {
-            selectStyle.value = newv[index]
-        } else {
-            selectStyle.value = newv[0]
-        }
-    },
-    { immediate: true }
-)
-
-export const MAX_DIS = 10
-
-export const toastErr = (type, info) => ui18n.t(`sys.uploadErr.${type}`, info)

+ 0 - 355
src/components/edit-hot-item/index.vue

@@ -1,355 +0,0 @@
-<template>
-  <HotItemLabel
-    :data="data"
-    :active="active"
-    class="edit-item-layer"
-    :x="x"
-    :y="y"
-    noUseDefault
-    :forceHide="!active"
-    :permanent="true"
-    @mousedown.stop.prevent="downHandler"
-    @click.stop="clickHandler"
-  >
-    <template v-slot:content>
-      <h3 class="edit-title">
-        {{ $t("hotspot.name") }}
-        <ui-icon type="close" ctrl @click.stop="quit" class="edit-close" />
-      </h3>
-      <StylesManage
-        :styles="allStyles"
-        :active="data.style"
-        @change="(style) => changeStyle(data, style)"
-        @delete="deleteStyle"
-        @uploadStyles="uploadStyles"
-      />
-
-      <ui-input
-        require
-        class="input"
-        width="100%"
-        :placeholder="$t('hotspot.edit.placeholder.title')"
-        type="text"
-        :modelValue="data.title"
-        @update:modelValue="(value) => (data.title = value.trim())"
-        maxlength="15"
-      />
-      <ui-input
-        class="input"
-        width="100%"
-        height="158px"
-        :placeholder="$t('hotspot.edit.placeholder.content')"
-        type="richtext"
-        v-model="data.content"
-        :maxlength="maxContentLen"
-        ref="contentRef"
-        :onUpdatePos="(i) => (index = i)"
-      >
-        <template v-slot:icon>
-          <div class="link">
-            <LinkManage
-              :show="!!(inInsertLink && maxTextLen)"
-              :textlen="maxTextLen"
-              @close="inInsertLink = false"
-              @add="insertel"
-            />
-            <ui-icon type="link" class="icon" @click="openInsertLink" ctrl />
-          </div>
-        </template>
-      </ui-input>
-      <MetasManage :data="data" @change="changeMeta" :hotFiles="hotFiles" />
-      <div class="submit-ctrl">
-        <div class="radio-group">
-          <ui-input
-            v-for="(item, type) in custom"
-            :key="type"
-            class="radio"
-            type="radio"
-            :modelValue="data.type === type"
-            @update:modelValue="data.type = type"
-            :icon="item.icon"
-          />
-        </div>
-      </div>
-    </template>
-  </HotItemLabel>
-</template>
-
-<script setup lang="ts">
-import MetasManage from "./metas-upload.vue";
-import StylesManage from "./styles-manage.vue";
-import HotItemLabel from "@/components/show-hot-item/index.vue";
-import { computed, ref, watchEffect } from "vue";
-import { HotAtom, TemploraryID } from "@/store";
-import {
-  custom,
-  LocalMeta,
-  Meta,
-  MetaAtom,
-  LocalStyleAtom,
-  selectStyle,
-  Metas,
-  ServerMeta,
-  LocalStyleAtomIcon,
-  StyleAtom,
-  MAX_DIS,
-} from "./constant";
-import { styles, HotStyleAtom, list } from "@/store/hot";
-import LinkManage from "./link-manage.vue";
-import { Message } from "@kankan/components/index";
-import { useSDK } from "@/hook";
-import { calcLintDis } from "@/utils";
-import { ui18n } from "@/lang";
-
-const laser = useSDK();
-const props = defineProps<{
-  hotFiles: WeakMap<HotAtom, Array<File>>;
-  styleFile: WeakMap<HotStyleAtom, File>;
-  active?: boolean;
-  data: HotAtom;
-  x: number;
-  y: number;
-  quit: () => void;
-}>();
-
-const clickHandler = () => {
-  laser.carry.store.share.showHot = props.data;
-};
-
-const move = ref(false);
-const downHandler = (sev) => {
-  const el = sev.target as HTMLElement;
-  const mountEl = document.documentElement;
-  const preset = {
-    x: el.offsetWidth / 2 - sev.offsetX,
-    y: el.offsetHeight - sev.offsetY,
-  };
-
-  const moveHandler = (ev: MouseEvent) => {
-    move.value = true;
-    const sdk = useSDK();
-    const pos = sdk.scene.getPointByScreen({
-      x: ev.pageX + preset.x,
-      y: ev.pageY + preset.y,
-      inDrag: true,
-    });
-    if (
-      pos?.position &&
-      calcLintDis(sdk.scene.currentCamera(), pos.position) <= MAX_DIS
-    ) {
-      props.data.pos.x = pos.position.x;
-      props.data.pos.y = pos.position.y;
-      props.data.pos.z = pos.position.z;
-      props.data.dataset_location = pos.dataset_location;
-      props.data.datasetId = pos.datasetId;
-    }
-  };
-  const upHandler = (ev: MouseEvent) => {
-    mountEl.removeEventListener("mousemove", moveHandler);
-    mountEl.removeEventListener("mouseup", upHandler);
-    move.value = false;
-  };
-
-  mountEl.addEventListener("mousemove", moveHandler);
-  mountEl.addEventListener("mouseup", upHandler);
-};
-
-const contentRef = ref(null);
-const maxContentLen = 200;
-const inInsertLink = ref(false);
-const metas = ref<Metas>({
-  TEXT: [],
-  AUDIO: [],
-  VIDEO: [],
-  IMAGE: [],
-  WEB: [],
-});
-props.data.type = props.data.type === "TEXT" ? "IMAGE" : props.data.type;
-metas.value[props.data.type] = props.data.meta || [];
-
-const normalizeMate = (item: MetaAtom): ServerMeta => {
-  if ((item as LocalMeta).preview) {
-    return (item as LocalMeta).preview;
-  } else {
-    return item as ServerMeta;
-  }
-};
-const normalizeIcon = (item: LocalStyleAtomIcon | string): string => {
-  if ((item as LocalStyleAtomIcon).preview) {
-    return (item as LocalStyleAtomIcon).preview;
-  } else {
-    return item as string;
-  }
-};
-watchEffect(() => {
-  const meta = metas.value[props.data.type] || [];
-
-  props.data.meta = meta.map(normalizeMate);
-  const files = [];
-  meta.forEach((item: MetaAtom) => {
-    if ((item as LocalMeta).file) {
-      files.push((item as LocalMeta).file);
-    }
-  });
-  props.hotFiles.set(props.data, files);
-});
-
-const el = document.createElement("div");
-const contentLen = computed(() => {
-  el.innerHTML = props.data.content;
-  return el.textContent.length;
-});
-const maxTextLen = computed(() => 40);
-
-const index = ref(0);
-const openInsertLink = () => {
-  if (contentLen.value > maxContentLen) {
-    return Message.error(ui18n.t("hotspot.edit.maxContentLen"));
-  } else {
-    inInsertLink.value = true;
-  }
-};
-
-const insertel = (html: string, link, text) => {
-  el.innerHTML = html;
-  let htmlLen = el.textContent.length;
-  props.data.content = props.data.content || "";
-  el.innerHTML = props.data.content;
-  while (true) {
-    const overstep = el.textContent.length - (maxContentLen - htmlLen);
-    if (overstep <= 0) break;
-    const lastDOM = el.childNodes[el.childNodes.length - 1] as Element;
-
-    if (lastDOM.textContent.length > overstep) {
-      let content = lastDOM.textContent;
-      content = content.substring(0, content.length - overstep);
-      lastDOM.textContent = content;
-    } else {
-      el.removeChild(lastDOM);
-    }
-  }
-
-  let current = 0;
-  if (el.childNodes.length) {
-    for (let i = 0; i < el.childNodes.length; i++) {
-      const node = el.childNodes[i];
-      let length = node.textContent.length;
-
-      if ((node as any).innerHTML === "<br>") {
-        length = 1;
-        (node as any).innerHTML = "";
-      }
-
-      if (current + length > index.value) {
-        const start = index.value - current;
-
-        if (node.nodeType === Node.ELEMENT_NODE) {
-          let ehtml = (node as HTMLElement).innerHTML;
-          ehtml = ehtml.substring(0, start) + html + ehtml.substring(start);
-          (node as HTMLElement).innerHTML = ehtml;
-        } else {
-          let ehtml = node.textContent;
-          const startNode = node.cloneNode();
-          startNode.textContent = ehtml.substring(0, start);
-          el.insertBefore(startNode, node);
-          const dom = document.createElement("a");
-          dom.setAttribute("href", link);
-          dom.setAttribute("target", "_blank");
-          dom.innerHTML = text;
-          el.insertBefore(dom, node);
-          const endNode = node.cloneNode();
-          endNode.textContent = ehtml.substring(start);
-          el.insertBefore(endNode, node);
-          el.removeChild(node);
-        }
-
-        break;
-      } else {
-        current += node.textContent.length;
-      }
-
-      if (i === el.childNodes.length - 1) {
-        el.innerHTML += html;
-        break;
-      }
-    }
-  } else {
-    el.innerHTML = html;
-  }
-  props.data.content = el.innerHTML;
-  inInsertLink.value = false;
-};
-
-const changeMeta = (ameta: Meta) => {
-  const meta = metas.value[props.data.type];
-  const nmeta: Meta = [];
-
-  for (let i = 0; i < ameta.length; i++) {
-    const index = meta.findIndex(
-      (atom) => atom === ameta[i] || (atom as LocalMeta).preview === ameta[i]
-    );
-    if (~index) {
-      nmeta.push(meta[index]);
-    } else {
-      nmeta.push(ameta[i]);
-    }
-  }
-  metas.value[props.data.type] = nmeta;
-};
-
-const changeStyle = (info, style) => {
-  info.style = style;
-  selectStyle.value = style;
-};
-
-const allStyles = computed(() =>
-  [...styles.value].sort((a, b) => {
-    return a.default
-      ? -1
-      : b.default
-      ? 1
-      : a.id === TemploraryID
-      ? -1
-      : b.id === TemploraryID
-      ? 1
-      : 0;
-  })
-);
-const uploadStyles = (unStyles: Array<LocalStyleAtom>) => {
-  const addStyles = unStyles.map((item) => {
-    const style = {
-      ...item,
-      icon: normalizeIcon(item.icon),
-    };
-    props.styleFile.set(style, item.icon.file);
-    return style;
-  });
-  styles.value.push(...addStyles);
-  changeStyle(props.data, addStyles[0]);
-};
-
-const deleteStyle = (delStyle: HotStyleAtom) => {
-  const index = styles.value.indexOf(delStyle);
-  if (~index) {
-    styles.value.splice(index, 1);
-    for (const item of list.value) {
-      if (item.style === delStyle) {
-        item.style = styles.value.find(({ default: isDefault }) => isDefault);
-      }
-    }
-  }
-};
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>
-
-<style>
-.edit-item-layer > img {
-  cursor: move;
-}
-.radio-group .label {
-  font-size: 16px;
-}
-</style>

+ 0 - 99
src/components/edit-hot-item/link-manage.vue

@@ -1,99 +0,0 @@
-<template>
-  <ui-bubble class="link-bubble" type="bottom" :show="show">
-    <ui-dialog-content>
-      <template v-slot:header>
-        <span>{{ $t("hotspot.edit.addLink") }}</span>
-      </template>
-      <div class="link-text-from">
-        <ui-input
-          class="link-text-input"
-          width="100%"
-          :placeholder="$t('hotspot.edit.placeholder.addLinkTitle')"
-          type="text"
-          v-model="text"
-          require
-          :error="error.text"
-          :maxlength="textlen"
-        />
-        <ui-input
-          width="100%"
-          type="text"
-          v-model="link"
-          :error="error.link"
-          require
-          :placeholder="$t('hotspot.edit.placeholder.addLinkContent')"
-        />
-      </div>
-      <template v-slot:footer>
-        <ui-button type="cancel" @click="quit">{{ $t("sys.cancel") }}</ui-button>
-        <ui-button type="primary" @click="enter">{{ $t("sys.add") }}</ui-button>
-      </template>
-    </ui-dialog-content>
-  </ui-bubble>
-</template>
-<script setup lang="ts">
-import { normalizeLink } from "@/utils";
-import { reactive, watchEffect } from "vue";
-import { ref } from "vue";
-import { ui18n } from "@/lang";
-
-const link = ref("");
-const text = ref("");
-const error = reactive({ link: "", text: "" });
-const openError = ref(false);
-
-watchEffect(
-  () =>
-    (error.link =
-      openError.value && !link.value.trim()
-        ? ui18n.t("hotspot.edit.placeholder.addLinkContent")
-        : ""),
-  { flush: "sync" }
-);
-watchEffect(
-  () =>
-    (error.text =
-      openError.value && !text.value.trim()
-        ? ui18n.t("hotspot.edit.placeholder.addLinkTitle")
-        : ""),
-  { flush: "sync" }
-);
-
-defineProps<{ textlen: number; show: boolean }>();
-const emit = defineEmits<{
-  (e: "close"): void;
-  (e: "add", content: string, link: string, text: string);
-}>();
-const enter = () => {
-  openError.value = true;
-  if (!error.link && !error.text) {
-    emit(
-      "add",
-      `<a href="${normalizeLink(link.value)}" target="_blank">${text.value}</a>`,
-      link.value,
-      text.value
-    );
-    openError.value = false;
-    link.value = "";
-    text.value = "";
-  }
-};
-const quit = () => {
-  emit("close");
-  openError.value = false;
-};
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>
-
-<style>
-.link-text-input .text.suffix input {
-  padding-right: 60px;
-}
-.link-bubble .ui-dialog__box {
-  max-width: none;
-  backdrop-filter: none;
-}
-</style>

+ 0 - 43
src/components/edit-hot-item/metas-manage.vue

@@ -1,43 +0,0 @@
-<template>
-  <div class="audo-prevew" v-if="data.type === 'AUDIO'">
-    <ui-icon type="music" class="icon" />
-    <p>
-      {{ data.meta[0].name }}
-    </p>
-    <span @click="emit('delete', data.meta[0])" class="del-file">
-      <ui-icon type="del" ctrl />
-    </span>
-  </div>
-  <MetasManage
-    :hot="data"
-    v-else
-    :index="index"
-    @change="(i) => emit('change', i)"
-    hideInfo
-  >
-    <template v-slot:icons="{ active }">
-      <span @click="emit('delete', active)" class="del-file">
-        <ui-icon type="del" ctrl />
-      </span>
-    </template>
-  </MetasManage>
-</template>
-
-<script setup lang="ts">
-import { HotAtom } from "@/store";
-import MetasManage from "../show-hot-item/metas-mange.vue";
-
-const emit = defineEmits<{
-  (e: "delete", data: HotAtom["meta"][number]): void;
-  (e: "change", i: number): void;
-}>();
-
-defineProps<{
-  data: HotAtom;
-  index?: number;
-}>();
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 158
src/components/edit-hot-item/metas-upload.vue

@@ -1,158 +0,0 @@
-<template>
-  <ui-input
-    v-if="data.type !== 'TEXT' && data.type !== 'WEB'"
-    class="input"
-    width="100%"
-    height="225px"
-    preview
-    :toastErr="toastErr"
-    :placeholder="custom[data.type].uploadPlace"
-    :disable="custom[data.type].upload"
-    :scale="custom[data.type].scale"
-    :accept="custom[data.type].accept"
-    :multiple="custom[data.type].multiple"
-    :maxSize="custom[data.type].maxSize"
-    :maxLen="custom[data.type].maxNum"
-    :modelValue="data.meta"
-    :addText="$t('sys.uploadAddText')"
-    :replaceText="$t('sys.uploadReplaceText')"
-    @update:modelValue="fileChange"
-    :othPlaceholder="custom[data.type].othPlaceholder"
-    type="file"
-  >
-    <template v-slot:valuable>
-      <MetasMange
-        :hotFiles="hotFiles"
-        :data="data"
-        @delete="delMetaHandler"
-        :index="index"
-        @change="(i) => (index = i)"
-      />
-    </template>
-  </ui-input>
-  <div v-else-if="data.type === 'WEB'" class="webview">
-    <MetasMange
-      :data="data"
-      @delete="delMetaHandler"
-      v-if="data.meta && data.meta.length"
-    />
-    <p v-else>{{ $t("hotspot.meta.web.place") }}</p>
-    <ui-input
-      placeholder="https://"
-      type="text"
-      v-model="link"
-      width="100%"
-      class="link-input"
-    >
-      <template v-slot:icon>
-        <span class="link-enter fun-ctrl" @click="enterLink">
-          <ui-icon type="checkbox" color="rgba(0, 0, 0, 0.7)" />
-        </span>
-      </template>
-    </ui-input>
-  </div>
-</template>
-
-<script setup lang="ts">
-import MetasMange from "./metas-manage.vue";
-import { ref, watchEffect, watch } from "vue";
-import { HotAtom } from "@/store";
-import { custom, Meta, ServerMeta, toastErr } from "./constant";
-import { normalizeLink } from "@/utils";
-import { ui18n } from "@/lang";
-import { useConfirm } from "@/hook";
-
-const props = defineProps<{
-  data: HotAtom;
-  hotFiles: WeakMap<HotAtom, Array<File>>;
-}>();
-const link = ref<string>("");
-const emit = defineEmits<{
-  (e: "change", data: Meta): void;
-}>();
-
-watchEffect(() => {
-  if (props.data.type === "WEB") {
-    link.value = props.data.meta[0] ? props.data.meta[0].url : "";
-  }
-});
-
-const enterLink = () => {
-  link.value = normalizeLink(link.value);
-  emit("change", [{ url: link.value, name: "" }]);
-};
-
-const delMetaHandler = async (meta: ServerMeta) => {
-  const index = props.data.meta.indexOf(meta);
-  const name = custom[props.data.type].name;
-
-  if (~index && (await useConfirm(ui18n.t("hotspot.deleteConfirm", { type: name })))) {
-    const meta = [...props.data.meta];
-    meta.splice(index, 1);
-    emit("change", meta);
-  }
-};
-
-type MetaFile = { file: File; preview: string };
-type MetaFileAtom = MetaFile | ServerMeta;
-const fileChange = (file: MetaFileAtom | MetaFileAtom[]) => {
-  const files = Array.isArray(file) ? file : [file];
-  const meta: Meta = files.map((atom) => {
-    if ((atom as MetaFile).file) {
-      return {
-        file: (atom as MetaFile).file,
-        preview: {
-          url: (atom as MetaFile).preview,
-          name: (atom as MetaFile).file.name,
-        },
-      };
-    } else {
-      return atom as ServerMeta;
-    }
-  });
-  emit("change", meta);
-};
-
-const index = ref(0);
-
-watch(
-  () => {
-    return {
-      type: props.data.type,
-      meta: props.data.meta,
-    };
-  },
-  (newv, oldv) => {
-    if (newv.type !== oldv.type) {
-      index.value = 0;
-    } else if (newv.meta.length > oldv.meta.length || index.value >= newv.meta.length) {
-      index.value = newv.meta.length - 1;
-    }
-  }
-);
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>
-
-<style>
-.link-input input {
-  border: none !important;
-  background: linear-gradient(
-    180deg,
-    rgba(0, 0, 0, 0.25) 0%,
-    rgba(0, 0, 0, 0.5) 100%
-  ) !important;
-  border-radius: 0 !important;
-  color: #ffffff !important;
-}
-
-.link-input input::placeholder {
-  color: rgba(255, 255, 255, 0.7) !important;
-}
-
-.link-input .input {
-  border-radius: 0 !important;
-}
-</style>

+ 0 - 328
src/components/edit-hot-item/style.scss

@@ -1,328 +0,0 @@
-.hot-styles {
-  --size: 40px;
-  --icon-size: calc(var(--size) * 0.85);
-  margin: 24px 0;
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(var(--size), 1fr));
-  gap: calc(var(--size) / 4);
-  align-items: start;
-  justify-content: center;
-
-  .item {
-    --un-active-color: rgba(var(--colors-primary-base-fill), 0);
-    --active-transition: 0.3s ease;
-    cursor: pointer;
-
-    &.disable {
-      opacity: 0.3;
-      pointer-events: none;
-      cursor: inherit;
-    }
-
-    span {
-      width: var(--size);
-      height: var(--size);
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      border: 1px solid var(--un-active-color);
-      position: relative;
-      transition: border var(--active-transition);
-      border-radius: 4px;
-
-      .input {
-        margin: 0;
-      }
-
-      img {
-        width: var(--icon-size);
-        height: var(--icon-size);
-        // outline: 1px dashed var(--un-active-color);
-        transition: outline-color var(--active-transition);
-        border-radius: 4px;
-      }
-
-      .delete {
-        --round-size: calc(var(--size) * 0.45);
-        position: absolute;
-        width: var(--round-size);
-        height: var(--round-size);
-        border-radius: 50%;
-        background-color: rgba(250, 63, 72, 1);
-        right: calc(var(--round-size) * -1 / 2);
-        top: calc(var(--round-size) * -1 / 2);
-        transition: background-color var(--active-transition);
-        font-size: 12px;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        color: #fff;
-        opacity: 0;
-        transition: opacity 0.3s ease;
-      }
-    }
-
-    p {
-      transition: color var(--active-transition);
-      margin-top: calc(var(--size) / 4);
-      text-align: center;
-      color: rgb(var(--colors-primary-fill));
-      font-size: var(--small-size);
-    }
-
-    &.active {
-      color: rgba(var(--colors-primary-base-fill), 1);
-      --un-active-color: rgba(var(--colors-primary-base-fill), 1);
-
-      span img {
-        outline-color: rgb(var(--colors-primary-fill));
-      }
-      p {
-        color: currentColor;
-      }
-    }
-
-    &:not(.style-more):hover {
-      .delete {
-        opacity: 0.5;
-
-        &:hover {
-          opacity: 1;
-        }
-      }
-    }
-  }
-
-  .add {
-    height: 100%;
-    align-items: center;
-    display: flex;
-    flex: none;
-
-    span {
-      font-size: calc(var(--icon-size) * 0.4);
-      border: none;
-
-      &::before {
-        content: '';
-        position: absolute;
-        left: 50%;
-        top: 50%;
-        transform: translate(-50%, -50%);
-        width: var(--icon-size);
-        height: var(--icon-size);
-        border-radius: 2px;
-        border: 1px solid var(--colors-border-color);
-        transition: border-color 0.3s ease;
-      }
-
-      &:hover::before {
-        border-color: rgba(255, 255, 255, 1);
-      }
-      &:active::before {
-        border-color: var(--colors-primary-base) !important;
-      }
-    }
-  }
-
-  .style-more {
-    .fun-ctrl {
-      position: relative;
-    }
-
-    .more-content {
-      width: 360px;
-      z-index: 9;
-      --arrow-width: 20px;
-      --bottom-left: 310px;
-      --back-color: rgba(0, 0, 0, 0.7);
-
-      .hot-styles {
-        margin: 0;
-      }
-    }
-  }
-}
-
-.ctrls {
-  .btn-item {
-    margin-bottom: 20px;
-  }
-}
-
-.edit-item-layer {
-  color: rgb(var(--colors-primary-fill), 0.7);
-  font-size: var(--medium-size);
-  .input {
-    margin-bottom: 10px;
-  }
-
-  .submit-ctrl {
-    margin-top: 20px;
-    display: flex;
-
-    .radio-group {
-      flex: 1;
-      display: inline-flex;
-
-      > .radio {
-        margin-right: 22px;
-      }
-    }
-
-    .submit {
-      flex: none;
-      cursor: pointer;
-    }
-  }
-
-  .del-file {
-    display: block;
-    width: 24px;
-    height: 24px;
-    background-color: rgba(0, 0, 0, 0.3);
-    font-size: 14px;
-    color: rgba(255, 255, 255, 0.7);
-    border-radius: 50%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-
-    &:not(:last-child) {
-      margin-bottom: 10px;
-    }
-  }
-
-  .audo-prevew {
-    position: relative;
-    width: 100%;
-    height: 100%;
-    display: flex;
-    text-align: center;
-    align-items: center;
-    justify-content: center;
-
-    > .icon {
-      font-size: 16px;
-      margin-right: 6px;
-    }
-
-    .del-file {
-      position: absolute;
-      top: 10px;
-      right: 10px;
-    }
-  }
-
-  .webview {
-    height: 225px;
-    background: rgba(255, 255, 255, 0.1);
-    border-radius: 4px;
-    border: 1px solid rgba(255, 255, 255, 0.2);
-    position: relative;
-    display: flex;
-    align-items: center;
-    margin-bottom: 30px;
-    justify-content: center;
-    overflow: hidden;
-
-    p {
-      color: rgba(255, 255, 255, 0.3);
-      font-size: 16px;
-      font-weight: bold;
-    }
-
-    .link-input {
-      position: absolute;
-      left: 0;
-      bottom: 0;
-      right: 0;
-      input {
-        border: none;
-      }
-    }
-
-    .link-enter {
-      width: 16px;
-      height: 16px;
-      border-radius: 50%;
-      background: rgba(255, 255, 255, 0.7);
-      color: rgba(0, 0, 0, 0.7);
-      display: inline-flex;
-      align-items: center;
-      justify-content: center;
-      cursor: pointer;
-    }
-  }
-}
-
-.buttons {
-  position: relative;
-  padding-top: 15px;
-  text-align: right;
-  &::after {
-    content: '';
-    position: absolute;
-    height: 1px;
-    background-color: rgba(255, 255, 255, 0.1);
-    top: 0;
-    bottom: 0;
-    left: -20px;
-    right: -20px;
-  }
-
-  .button {
-    width: auto;
-    padding: 8px 38px;
-    line-height: 1em;
-    &:not(:first-child) {
-      margin-left: 20px;
-    }
-  }
-}
-
-.edit-close {
-  position: absolute;
-  cursor: pointer;
-  top: calc((100% - 18px) / 2);
-  right: 0;
-  transform: translateY(-50%);
-}
-
-.edit-title {
-  padding-bottom: 18px;
-  position: relative;
-
-  &::after {
-    content: '';
-    position: absolute;
-    left: -20px;
-    right: -20px;
-    height: 1px;
-    bottom: 0;
-    background-color: rgba(255, 255, 255, 0.16);
-  }
-}
-
-.link {
-  position: relative;
-
-  .icon {
-    cursor: pointer;
-  }
-}
-
-.link-bubble {
-  --arrow-width: 15px;
-  --arrow-height: 10px;
-  --padding: 0;
-  margin-top: -10px;
-  width: 360px;
-}
-
-.link-text-from {
-  .link-text-input {
-    margin-bottom: 30px;
-  }
-}

+ 0 - 124
src/components/edit-hot-item/styles-manage.vue

@@ -1,124 +0,0 @@
-<template>
-  <div class="hot-styles">
-    <div class="add item" v-if="!props.all">
-      <span class="fun-ctrl">
-        <ui-input
-          class="input"
-          preview
-          :toastErr="toastErr"
-          accept=".jpg, .jpeg, .png"
-          @update:modelValue="iconUpload"
-          type="file"
-        >
-          <template v-slot:replace>
-            <ui-icon type="add" class="icon" />
-          </template>
-        </ui-input>
-      </span>
-    </div>
-    <div
-      v-for="hotStyle in styleAll"
-      class="item"
-      :class="{ active: active === hotStyle }"
-      @click="clickHandler(hotStyle)"
-    >
-      <span>
-        <img :src="getResources(hotStyle.icon)" />
-        <ui-icon
-          class="delete"
-          type="close"
-          @click.stop="emit('delete', hotStyle)"
-          v-if="!hotStyle.default"
-        />
-      </span>
-    </div>
-    <div
-      class="add item style-more"
-      v-if="!props.all && props.styles.length > 5"
-      @click="showAll = !showAll"
-    >
-      <span class="fun-ctrl">
-        <ui-icon :type="showAll ? 'pull-up' : 'pull-down'" class="icon" />
-        <ui-bubble class="more-content" :show="showAll" @click.stop type="bottom">
-          <styles-manage
-            :styles="styles.filter((style) => !styleAll.includes(style))"
-            :active="active"
-            all
-            @quitMore="showAll = false"
-            @uploadStyles="addStyles"
-            @change="clickHandler"
-            @delete="(style) => emit('delete', style)"
-          ></styles-manage>
-        </ui-bubble>
-      </span>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { HotStylesRaw, HotStyleAtom } from "@/store/hot";
-import { getResources } from "@/store/app";
-import { TemploraryID } from "@/store";
-import { ref, computed } from "vue";
-import { LocalStyleAtom, toastErr } from "./constant";
-import { Cropper } from "@kankan/components/index";
-import { ui18n } from "@/lang";
-
-const props = defineProps<{
-  styles: HotStylesRaw;
-  active: HotStyleAtom;
-  all?: boolean;
-}>();
-
-const emit = defineEmits<{
-  (e: "change", style: HotStyleAtom): void;
-  (e: "delete", style: HotStyleAtom): void;
-  (e: "uploadStyles", styles: Array<LocalStyleAtom>): void;
-  (e: "quitMore");
-}>();
-
-const showAll = ref(false);
-const styleAll = computed(() => {
-  if (props.all) {
-    return props.styles;
-  } else {
-    const styles = props.styles.slice(0, props.styles.length > 5 ? 4 : 5);
-    if (!styles.includes(props.active)) {
-      styles[3] = props.active;
-    }
-    return styles;
-  }
-});
-
-const iconUpload = async ({ file, preview }) => {
-  const data = await Cropper.open(preview, {
-    title: ui18n.t("sys.crop"),
-    okText: ui18n.t("sys.enter"),
-    noText: ui18n.t("sys.cancel"),
-  });
-  if (data) {
-    const item = {
-      id: TemploraryID,
-      icon: { file: data[0], preview: data[1] },
-      name: file.name,
-      default: false,
-    };
-    emit("uploadStyles", [item]);
-  }
-};
-
-const clickHandler = (hotStyle: HotStyleAtom) => {
-  if (!props.all) {
-    showAll.value = false;
-  }
-  emit("change", hotStyle);
-};
-
-const addStyles = (newStyles: Array<LocalStyleAtom>) => {
-  emit("uploadStyles", newStyles);
-};
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 2 - 2
src/components/main-panel/index.vue

@@ -28,8 +28,8 @@ import Menu from '@/views/sys/menu'
 import {MenuAtom, MenuRaw} from "@/views/sys/menu/menu.js";
 import { customMap } from "@/hook/custom";
 import { computed, ref } from "vue";
-import "@/preset/pc.scss"
-import "@/preset/style.scss"
+// import "@/preset/pc.scss"
+// import "@/preset/style.scss"
 
 const props = defineProps<{
   menus: MenuRaw,

+ 2 - 0
src/dbo/attach.ts

@@ -6,6 +6,8 @@ import { useParams } from "@/hook/useParams";
 import { encodePassword } from "@/utils";
 import { Code, errTip } from "./code";
 import { status, StatusEum } from "@/store/setup";
+import axios from 'axios'
+
 
 const params = useParams();
 

+ 14 - 0
src/dbo/main.ts

@@ -0,0 +1,14 @@
+import axios from 'axios'
+import {params} from "@/hook";
+
+const instance = axios.create()
+const baseURL =
+  (import.meta.env.VITE_API_BASE_URL
+    ? `/${import.meta.env.VITE_API_BASE_URL}`
+    : "") + `/${params.m}`;
+
+instance.defaults.baseURL = baseURL
+
+console.log(baseURL)
+
+export default instance

+ 0 - 263
src/guide/index.ts

@@ -1,263 +0,0 @@
-import "driver.js/dist/driver.min.css";
-import "@/assets/guide.scss";
-import { router, writeRouteName, writeRouteMeta } from "@/router";
-import Driver from "driver.js";
-import { useAsyncSDK } from "@/hook/useLaser";
-import { ref, watchEffect } from "vue";
-import { asyncTimeout } from "@/utils";
-import { mount } from "./mount";
-import Help from "@/components/help/index.vue";
-import { Mode } from "@/sdk";
-import app from "@/main";
-import { ui18n, lang, langNameEum } from "@/lang";
-import { helpDoc } from "@/views/sys/head/help";
-import { params } from "@/hook";
-
-const loaded = ref(false);
-useAsyncSDK()
-  .then(() => asyncTimeout(1000))
-  .then(() => (loaded.value = true));
-
-const showedGuides = ref<string[]>([]);
-if (localStorage.getItem("showedGuides")) {
-  try {
-    const str = localStorage.getItem("showedGuides");
-    if (str) {
-      showedGuides.value = JSON.parse(str);
-    }
-  } catch {}
-}
-watchEffect(() => {
-  let oldGuides;
-  try {
-    oldGuides = JSON.parse(localStorage.getItem("showedGuides")) || [];
-  } catch {
-    oldGuides = [];
-  }
-  oldGuides.push(
-    ...showedGuides.value.filter((guide) => !oldGuides.includes(guide))
-  );
-  localStorage.setItem("showedGuides", JSON.stringify(oldGuides));
-});
-
-watchEffect((onCleatup) => {
-  const routerName = router.currentRoute.value?.name as string;
-  if (loaded.value && routerName) {
-    showGuide();
-  }
-});
-
-export const repeatGuides = (forceKey?: string) => {
-  const key = getCurrentKey(forceKey);
-  showedGuides.value = showedGuides.value.filter((skey) => skey !== key);
-};
-(window as any).skipEditGuides = () => {
-  skipGuides();
-  showedGuides.value.push(InitKey);
-  advanceClose.value = true;
-  driver?.reset();
-};
-
-export const skipGuides = () => {
-  showedGuides.value = [
-    `user-${writeRouteName.hotspot}`,
-    `user-${writeRouteName.layout}`,
-    `user-${writeRouteName.measure}`,
-    `user-${writeRouteName.query}`,
-    `user-epoint`,
-    `unuser-${Mode.cloud}`,
-    `unuser-${Mode.pano}`,
-  ];
-};
-
-export const disabledGuides = ref(false);
-watchEffect(() => {
-  if (disabledGuides.value) {
-    skipGuides();
-    showedGuides.value.push(InitKey);
-  }
-});
-
-const getEditSteps = (element: Element, name: string) => {
-  const logo = `<img src="${
-    new URL("@/assets/images/pic_kankan.svg", import.meta.url).href
-  }" >
-  <i class="iconfont icon-close close fun-ctrl" onClick="skipEditGuides()"></i>`;
-  const guides = {
-    [writeRouteName.query]: [
-      {
-        img:
-          lang === langNameEum.zh
-            ? new URL("@/assets/images/help/zh/query.gif", import.meta.url).href
-            : "",
-        description: ui18n.t("help.edit.query[0]"),
-        position: "right",
-      },
-    ],
-    [writeRouteName.hotspot]: {
-      img:
-        lang === langNameEum.zh
-          ? new URL("@/assets/images/help/zh/hotspot.gif", import.meta.url).href
-          : "",
-      description: ui18n.t("help.edit.hotspot.0"),
-      position: "right-center",
-    },
-    [writeRouteName.measure]: {
-      img:
-        lang === langNameEum.zh
-          ? new URL("@/assets/images/help/zh/measure.gif", import.meta.url).href
-          : "",
-      description: ui18n.t("help.edit.measure.0"),
-      position: "right-center",
-    },
-    ["epoint"]: {
-      element: ".ui-editor-toolbox",
-      videoLink: ui18n.t(
-        params.kankan ? "help.video.kankanEpoint" : "help.video.epoint"
-      ),
-      popover: {
-        title: `${logo} ${ui18n.t("help.title")} >> ${ui18n.t("epoint.title")}`,
-        description: ui18n.t("help.edit.epoint.0"),
-        position: "left",
-      },
-    },
-  };
-
-  let steps = guides[name];
-  if (steps) {
-    if (!Array.isArray(steps)) {
-      steps = [steps];
-    }
-    steps = steps.map((step, index) => {
-      const popover = step.popover || step;
-      let description = popover.description;
-      if (popover.img) {
-        description = `<img src='${popover.img}' />` + description;
-      }
-      if (step.videoLink) {
-        popover.className = "video-layout";
-        description += `<div class="video-btns">
-          <a class="video-btn" href="${
-            step.videoLink
-          }" target="_blank">${ui18n.t("help.videoBtn")}</a>
-        </div>`;
-      }
-
-      return {
-        popover: {
-          className: popover.className,
-          ...popover,
-          title:
-            popover.title ||
-            `${logo} ${ui18n.t("help.title")} >> ${writeRouteMeta[name].title}`,
-          description,
-        },
-        padding: 0,
-        nextBtnText:
-          step.nextBtnText || index === steps.length - 1
-            ? ui18n.t("sys.ok")
-            : ui18n.t("help.next"),
-        prevBtnText:
-          index === 0 ? "123" : step.prevBtnText || ui18n.t("help.prev"),
-        closeBtnText:
-          step.closeBtnText || steps.length > 1 ? "" : ui18n.t("sys.ok"),
-        doneBtnText: step.doneBtnText || ui18n.t("sys.ok"),
-        element: step.element || element,
-      };
-    });
-  }
-  return steps;
-};
-
-const eleReady = async (ele: string | Element) => {
-  await asyncTimeout(300);
-  if (typeof ele !== "string") {
-    return;
-  }
-  for (let i = 0; i < 10; i++) {
-    if (document.querySelector(ele)) {
-      return;
-    }
-    await asyncTimeout(300);
-  }
-  throw `没有${ele}DOM`;
-};
-
-export const advanceClose = ref(false);
-
-const InitKey = "initShow";
-const getCurrentKey = (forceKey?: string) => {
-  if (!showedGuides.value.includes(InitKey)) {
-    return InitKey;
-  } else {
-    const routerName = forceKey || (router.currentRoute.value?.name as string);
-    return `user-${routerName}`;
-  }
-};
-
-let runing = false;
-let driver: Driver;
-export const showGuide = async (forceKey?: string) => {
-  const key = getCurrentKey(forceKey);
-  if (runing || showedGuides.value.includes(key)) {
-    return;
-  }
-  runing = true;
-
-  if (key === InitKey) {
-    const { destroy } = mount(Help as any, {
-      app,
-      element: document.body,
-      props: {
-        class: "edit-goto",
-        steps: [
-          {
-            content: ui18n.t("help.init"),
-            img: (await import("@/assets/images/pic_laser@2x.png")).default,
-            imgWidth: "100",
-          },
-        ],
-        showStep: false,
-        btns: [
-          { key: "link", label: ui18n.t("help.link"), type: "submit" },
-          { key: "yin", label: ui18n.t("help.title"), type: "primary" },
-        ],
-        clickBtn(key) {
-          if (key === "yin") {
-            destroy();
-            runing = false;
-            showGuide(forceKey);
-          } else {
-            window.open(helpDoc);
-          }
-        },
-        close: (step) => {
-          (window as any).skipEditGuides();
-          destroy();
-          runing = false;
-        },
-      },
-    });
-  } else {
-    const routerName = forceKey || (router.currentRoute.value?.name as string);
-    const element = document.querySelector(`[data-route-name="${routerName}"]`);
-    if (!forceKey && !element) {
-      runing = false;
-      return;
-    }
-    const steps = getEditSteps(element, routerName);
-    if (!steps) {
-      runing = false;
-      return;
-    }
-    await Promise.all(steps.map((step) => eleReady(step.element)));
-    driver = new Driver({
-      onReset() {
-        runing = false;
-      },
-    });
-    driver.defineSteps(steps);
-    driver.start();
-  }
-  showedGuides.value.push(key);
-};

+ 0 - 39
src/guide/mount.ts

@@ -1,39 +0,0 @@
-import { createVNode, render } from 'vue'
-import type { App, VNode } from 'vue'
-
-interface ComponentConstructor<P = any> {
-  new (...args: any[]): {
-    $props: P
-  }
-}
-
-export type MountContext<P = any> = {
-  props?: P
-  children?: unknown
-  element?: HTMLElement
-  app?: App
-}
-
-export function mount<P>(
-  component: ComponentConstructor<P>,
-  { props, children, element, app }: MountContext<P> = {}
-) {
-  let el = element
-  let vNode: VNode | undefined = createVNode(component, props as any, children)
-
-  if (app && app._context) vNode.appContext = app._context
-  if (el) {
-    render(vNode, el)
-    console.log('render', el)
-  } else if (typeof document !== 'undefined') {
-    render(vNode, (el = document.createElement('div')))
-  }
-
-  const destroy = () => {
-    if (el) render(null, el)
-    el = undefined
-    vNode = undefined
-  }
-
-  return { vNode, destroy, el }
-}

+ 1 - 55
src/hook/useLaser.ts

@@ -2,9 +2,8 @@ import { sdkFactory, SDK, SDKProps, DensityType, Pos3D, Mode } from "@/sdk";
 import { watch, watchEffect } from "vue";
 import { store } from "@/store";
 import { loadLib, toRawType } from "@/utils";
-import { laserModeStack } from "./custom/preset";
 import { Message } from "@kankan/components/index";
-import { ui18n } from "@/lang";
+import { ui18n } from "@/lang/index";
 import { DataSetAtom } from "@/sdk";
 
 let sdk: SDK;
@@ -27,58 +26,6 @@ export const useDataset = (dataset: DataSetAtom) => {
   return rdataset;
 };
 
-const relationStore = (sdk: SDK, { setting, setup }: typeof store) => {
-  watch(
-    () => setting.density,
-    (newv, olv) => {
-      if (toRawType(olv) !== "Undefined") {
-        if (setting.density === DensityType.high) {
-          setting.range = 300;
-        } else if (setting.density === DensityType.middle) {
-          setting.range = 150;
-        } else if (setting.density === DensityType.low) {
-          setting.range = 50;
-        }
-      }
-      const info = sdk.scene.changePointDensity(setting.density);
-      if (toRawType(olv) !== "Undefined") {
-        console.log("--->", info.percent);
-        setting.detail = info.percent;
-      }
-    },
-    { immediate: true }
-  );
-  watch(
-    () => setting.colorMode,
-    (newv, olv) => {
-      const info = sdk.scene.changeColorMode(setting.colorMode);
-      if (toRawType(olv) !== "Undefined") {
-        setting.opacity = info.opacity;
-        setting.size = info.size;
-      }
-    },
-    { immediate: true }
-  );
-
-  watchEffect(() => sdk.scene.changePointShape(setting.shape));
-  watchEffect(() => sdk.scene.changePanoPoint(setting.showRoamPos));
-  watchEffect(() => sdk.scene.changeViewRange(setting.range));
-  watchEffect(() => sdk.scene.changePointOpacity(setting.opacity));
-  watchEffect(() => sdk.scene.changePointSize(setting.size));
-  watchEffect(() => sdk.scene.changePointEdge(setting.edgeStrong));
-  watchEffect(() => sdk.scene.changeDensityPercent(setting.detail));
-
-  watchEffect(
-    () =>
-      setup.pose &&
-      sdk.scene.setPose({
-        position: setup.pose.inisPosition,
-        yaw: setup.pose.inisDirection.yaw,
-        pitch: setup.pose.inisDirection.pitch,
-      })
-  );
-};
-
 const listenLoaded: Function[] = [];
 export const useAsyncSDK = () => {
   if (sdk) {
@@ -114,7 +61,6 @@ export const setupLaser = async (
     sdk = sdkFactory(props as any);
     sdk.scene.on("allLoaded", () => resolve(sdk));
   }).then((sdk) => {
-    relationStore(sdk, props.store);
     for (const fn of listenLoaded) {
       setTimeout(fn, 0, sdk);
     }

+ 1 - 1
src/main.ts

@@ -7,7 +7,7 @@ import { setupI18n } from "@/lang";
 import { router, setupRouter } from "@/router";
 import appConfig from "./appConfig";
 import { currentApp, setCurrentApp } from "@/store/app";
-import App from "./preset/slot.vue";
+import App from "./main.vue";
 
 const app = createApp(App);
 

src/preset/slot.vue → src/main.vue


+ 0 - 40
src/preset/app.vue

@@ -1,40 +0,0 @@
-<template>
-  <template v-if="loaded">
-    <Component />
-  </template>
-</template>
-
-<script setup lang="ts">
-import { ref, computed } from "vue";
-import { baseInitStore } from "./preset";
-import { useAsyncComponent, useParams } from "@/hook";
-import { store as setup, inVerify, StatusEum } from "@/store/setup";
-
-const props = defineProps<{ main?: any }>();
-
-const params = useParams();
-const loaded = ref(false);
-const Main = props.main || useAsyncComponent(() => import("./traffic-main.vue"));
-const Err = useAsyncComponent(() => import("@/views/sys/err/index.vue"));
-
-const Component = computed(() => {
-  if (setup.status === StatusEum.success) {
-    return Main;
-  } else {
-    return Err;
-  }
-});
-
-if (!params.m) {
-  setup.status = StatusEum.un;
-  loaded.value = true;
-} else {
-  baseInitStore()
-    .then(() => (loaded.value = true))
-    .catch((e) => {
-      loaded.value = true;
-    });
-}
-</script>
-
-<style scoped lang="scss"></style>

+ 0 - 237
src/preset/main.vue

@@ -1,237 +0,0 @@
-<template>
-  <ui-editor-layout
-    @click.stop
-    id="layout-app"
-    class="editor-layout"
-    :class="{
-      [`sys-view-${customMap.sysView}`]: true,
-      'edit-mode': isEdit || showToolbar,
-      'navogatopn-mode': showToolbar,
-      'setting-mode': showToolbar,
-      'put-ctrl-pano': putCtrl || disabledMap.tool,
-      'unfold-ctrl-pano': !putCtrl && !disabledMap.tool,
-      ['full']: !loaded,
-      [customMap.carryView]: loaded,
-      ['tablet']: os.isPc && os.isTablet,
-    }"
-    :style="styles"
-  >
-    <div class="laser-layer">
-      <!-- @click.right="ev => rightClickHandler(ev, laser.scene)" -->
-      <div class="scene" ref="sceneRef" :class="{ loading: !disabledMap.laserLoading }">
-        <span
-          @click="customMap.full = 'scene'"
-          class="taggle switch"
-          v-if="customMap.full === 'map'"
-        >
-          <ui-icon
-            type="switch"
-            class="icon"
-            ctrl
-            :tip="$t('view.switchView')"
-            tip-h="left"
-          />
-        </span>
-      </div>
-      <div :style="{ opacity: loaded ? '1' : '0' }">
-        <div class="map" ref="mapRef">
-          <span
-            @click="customMap.full = 'map'"
-            class="taggle switch"
-            v-if="customMap.full === 'scene'"
-          >
-            <ui-icon
-              type="switch"
-              class="icon"
-              ctrl
-              :tip="$t('view.switchView')"
-              tip-h="left"
-            />
-          </span>
-        </div>
-      </div>
-      <span
-        @click.stop="minimumHandler"
-        class="taggle minimum"
-        v-if="
-          (customMap.full === 'scene' && !disabledMap.map) ||
-          (customMap.full === 'map' && !disabledMap.clound)
-        "
-        :class="{
-          active: mapMinium || !os.isPc,
-          pc: os.isPc,
-          'in-map': customMap.full === 'map',
-          panmode: customMap.boxWidth === 'calc(100% - 60px)',
-        }"
-      >
-        <ui-icon
-          :type="mapMinium || !os.isPc ? 'map-m' : 'close'"
-          class="icon"
-          :tip="
-            $t('view.switchMiniView', {
-              action: mapMinium ? $t('sys.open') : $t('sys.close'),
-            })
-          "
-          tip-v="top"
-          tip-h="right"
-          ctrl
-        />
-      </span>
-    </div>
-
-    <div v-if="loaded" style="height: 100%">
-      <span
-        class="ctrl-pano-c fun-ctrl strengthen-left strengthen-top strengthen-bottom"
-        v-if="customMap.sysView !== 'full' && !disabledMap.tool && os.isPc"
-        @click="putCtrl = !putCtrl"
-        :class="{ active: putCtrl }"
-      >
-        <ui-icon type="extend" class="icon"></ui-icon>
-      </span>
-      <router-view v-slot="{ Component }" v-if="currentApp.routerRef">
-        <keep-alive>
-          <component :is="Component" />
-        </keep-alive>
-      </router-view>
-      <Sys />
-    </div>
-  </ui-editor-layout>
-</template>
-
-<script lang="ts" setup>
-import Sys from "@/views/sys/index.vue";
-import { onMounted, onUnmounted, ref, watch, watchEffect } from "vue";
-import { Pose, SDK } from "@/sdk";
-import { store, isEdit, showToolbar, appEl, isLogin } from "@/store";
-import {
-  customMap,
-  disabledMap,
-  setupLaser,
-  boxWidthStack,
-  useParams,
-  sysViewStack,
-  useLoading,
-  params,
-} from "@/hook";
-import { basePreset, presetLogin, presetDelogin } from "./preset";
-import { status, StatusEum, webSite } from "@/store/setup";
-import router from "@/router";
-import { os } from "@/utils";
-import { currentApp } from "@/store/app";
-import { axios } from "@/dbo";
-
-const mapRef = ref(null);
-const sceneRef = ref(null);
-const laser = ref<SDK>(null) as any;
-const loaded = ref(false);
-const putCtrl = ref(false);
-const mapMinium = ref(false);
-
-const minimumHandler = () => {
-  if (!os.isPc) {
-    if (customMap.full === "scene") {
-      customMap.full = "map";
-    } else {
-      customMap.full = "scene";
-    }
-  } else {
-    if (mapMinium.value) {
-      laser.value.minimumHide();
-    } else {
-      laser.value.minimumShow();
-    }
-    mapMinium.value = !mapMinium.value;
-  }
-};
-
-let inPush = false;
-watchEffect(() => {
-  if (isEdit.value) {
-    inPush = true;
-    sysViewStack.push(ref("auto"));
-  } else if (inPush) {
-    inPush = false;
-    sysViewStack.pop();
-  }
-});
-
-const styles = ref({});
-watch(
-  () => boxWidthStack.current.value,
-  (val) => {
-    if (val) {
-      styles.value["--editor-toolbox-width"] = val;
-    } else {
-      delete styles.value["--editor-toolbox-width"];
-    }
-  }
-);
-
-onMounted(async () => {
-  appEl.value = document.querySelector("#layout-app") as any;
-
-  try {
-    const sdk = await useLoading(
-      setupLaser({
-        sceneSelector: sceneRef.value,
-        num: useParams().m,
-        store: store,
-        isDebug: useParams().test,
-        webSite: webSite.value,
-        axios,
-        basePath: currentApp.basePath,
-      })
-    );
-
-    // 如果是移动端主动隐藏小地图
-    sdk.minimumShow();
-
-    laser.value = sdk;
-    sdk.scene.on("webglError", () => {
-      status.value = StatusEum.webglErr;
-    });
-
-    (window as any).getCurrentPose = async () => {
-      const pose = await sdk.scene.getPose();
-      const poseURL = encodeURI(JSON.stringify(pose));
-      console.log(poseURL);
-      return poseURL;
-    };
-
-    if (params.flyPose) {
-      try {
-        const position: Pose = JSON.parse(decodeURI(params.flyPose));
-        sdk.scene.setPose(position);
-      } catch (e) {}
-    }
-  } catch (e) {
-    status.value = StatusEum.sdkErr;
-    throw e;
-  }
-
-  try {
-    await basePreset();
-  } catch (e) {
-    if (status.value === StatusEum.success) {
-      // status.value = StatusEum.presetErr
-      status.value = StatusEum.webglErr;
-    }
-    throw e;
-  }
-  await presetLogin();
-
-  loaded.value = true;
-  console.log("???");
-  watch(router.currentRoute, () => {
-    putCtrl.value = false;
-  });
-});
-
-onUnmounted(() => {
-  laser.value.scene.off("*");
-});
-</script>
-
-<style lang="scss" scoped>
-@import "./style.scss";
-</style>

+ 0 - 35
src/preset/mobile.scss

@@ -1,35 +0,0 @@
-:root body {
-  // right-tool
-  --editor-toolbox-width: calc(100vw - var(--editor-menu-width));
-  // 隐藏head
-  --hide-header-top: calc(-1 * var(--editor-head-height));
-  // 显示head
-  --show-header-top: calc(-1 * var(--editor-head-height));
-  // mini-map size
-  --simle-map-width: 300px;
-  --simle-map-height: 150px;
-  --scale-simle-map-width: 300px;
-  --scale-simle-map-height: 200px;
-
-  --global-search-width: calc(100% - 72px);
-
-  --taggle-btn-width: 42px;
-  --body-right-margin: 10px;
-
-  .ui-editor-toolbox {
-    z-index: 300;
-    padding-top: calc(var(--padding-top) + 20px);
-  }
-
-  .ui-editor-head {
-    z-index: 3000;
-  }
-
-  -webkit-tap-highlight-color: transparent;
-  -webkit-touch-callout: none;
-}
-
-.horizontal .hot-item .hot-bubble:not(.pc) {
-  width: 356px !important;
-  --bottom-left: 173px !important;
-}

+ 0 - 15
src/preset/pc.scss

@@ -1,15 +0,0 @@
-:root body {
-  --hide-header-top: calc(-1 * var(--editor-head-height));
-  --show-header-top: 0px;
-  // mini-map size
-  --simle-map-width: 400px;
-  --simle-map-height: 200px;
-  --scale-simle-map-width: 600px;
-  --scale-simle-map-height: 300px;
-  // 搜索框
-  --global-search-width: 340px;
-
-  --taggle-btn-width: 30px;
-
-  --body-right-margin: 20px;
-}

+ 0 - 200
src/preset/preset.ts

@@ -1,200 +0,0 @@
-import {
-  customMap,
-  customSetup,
-  RightMenuAtom,
-  useSDK,
-  RouteCustomConfig,
-  DisabledCom,
-  RightMenuEum,
-  disabledMap,
-  residenMouseMenuDisapbedStack,
-} from "@/hook";
-import { setupEdit } from "@/hook/useEdit";
-import { computed, reactive, ref, watchEffect } from "vue";
-import router, { routeName } from "@/router";
-import { requestData as hotRequestData } from "@/store/hot";
-import { requestData as measureRequestData } from "@/store/measure";
-import { requestData as setupRequestData } from "@/store/setup";
-import { writeRouteName } from "@/router";
-import { isEdit, mode, modeFlags, TemploraryID } from "@/store";
-import EditHotItem from "@/components/show-hot-item/edit.vue";
-import ShowHotItem from "@/components/show-hot-item/index.vue";
-import { HotAtom, Mode } from "@/sdk";
-import { currentApp } from "@/store/app";
-import { ui18n } from "@/lang";
-
-// 界面显示隐藏组件定义
-export const customConfig: RouteCustomConfig = {
-  [writeRouteName.measure]: {
-    disabled: [DisabledCom.Hot],
-    enabled: [DisabledCom.Measure],
-  },
-  [writeRouteName.setup]: {
-    // disabled: [DisabledCom.lmenu],
-  },
-};
-
-// 初始化定制化组件
-export const initCustom = (() => {
-  let inInit = false;
-  return () => {
-    const sdk = useSDK();
-    customSetup(sdk, router, customConfig);
-
-    inInit = true;
-  };
-})();
-// 基础启动查询
-export const baseInitStore = (() => {
-  let inInit = false;
-  let result: Promise<any>;
-  return () => {
-    if (!inInit) {
-      inInit = true;
-      result = Promise.all([setupRequestData()]);
-    }
-    return result;
-  };
-})();
-
-// 初始化store
-export const initStore = (() => {
-  let inInit = false;
-  let result: Promise<any>;
-  const request = async () => {
-    await baseInitStore();
-    const reqs: Promise<any>[] = [hotRequestData(), measureRequestData()];
-    if (currentApp.auth) {
-      reqs.push(currentApp.auth.request());
-    }
-    await Promise.all(reqs);
-  };
-  return () => {
-    if (!inInit) {
-      inInit = true;
-      result = request();
-    }
-    return result;
-  };
-})();
-
-// 初始化setupedit
-export const initUseEditView = () => {
-  setupEdit({
-    edit: () => {
-      mode.value |= modeFlags.EDIT;
-    },
-    leave: () => {
-      mode.value &= ~modeFlags.EDIT;
-    },
-    leaveSave: () => {
-      mode.value |= modeFlags.SAVED;
-    },
-    desave: () => {
-      mode.value &= ~modeFlags.SAVED;
-    },
-  });
-};
-
-let inFirst = true;
-// 已经登录用户的初始化数据准备
-export const presetLogin = (() => {
-  return async () => {
-    inFirst = false;
-    const sdk = useSDK();
-    sdk.carry.hotTheme.push({
-      component: EditHotItem,
-      props: {
-        onEdit: (hot: HotAtom) => {
-          router.push({
-            name: routeName.value.hotspot,
-            params: { id: hot.id, edit: 1, random: Math.random() },
-          });
-        },
-      },
-    });
-    const include = (name) =>
-      computed(() =>
-        currentApp.menu.value.list.some((atom) => atom.name === name)
-      );
-    const attachMenus = [
-      {
-        menu: reactive({
-          key: RightMenuEum.AddHot,
-          color: "#fff",
-          icon: "add",
-          mapDisabled: true,
-          label: ui18n.t("hotspot.addMenu"),
-          click: (pos) => {
-            router.push({
-              name: routeName.value.hotspot,
-              params: {
-                id: TemploraryID,
-                pos: JSON.stringify(pos),
-                edit: 1,
-              },
-            });
-          },
-        } as RightMenuAtom),
-        joinName: writeRouteName.hotspot,
-        include: include(writeRouteName.hotspot),
-      },
-    ];
-    const stopWatch = watchEffect(() => {
-      for (const { joinName, menu } of attachMenus) {
-        menu.custDisabled =
-          isEdit.value && router.currentRoute.value.name !== joinName;
-      }
-    });
-
-    const stopMenu = watchEffect(() => {
-      for (const { include, menu } of attachMenus) {
-        if (include.value) {
-          customMap.rMouseMenu.includes(menu) ||
-            customMap.rMouseMenu.push(menu);
-        } else {
-          const index = customMap.rMouseMenu.indexOf(menu);
-          ~index && customMap.rMouseMenu.splice(index, 1);
-        }
-      }
-    });
-    customMap.sysView = "auto";
-
-    inFirst = false;
-    return () => {
-      stopWatch();
-      stopMenu();
-      for (const { menu } of attachMenus) {
-        const index = customMap.rMouseMenu.indexOf(menu);
-        ~index && customMap.rMouseMenu.splice(index, 1);
-      }
-    };
-  };
-})();
-
-export const basePreset = async () => {
-  await Promise.all([initCustom(), initStore(), initUseEditView()]);
-  if (currentApp.preset) {
-    await currentApp.preset();
-  }
-
-  // 非热点页面编辑模式不展开热点信息
-  watchEffect(() => {
-    disabledMap.hotInfo = !(
-      !isEdit.value || router.currentRoute.value.name === writeRouteName.hotspot
-    );
-  });
-
-  let inSet = false;
-  watchEffect(() => {
-    if (isEdit.value) {
-      if (!inSet) {
-        residenMouseMenuDisapbedStack.push(ref(true));
-        inSet = true;
-      }
-    } else if (inSet) {
-      residenMouseMenuDisapbedStack.pop();
-      inSet = false;
-    }
-  });
-};

+ 0 - 196
src/preset/style.scss

@@ -1,196 +0,0 @@
-.tablet {
-  // mini-map size
-  --simle-map-width: 330px;
-  --simle-map-height: 200px;
-}
-
-.edit-mode {
-  --editor-menu-left: calc(-1 * var(--editor-menu-width));
-}
-.navogatopn-mode {
-  --editor-menu-right: calc(-1 * var(--editor-toolbox-width));
-}
-
-.editor-layout {
-  --editor-menu-bottom: 0px;
-
-  &.auto {
-    background-color: #000;
-  }
-}
-.setting-mode {
-  --editor-menu-bottom: 60px;
-}
-
-.sys-view-full {
-  --header-top: var(--hide-header-top);
-  --editor-menu-right: calc(-1 * var(--editor-toolbox-width)) !important;
-  --editor-menu-left: calc(-1 * var(--editor-menu-width));
-  --search-left: 52px;
-}
-
-.app {
-  --padding-top: 30px;
-  --header-top: calc(var(--hide-header-top) + var(--padding-top));
-}
-
-.sys-view-auto {
-  --header-top: var(--show-header-top);
-  --search-left: 0px;
-}
-
-.put-ctrl-pano {
-  --editor-menu-right: calc(-1 * var(--editor-toolbox-width));
-}
-.unfold-ctrl-pano {
-  --editor-menu-right: 0px;
-}
-
-.ctrl-pano-c {
-  position: absolute;
-  right: calc(var(--editor-menu-right) + var(--editor-toolbox-width));
-  width: 20px;
-  height: 80px;
-  background: rgba(26, 26, 26, 0.8);
-  border-radius: 6px 0px 0px 6px;
-  top: 50%;
-  transform: translateY(-50%);
-  z-index: 1;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  color: rgba(255, 255, 255, 0.7);
-  font-size: 14px;
-  cursor: pointer;
-  transition: inset 0.3s ease, color 0.3s ease;
-
-  &:hover {
-    color: rgba(255, 255, 255, 1);
-  }
-
-  &:active {
-    color: var(--colors-primary-base);
-  }
-
-  .icon {
-    display: inline-block;
-    transition: transform 0.3s ease;
-    transform: rotate(0);
-  }
-  &.active {
-    .icon {
-      transform: rotate(180deg);
-    }
-  }
-}
-
-.laser-layer {
-  position: absolute;
-  z-index: 1;
-
-  #potree_sidebar_container {
-    position: absolute;
-    top: var(--editor-head-height);
-    left: var(--editor-menu-width);
-    bottom: 0;
-    width: 300px;
-    z-index: 3;
-  }
-
-  .scene.loading::after {
-    content: '';
-    position: absolute;
-    z-index: 999;
-    left: 0;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    background-color: #000;
-  }
-}
-
-.full .laser-layer {
-  width: 100%;
-  height: 100%;
-}
-
-.auto .laser-layer {
-  --left-width: 70px;
-}
-.not-left .laser-layer {
-  --left-width: 0px;
-}
-.auto-not-left .laser-layer,
-.auto .laser-layer {
-  margin-top: var(--editor-head-height);
-  height: calc(100% - var(--editor-head-height));
-  transition: width 0.3s ease;
-  margin-left: var(--left-width);
-  width: calc(
-    100% - (var(--editor-toolbox-width) + var(--editor-menu-right)) -
-      var(--left-width)
-  );
-}
-
-.taggle {
-  position: absolute;
-  font-size: 16px;
-  color: #fff;
-  background: rgba(0, 0, 0, 0.2);
-  z-index: 9999999;
-  width: var(--taggle-btn-width);
-  height: var(--taggle-btn-width);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  border-radius: 3px;
-  cursor: pointer;
-  i {
-    display: inline-block;
-    width: 100%;
-    height: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  &.switch {
-    left: 10px;
-    top: 10px;
-  }
-
-  &.minimum {
-    transition: all 0.3s ease;
-
-    &.active {
-      background: rgba(27, 27, 28, 0.8);
-      border-radius: 4px;
-      border: 1px solid #000000;
-      color: rgba(255, 255, 255, 0.7);
-    }
-
-    &:not(.pc) {
-      bottom: 42px;
-      font-size: 24px;
-      left: calc(
-        var(--editor-menu-left) + var(--editor-menu-width) +
-          var(--body-right-margin)
-      );
-
-      &.panmode {
-        left: 70px;
-      }
-
-      &.in-map i {
-        color: var(--color-main-normal) !important;
-      }
-    }
-    &.pc {
-      bottom: 20px;
-      right: calc(
-        var(--editor-menu-right) + var(--editor-toolbox-width) +
-          var(--body-right-margin)
-      );
-    }
-  }
-}

+ 0 - 159
src/preset/traffic-main.vue

@@ -1,159 +0,0 @@
-<template>
-  <ui-editor-layout
-    @click.stop
-    id="layout-app"
-    class="editor-layout"
-    :class="{
-      [`sys-view-${customMap.sysView}`]: true,
-      'edit-mode': isEdit || showToolbar,
-      'navogatopn-mode': showToolbar,
-      'setting-mode': showToolbar,
-      'put-ctrl-pano': putCtrl || disabledMap.tool,
-      'unfold-ctrl-pano': !putCtrl && !disabledMap.tool,
-      ['full']: !loaded,
-      [customMap.carryView]: loaded,
-      ['tablet']: os.isPc && os.isTablet,
-    }"
-    :style="styles"
-  >
-    <div class="laser-layer">
-      <!-- @click.right="ev => rightClickHandler(ev, laser.scene)" -->
-      <div
-        class="scene"
-        ref="sceneRef"
-        :class="{ loading: !disabledMap.laserLoading }"
-      ></div>
-    </div>
-
-    <div v-if="loaded" style="height: 100%">
-      <span
-        class="ctrl-pano-c fun-ctrl strengthen-left strengthen-top strengthen-bottom"
-        v-if="customMap.sysView !== 'full' && !disabledMap.tool && os.isPc"
-        @click="putCtrl = !putCtrl"
-        :class="{ active: putCtrl }"
-      >
-        <ui-icon type="extend" class="icon"></ui-icon>
-      </span>
-      <router-view v-slot="{ Component }" v-if="currentApp.routerRef">
-        <keep-alive>
-          <component :is="Component" />
-        </keep-alive>
-      </router-view>
-      <Sys />
-    </div>
-  </ui-editor-layout>
-</template>
-
-<script lang="ts" setup>
-import Sys from "@/views/sys/index.vue";
-import { onMounted, onUnmounted, ref, watch, watchEffect } from "vue";
-import { Pose, SDK } from "@/sdk";
-import { store, isEdit, showToolbar, appEl } from "@/store";
-import {
-  customMap,
-  disabledMap,
-  setupLaser,
-  boxWidthStack,
-  useParams,
-  sysViewStack,
-  useLoading,
-  params,
-} from "@/hook";
-import { basePreset, presetLogin } from "./preset";
-import { status, StatusEum, webSite } from "@/store/setup";
-import router from "@/router";
-import { os } from "@/utils";
-import { currentApp } from "@/store/app";
-import { axios } from "@/dbo";
-
-const sceneRef = ref(null);
-const laser = ref<SDK>(null) as any;
-const loaded = ref(false);
-const putCtrl = ref(false);
-
-let inPush = false;
-watchEffect(() => {
-  if (isEdit.value) {
-    inPush = true;
-    sysViewStack.push(ref("auto"));
-  } else if (inPush) {
-    inPush = false;
-    sysViewStack.pop();
-  }
-});
-
-const styles = ref({});
-watch(
-  () => boxWidthStack.current.value,
-  (val) => {
-    if (val) {
-      styles.value["--editor-toolbox-width"] = val;
-    } else {
-      delete styles.value["--editor-toolbox-width"];
-    }
-  }
-);
-
-onMounted(async () => {
-  appEl.value = document.querySelector("#layout-app") as any;
-
-  try {
-    const sdk = await useLoading(
-      setupLaser({
-        sceneSelector: sceneRef.value,
-        num: useParams().m,
-        store: store,
-        isDebug: useParams().test,
-        webSite: webSite.value,
-        axios,
-        basePath: currentApp.basePath,
-      } as any)
-    );
-
-    laser.value = sdk;
-    sdk.scene.on("webglError", () => {
-      status.value = StatusEum.webglErr;
-    });
-
-    (window as any).getCurrentPose = async () => {
-      const pose = await sdk.scene.getPose();
-      const poseURL = encodeURI(JSON.stringify(pose));
-      console.log(poseURL);
-      return poseURL;
-    };
-
-    if (params.flyPose) {
-      try {
-        const position: Pose = JSON.parse(decodeURI(params.flyPose));
-        sdk.scene.setPose(position);
-      } catch (e) {}
-    }
-  } catch (e) {
-    status.value = StatusEum.sdkErr;
-    throw e;
-  }
-
-  try {
-    await basePreset();
-  } catch (e) {
-    if (status.value === StatusEum.success) {
-      // status.value = StatusEum.presetErr
-      status.value = StatusEum.webglErr;
-    }
-    throw e;
-  }
-  await presetLogin();
-  loaded.value = true;
-  watch(router.currentRoute, () => {
-    putCtrl.value = false;
-  });
-});
-
-onUnmounted(() => {
-  laser.value?.scene.off("*");
-});
-</script>
-
-<style lang="scss" scoped>
-@import "./style.scss";
-</style>

+ 1 - 31
src/router/info.ts

@@ -6,8 +6,6 @@ import {
   RouteMetaRaw,
   readyRouteMeta,
   readyRouteName,
-  writeRouteName,
-  writeRouteMeta,
   defRouteName,
 } from "./constant";
 
@@ -32,39 +30,11 @@ export const baseAppRoute: RouteAtom = {
   component: () => import("@/preset/app.vue"),
 };
 
-export const readlyChildren: RoutesRaw = [
-  {
-    path: "",
-    name: readyRouteName.query,
-    meta: readyRouteMeta.query,
-    component: () => import("@/views/query/index.vue"),
-  },
-  {
-    path: "hotspot",
-    name: readyRouteName.hotspot,
-    meta: readyRouteMeta.hotspot,
-    component: () => import("@/views/hotspot/index.vue"),
-  },
-  {
-    path: "measure",
-    name: readyRouteName.measure,
-    meta: readyRouteMeta.measure,
-    component: () => import("@/views/measure/index.vue"),
-  },
-];
+export const readlyChildren: RoutesRaw = [];
 
-export const readlyRoutesRaw: RoutesRaw = [
-  { ...baseAppRoute, children: readlyChildren },
-];
 
 export const writeChildren: RoutesRaw<typeof modeFlags.LOGIN> = [
   ...readlyChildren,
-  {
-    path: "setup",
-    name: writeRouteName.setup,
-    meta: writeRouteMeta.setup,
-    component: () => import("@/views/setup/index.vue"),
-  },
 ];
 
 export const writeRoutesRaw: RoutesRaw<typeof modeFlags.LOGIN> = [

+ 4 - 11
src/sdk/carry/instance.ts

@@ -1,7 +1,6 @@
-import { markRaw, reactive, shallowReactive } from 'vue'
-import { stackFactory, mangeStackFactory } from '@/utils'
-import { CarryComponentProps, HotAtom, MeasureAtom, Theme, CoordType, InjectTheme } from '../types'
-import { LocalCoord } from '@/hook/useTransform'
+import {markRaw, reactive, shallowReactive} from 'vue'
+import {mangeStackFactory, stackFactory} from '@/utils'
+import {CarryComponentProps, HotAtom, InjectTheme, MeasureAtom, Theme} from '../types'
 
 export const carryInstanceFactory = (props: CarryComponentProps) => {
     props.measureMap = reactive(new WeakMap())
@@ -10,7 +9,7 @@ export const carryInstanceFactory = (props: CarryComponentProps) => {
     props.measureTheme = mangeStackFactory<MeasureAtom, Theme>()
     props.injectThemes = shallowReactive([])
 
-    const instance = {
+    return {
         // vue是否已经初始化完成
         store: props,
         vueSetup: false,
@@ -18,11 +17,7 @@ export const carryInstanceFactory = (props: CarryComponentProps) => {
         coordTheme: props.coordTheme,
         measureMap: props.measureMap,
         measureTheme: props.measureTheme,
-        setCoordType(type: null | LocalCoord | string) {
-            props.store.coord = type
-        },
         setShowHots: show => (props.share.showHots = show),
-        setForeShowHot: (hot: HotAtom) => (props.share.foreShowHot = hot),
         setShowMeasures: show => (props.showMeasures = show),
         use(theme: InjectTheme) {
             const propsRef = reactive(theme.props)
@@ -38,6 +33,4 @@ export const carryInstanceFactory = (props: CarryComponentProps) => {
             return destroy
         },
     }
-
-    return instance
 }

+ 0 - 2
src/sdk/carry/setup.vue

@@ -1,13 +1,11 @@
 <template>
   <div class="carry-layer" @click.right.stop.prevent>
-    <Hots />
     <Measures v-if="props.showMeasures" />
     <InjectComponent />
   </div>
 </template>
 
 <script setup lang="ts">
-import Hots from "./hots/index.vue";
 import Measures from "./measures/index.vue";
 import InjectComponent from "./inject/index.vue";
 import { propsKey, laserKey } from "./constant";

+ 1 - 17
src/sdk/types/store.ts

@@ -1,18 +1,6 @@
-import { HotsRaw } from './hot'
-import { LocalCoord } from '@/hook/useTransform'
-import { MeasuresRaw, MeasureUnit } from './measure'
-import { NavigationAtom } from './navigation'
-import { CtrlStore } from './controlPoint'
-import { Ref } from 'vue'
-import { Setup } from '@/store/setup'
-import { AppConfig } from '@/store/app'
+import { MeasuresRaw, MeasureUnit } from '@/sdk'
 
 export type Store = {
-    hot: {
-        list: HotsRaw
-        show: boolean
-    }
-    coord?: LocalCoord | string
     measure?: {
         list: MeasuresRaw
         unit: MeasureUnit
@@ -21,8 +9,4 @@ export type Store = {
         baseLines: MeasuresRaw
         unit: MeasureUnit
     }
-    navigation: NavigationAtom
-    showNavpanel?: Ref<boolean>
-    controlPoint: CtrlStore
-    setup: Setup,
 }

+ 1 - 0
src/store/fixPoint.ts

@@ -2,6 +2,7 @@ import {ref} from "vue";
 
 export type FixPoint = {
   id: string
+  text: string
   pos: {
     x: number,
     y: number,

+ 0 - 140
src/store/hot.ts

@@ -1,140 +0,0 @@
-import { ref, Ref, UnwrapRef, reactive } from "vue";
-import { HotStyleAtom, HotStylesRaw, HotsRaw, HotAtom } from "@/sdk/types/hot";
-import { axios, URL } from "@/dbo";
-import { TemploraryID } from "./constant";
-import { inRevise } from "@/utils";
-
-export type HotStyles = Ref<HotStylesRaw>;
-export type Hots = Ref<HotsRaw>;
-export * from "@/sdk/types/hot";
-
-export const styles: HotStyles = ref([]);
-export const list: Hots = ref([]);
-export const show = ref(true);
-export const listStore = reactive({
-  list,
-  styles,
-});
-export const store = reactive({
-  list,
-  styles,
-  show,
-});
-
-let backupData: UnwrapRef<typeof listStore>;
-export const getBackups = () => backupData;
-export const backups = () => {
-  backupData = {
-    list: listStore.list.map((item) => ({
-      ...item,
-      visualRange: [...item.visualRange],
-      meta: item.meta && [...item.meta],
-    })),
-    styles: listStore.styles.map((item) => ({ ...item })),
-  };
-};
-export const recovery = () => {
-  if (backupData) {
-    listStore.styles = backupData.styles;
-    listStore.list = assembly(backupData.styles, backupData.list);
-  }
-};
-
-const assembly = (styles: HotStylesRaw, list: HotsRaw) => {
-  for (const item of list) {
-    item.style = styles.find(({ id }) => !item.style || id === item.style.id);
-  }
-  return list;
-};
-
-export const requestData = async () => {
-  // const [ohots, ostyles] = await Promise.all([
-  //   axios.get(URL.hotlist),
-  //   axios.get(URL.stylelist),
-  // ]);
-  const ohots = { list: [] };
-  const ostyles = { list: [] };
-  styles.value = ostyles.list;
-  list.value = assembly(
-    styles.value,
-    ohots.list.map((item) => ({
-      ...item,
-      style: item.hotStyleAtom,
-      type: item.meta && item.meta.length ? item.type : "TEXT",
-    }))
-  );
-};
-
-export const saveHot = async (hot: HotAtom) => {
-  const data = {
-    ...hot,
-    poiStyleId: hot.style.id,
-    style: undefined,
-    id: undefined,
-  };
-  const res = await axios.post(URL.addHot, data);
-  hot.id = res.id;
-};
-
-export const updateHot = async (hot: HotAtom) => {
-  const data = {
-    ...hot,
-    poiStyleId: hot.style.id,
-    style: undefined,
-  };
-  await axios.post(URL.updateHot, data);
-};
-
-export const deleteHot = async (hot: HotAtom) => {
-  await axios.post(URL.deleteHot, { paths: { id: hot.id } });
-};
-
-export const addStyle = async (style: HotStyleAtom) => {
-  const res = await axios.post(URL.addStyle, style);
-  style.id = res.id;
-};
-
-export const deleteStyle = async (style: HotStyleAtom) => {
-  await axios.post(URL.deleteStyle, { paths: { id: style.id } });
-};
-
-export const storeSave = async () => {
-  const posts = [];
-
-  for (const style of styles.value) {
-    if (style.id === TemploraryID) {
-      posts.push(addStyle(style));
-    }
-  }
-  await Promise.all(posts);
-  posts.length = 0;
-
-  const backups = getBackups();
-  for (const item of list.value) {
-    if (item.id === TemploraryID) {
-      posts.push(saveHot(item));
-    } else if (
-      backups &&
-      inRevise(
-        item,
-        backups.list.find(({ id }) => id === item.id)
-      )
-    ) {
-      posts.push(updateHot(item));
-    }
-  }
-  const oldStore = getBackups();
-  for (const oldItem of oldStore.list) {
-    if (!list.value.some(({ id }) => id === oldItem.id)) {
-      posts.push(deleteHot(oldItem));
-    }
-  }
-  for (const oldItem of oldStore.styles) {
-    if (!styles.value.some(({ id }) => id === oldItem.id)) {
-      posts.push(deleteStyle(oldItem));
-    }
-  }
-  await Promise.all(posts);
-};
-
-export default store;

+ 1 - 17
src/store/index.ts

@@ -1,36 +1,20 @@
-import hot from "./hot";
 import measure from "./measure";
-import setup from "./setup";
-import setting from "./setting";
 import { DataSetAtom } from "@/sdk";
 import baseLine from "@/store/baseLine";
 export const store = {
-  hot,
   measure,
-  setup,
-  setting,
   baseLine
 };
 
 export * from "./sys";
 export * from "./constant";
+import "./sync"
 export type Store = typeof store;
 
 // -------------type--------------
 
 export type { MeasureAtom, MeasuresRaw, MeasureType } from "./measure";
-export type { Setup, Pose } from "./setup";
 
-export type { Shape, ColorMode, DensityType } from "./setting";
-export type {
-  HotType,
-  HotStyleAtom,
-  HotStylesRaw,
-  HotStyles,
-  HotAtom,
-  HotsRaw,
-  Hots,
-} from "./hot";
 
 import { formatDate } from "@/utils";
 export const unTemp: DataSetAtom = {

+ 2 - 80
src/store/measure.ts

@@ -1,8 +1,5 @@
-import { MeasuresRaw, MeasureUnit, MeasureAtom } from "@/sdk/types/measure";
-import { Ref, ref, reactive, UnwrapRef } from "vue";
-import { axios, URL } from "@/dbo";
-import { TemploraryID } from "./constant";
-import { inRevise } from "@/utils";
+import { MeasuresRaw, MeasureUnit } from "@/sdk/types/measure";
+import { Ref, ref, reactive } from "vue";
 import { useParams } from "@/hook/useParams";
 
 export type Measures = Ref<MeasuresRaw>;
@@ -19,79 +16,4 @@ export const store = reactive({
   show,
   unit,
 });
-
-let backupData: Omit<UnwrapRef<typeof store>, "show">;
-export const getBackups = () => backupData;
-export const backups = () => {
-  backupData = {
-    list: store.list.map((item) => ({
-      ...item,
-      points: item.points.map((point) => ({ ...point })),
-    })),
-    unit: store.unit,
-  };
-};
-export const recovery = () => {
-  if (backupData) {
-    store.list = backupData.list;
-    store.unit = backupData.unit;
-  }
-};
-
-export const requestData = async () => {
-  // const res = await axios.get(URL.measureList);
-  const res = { list: [] };
-  list.value = res.list.map((item) => {
-    return {
-      ...item,
-      show: true,
-      dataSet: null,
-    };
-  });
-};
-
-export const saveMeasure = async (measure: MeasureAtom) => {
-  const res = await axios.post(URL.addMeasure, {
-    ...measure,
-    dataSet: null,
-  });
-  measure.id = res.id;
-};
-
-export const updateMeasure = async (measure: MeasureAtom) => {
-  await axios.post(URL.updateMeasure, {
-    ...measure,
-    dataSet: measure.dataSet.id,
-  });
-};
-
-export const deleteMeasure = async (measure: MeasureAtom) => {
-  await axios.post(URL.deleteMeasure, { paths: { id: measure.id } });
-};
-
-export const storeSave = () => {
-  const posts = [];
-  const backups = getBackups();
-  for (const item of list.value) {
-    if (item.id === TemploraryID) {
-      posts.push(saveMeasure(item));
-    } else if (
-      backups &&
-      inRevise(
-        item,
-        backups.list.find(({ id }) => id === item.id)
-      )
-    ) {
-      posts.push(updateMeasure(item));
-    }
-  }
-  const oldStore = getBackups();
-  for (const oldItem of oldStore.list) {
-    if (!list.value.some(({ id }) => id === oldItem.id)) {
-      posts.push(deleteMeasure(oldItem));
-    }
-  }
-  return Promise.all(posts);
-};
-
 export default store;

+ 0 - 105
src/store/setting.ts

@@ -1,105 +0,0 @@
-import { DensityType, ColorMode, Shape } from '@/sdk/types'
-import { ref, reactive, watch } from 'vue'
-import { localGetFactory, localSetFactory } from '@/utils/store'
-import { disabledMap, customMap } from '@/hook'
-import { useParams } from '@/hook/useParams'
-
-export const initSenior = {
-  density: DensityType.middle,
-  colorMode: ColorMode.fullcolor,
-  shape: Shape.rectangle,
-  range: 150,
-  opacity: 1,
-  size: 0.1,
-  edgeStrong: false,
-  detail: 0.7
-} as const
-
-const storeKey = 'setting-' + useParams().m
-const local = {
-  get: localGetFactory((data): typeof store =>
-    data
-      ? JSON.parse(data)
-      : {
-          showMiniView: true,
-          showRoamPos: true,
-          ...initSenior
-        }
-  ),
-  set: localSetFactory((data: typeof store) => JSON.stringify(data))
-}
-
-export const density = ref<DensityType>()
-export const colorMode = ref<ColorMode>()
-export const shape = ref<Shape>()
-export const showMiniView = ref<boolean>()
-export const showRoamPos = ref<boolean>()
-export const range = ref<number>()
-export const opacity = ref<number>()
-export const size = ref<number>(0.5)
-export const detail = ref<number>(4)
-export const edgeStrong = ref<boolean>()
-
-export const store = reactive({
-  density,
-  colorMode,
-  shape,
-  showMiniView,
-  showRoamPos,
-  range,
-  opacity,
-  size,
-  edgeStrong,
-  detail
-})
-
-const def = local.get(storeKey)
-const preKeys = ['colorMode', 'density']
-for (const key of preKeys) {
-  store[key] = def[key]
-}
-setTimeout(() => {
-  watch(
-    showMiniView,
-    () => {
-      customMap.full = 'scene'
-      disabledMap.map = !showMiniView.value
-    },
-    { immediate: true, deep: true }
-  )
-
-  for (const key in def) {
-    if (!preKeys.includes(key)) {
-      store[key] = def[key]
-    }
-  }
-}, 100)
-
-watch(
-  store,
-  () => {
-    local.set(storeKey, store)
-  },
-  { deep: true }
-)
-
-// let stopWatch
-// watchEffect(() => {
-//     if (!useRoute()) return
-
-//     if (useRoute().name === routeName.value.query) {
-//         console.log('----')
-//         stopWatch = watch(store, () => {
-//             console.log('set')
-//             local.set(storeKey, store)
-//         }, { deep: true })
-//     } else if (stopWatch) {
-//         console.log('----stop')
-//         stopWatch()
-//         stopWatch = null
-//     }
-// })
-
-export default store
-
-export { DensityType, ColorMode, Shape }

+ 0 - 70
src/store/setup.ts

@@ -89,74 +89,4 @@ export const store: Setup = reactive({
   sceneVersion,
 });
 
-let backupData: UnwrapRef<typeof store>;
-export const getBackups = () => backupData;
-export const backups = () => {
-  backupData = {
-    ...store,
-    pose: (pose && { ...pose }) as unknown as Pose,
-  };
-};
-export const recovery = () => {
-  if (backupData) {
-    for (const key in backupData) {
-      store[key] = backupData[key];
-    }
-  }
-};
-
-export const requestData = async () => {
-  // const [infoRes, inis] = await Promise.all([
-  //   axios.get(URL.setupInfo),
-  //   axios.get(URL.inis),
-  // ]);
-  const infoRes = {
-    msg: "操作成功",
-    code: 200,
-    data: {
-      sceneCode: "SS-t-P1d6CwREny2",
-      title: "F01C室外测试",
-      password: "",
-      isOpen: true,
-      disableFloorPan: false,
-      status: 2,
-      showMode: 0,
-      datasetId: "-1",
-      jobStatus: 0,
-    },
-  };
-  const inis = { msg: "查询失败,无数据", code: 200 };
-  if (infoRes.code !== Code.SUSSESS) {
-    status.value = StatusEum.un;
-  } else {
-    const info = infoRes.data;
-    // id.value = info.id;
-    title.value = info.title;
-    // sceneVersion.value = info.sceneVersion;
-    // initPic.value = info.initPic;
-    password.value = info.password;
-    isOpen.value = info.isOpen;
-    disableFloorPan.value = info.disableFloorPan;
-    // pose.value = inis;
-    showMode.value = customMap.mode = info.showMode ? info.showMode : Mode.pano;
-    status.value = info.status;
-    // webSite.value = info.webSite;
-    datasetId.value = info.datasetId;
-  }
-};
-
-export const storeSave = async () => {
-  const posts: Array<Promise<any>> = [axios.post(URL.updateSetupInfo, store)];
-  if (store.pose) {
-    const post = store.pose.id
-      ? axios.post(URL.updateInis, { ...store.pose, id: store.pose.id })
-      : axios
-          .post(URL.addInis, store.pose)
-          .then((res) => (store.pose.id = res.id));
-    posts.push(post);
-  }
-
-  await Promise.all(posts);
-};
-
 export default store;

+ 38 - 0
src/store/sync.ts

@@ -0,0 +1,38 @@
+import axios from '@/dbo/main'
+import { list } from "@/store/measure";
+import {baseLines} from "@/store/baseLine";
+import {basePoints} from "@/store/basePoint";
+import {fixPoints} from "@/store/fixPoint";
+import {debounce} from '@/utils'
+import {watch} from "vue";
+
+axios.get("/attach/sceneStore")
+  .then((data) => {
+    if (data.status === 200) {
+      list.value = data.data.measures || []
+      baseLines.value = data.data.baseLines || []
+      basePoints.value = data.data.basePoints || []
+      fixPoints.value = data.data.fixPoints || []
+    }
+
+    syncSceneStore()
+  })
+
+export const updateSceneStore = debounce((data) => {
+  axios.post("sceneStore", data)
+})
+
+const syncSceneStore = () => {
+  return watch(
+    () => ({
+      measures: list.value,
+      baseLines: baseLines.value,
+      basePoints: basePoints.value,
+      fixPoints: fixPoints.value
+    }),
+    (data) => {
+      updateSceneStore(data)
+    },
+    { deep: true }
+  )
+}

+ 0 - 21
src/views/hotspot/constant.ts

@@ -1,21 +0,0 @@
-import { HotAtom, styles, HotStyleAtom } from '@/store/hot'
-import { TemploraryID } from '@/store/constant'
-import { reactive } from 'vue'
-import { PointInfo } from '@/sdk'
-import { selectStyle } from '@/components/edit-hot-item/constant'
-
-export const hotFactory = (pos: PointInfo): HotAtom => {
-    return {
-        id: TemploraryID,
-        title: '',
-        visualRange: [7, 20],
-        type: 'TEXT',
-        style: selectStyle.value,
-        pos: { ...pos.position },
-        datasetId: pos.datasetId,
-        dataset_location: pos.dataset_location,
-    }
-}
-
-export const hotFiles = reactive(new WeakMap<HotAtom, Array<File>>())
-export const styleFile = reactive(new WeakMap<HotStyleAtom, File>())

+ 0 - 31
src/views/hotspot/hot-item/index.vue

@@ -1,31 +0,0 @@
-<template>
-  <div
-    class="view-hot-item"
-    :class="{ active, err: !item.title.trim() }"
-    @click="emit('click')"
-  >
-    <img :src="getResources(item.style.icon)" />
-    <p>{{ item.title || $t("hotspot.edit.placeholder.title") }}</p>
-    <span v-if="$slots.icon" class="hot-icon">
-      <slot name="icon" />
-    </span>
-  </div>
-  <slot />
-</template>
-
-<script setup lang="ts">
-import { HotAtom } from "@/store";
-import { getResources } from "@/store/app";
-
-const props = defineProps<{
-  item: HotAtom;
-  active?: boolean;
-}>();
-const emit = defineEmits<{
-  (e: "click"): void;
-}>();
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 53
src/views/hotspot/hot-item/style.scss

@@ -1,53 +0,0 @@
-.view-hot-item {
-  display: flex;
-  align-items: center;
-  padding: 10px 0;
-  position: relative;
-  cursor: pointer;
-
-  &::after {
-    content: '';
-    position: absolute;
-    pointer-events: none;
-    top: 0;
-    bottom: 0;
-    left: -20px;
-    right: -20px;
-    background-color: rgba(var(--colors-primary-base-fill), 0);
-    transition: background-color 0.3s ease;
-  }
-
-  &.active::after {
-    background-color: rgba(var(--colors-primary-base-fill), 0.16);
-  }
-  &.err p {
-    color: #fa3f48;
-  }
-
-  img {
-    flex: none;
-    width: 24px;
-    height: 24px;
-  }
-
-  .hot-icon {
-    flex: none;
-    cursor: pointer;
-  }
-
-  p {
-    flex: 1;
-    margin: 0 10px;
-  }
-}
-
-.edit-hot {
-  margin-top: 20;
-  text-align: right;
-
-  span {
-    font-size: 14px;
-    color: rgba(255, 255, 255, 0.7);
-    cursor: pointer;
-  }
-}

+ 0 - 184
src/views/hotspot/index.vue

@@ -1,184 +0,0 @@
-<template>
-  <ui-editor-toolbox v-model:toolbox="showToolbox" class="hot-layer" disabledAnimation>
-    <ui-gate :index="0" height="100%" class="clear-float view-scroll">
-      <ui-gate-content class="view-content">
-        <ViewHots
-          :hots="list"
-          :showHot="show"
-          :showHotManage="isEdit"
-          :selectHot="currentHot"
-          @selectHot="(hot) => (currentHot = currentHot === hot ? null : hot)"
-          @updateShowHot="(newShow) => (show = newShow)"
-          @deleleHot="deleleHot"
-        />
-      </ui-gate-content>
-    </ui-gate>
-  </ui-editor-toolbox>
-
-  <Control :show="isEdit" />
-</template>
-
-<script lang="ts" setup>
-import ViewHots from "./view-hots/index.vue";
-import Control from "@/components/magnifier-control/index.vue";
-import EditHot from "@/components/edit-hot-item/index.vue";
-import { list, show, listStore, backups, recovery, storeSave, styles } from "@/store/hot";
-import { hotFactory, hotFiles, styleFile } from "./constant";
-import { axios, URL } from "@/dbo";
-import { router, writeRouteName } from "@/router";
-import { ref, watch, nextTick, computed } from "vue";
-import { showToolbox, HotAtom, isEdit, TemploraryID } from "@/store";
-import {
-  useDesaveAssist,
-  useEdit,
-  useSDK,
-  useViewStack,
-  useAlert,
-  customMap,
-  RightMenuEum,
-  customMouseMenuStack,
-  useCanFly,
-} from "@/hook";
-import { PointInfo } from "@/sdk";
-import { ui18n } from "@/lang";
-
-// 是否是可视设置
-const laser = useSDK();
-
-// 进入编辑模式
-const currentHot = computed({
-  get: () => useSDK().carry.store.share.showHot,
-  set: (val) => {
-    // val && laser.scene.comeToHot(val)
-    useSDK().carry.store.share.showHot = val;
-  },
-});
-const enterEditHot = (hot: HotAtom) => useEdit([currentHot, hot, null]);
-
-useDesaveAssist(listStore, {
-  auto: true,
-  save: async () => {
-    for (const hot of list.value) {
-      if (hot.title.trim().length === 0) {
-        enterEditHot(hot);
-        useAlert(ui18n.t("hotspot.edit.unTitle"));
-        throw "存在热点未填写标题";
-      }
-    }
-    const uploads: Array<Promise<any>> = [];
-    for (const hot of list.value) {
-      if (hotFiles.has(hot)) {
-        const files = hotFiles.get(hot);
-        hotFiles.delete(hot);
-        const uploadMetas = Promise.all(
-          files.map((file) =>
-            axios.post(URL.uploadFile, file, { paths: { type: "poi" } })
-          )
-        ).then((urls) => {
-          const index = hot.meta.length - urls.length;
-          for (let i = 0; i < urls.length; i++) {
-            hot.meta[index + i].url = urls[i];
-          }
-        });
-        uploads.push(uploadMetas);
-      }
-    }
-    for (const style of styles.value) {
-      if (styleFile.has(style)) {
-        const file = styleFile.get(style);
-        const uploadIcon = axios
-          .post(URL.uploadFile, file, { paths: { type: "poi-style" } })
-          .then((url) => (style.icon = url));
-        uploads.push(uploadIcon);
-        styleFile.delete(style);
-      }
-    }
-
-    await Promise.all(uploads);
-    await storeSave();
-  },
-  backup: backups,
-  recovery,
-});
-
-const deleleHot = async (delHot: HotAtom) => {
-  const index = list.value.indexOf(delHot);
-  if (~index) {
-    list.value.splice(index, 1);
-  }
-};
-
-useViewStack(() => {
-  const stopWatch = watch(
-    router.currentRoute,
-    () => {
-      const route = router.currentRoute.value;
-      console.log(route);
-      const params = route.params;
-      if (params && params.id && params.edit && route.name === writeRouteName.hotspot) {
-        if (params.id !== TemploraryID.toString()) {
-          const atom = list.value.find(({ id }) => id === params.id);
-          atom && enterEditHot(atom);
-        } else if (params.pos) {
-          try {
-            const pos = JSON.parse(params.pos as string) as PointInfo;
-            if (useCanFly(pos.position, ui18n.t("hotspot.flyErr"))) {
-              const item = hotFactory(pos);
-              enterEditHot(item);
-              nextTick(() => {
-                list.value.splice(0, 0, item);
-              });
-            }
-          } catch (e) {
-            console.error(e);
-          }
-        }
-      }
-    },
-    { immediate: true }
-  );
-
-  // 热点编辑模块保留添加热点菜单
-  let inSet = false;
-  const stopWatchEdit = watch(
-    [isEdit],
-    () => {
-      const addHotMenu = customMap.rMouseMenu.find(
-        (menu) => menu.key === RightMenuEum.AddHot
-      );
-      if (isEdit.value && !inSet) {
-        addHotMenu && customMouseMenuStack.push(ref([addHotMenu]));
-        laser.carry.hotTheme.push({
-          component: EditHot,
-          props: {
-            quit: () => {
-              currentHot.value = null;
-            },
-            hotFiles,
-            styleFile,
-          },
-        });
-        inSet = true;
-      } else if (!isEdit.value && inSet) {
-        customMouseMenuStack.pop();
-        laser.carry.hotTheme.pop();
-        inSet = false;
-      }
-    },
-    { immediate: true }
-  );
-  // const menus = residenMouseMenuStack.current.value.value.filter(atom => atom.key !== RightMenuEum.NavEnd && atom.key !== RightMenuEum.NavStart)
-  // residenMouseMenuStack.push(ref(menus))
-
-  return () => {
-    currentHot.value = null;
-    stopWatch();
-    stopWatchEdit();
-    // residenMouseMenuStack.pop()
-  };
-});
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 11
src/views/hotspot/style.scss

@@ -1,11 +0,0 @@
-.view-scroll {
-  margin-left: -20px;
-  margin-right: -20px;
-  width: calc(100% + 40px);
-  height: 100%;
-
-  .view-content {
-    padding: 0 20px;
-    overflow-y: auto;
-  }
-}

+ 0 - 65
src/views/hotspot/view-hots/index.vue

@@ -1,65 +0,0 @@
-<template>
-  <div class="hot-view-all">
-    <div class="common">
-      <ui-group
-        :title="$t('hotspot.show')"
-        borderBottom
-        v-if="!showHotManage"
-        :class="{ disabled: hots.length === 0 }"
-      >
-        <template v-slot:icon>
-          <ui-input
-            type="switch"
-            :modelValue="showHot"
-            @update:modelValue="(val) => emit('updateShowHot', val)"
-          />
-        </template>
-      </ui-group>
-
-      <ui-group>
-        <template v-slot:header>
-          <h3 class="inserted">
-            {{ $t("hotspot.added") }}(
-            <span class="hot-count">{{ hots.length }}</span> )
-          </h3>
-        </template>
-
-        <Info v-if="!showHotManage && isLogin" :msg="$t('hotspot.addTip')" />
-
-        <hot-item
-          :item="hot"
-          v-for="hot in hots"
-          :active="hot === selectHot"
-          @click="emit('selectHot', hot)"
-        >
-          <template v-slot:icon v-if="isEdit">
-            <ui-icon type="del" @click.stop="emit('deleleHot', hot)" ctrl />
-          </template>
-        </hot-item>
-      </ui-group>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { HotAtom, HotsRaw, isEdit, isLogin } from "@/store";
-import HotItem from "../hot-item/index.vue";
-import Info from "@/components/info/index.vue";
-
-const props = defineProps<{
-  showHot: boolean;
-  hots: HotsRaw;
-  selectHot?: HotAtom;
-  showHotManage: boolean;
-}>();
-
-const emit = defineEmits<{
-  (e: "updateShowHot", v: boolean): void;
-  (e: "deleleHot", data: HotAtom): void;
-  (e: "selectHot", data: HotAtom): void;
-}>();
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 43
src/views/hotspot/view-hots/style.scss

@@ -1,43 +0,0 @@
-.hot-view-all {
-  display: flex;
-  flex-direction: column;
-  height: 100%;
-
-  .common {
-    flex: 1;
-  }
-
-  .visible {
-    flex: none;
-  }
-
-  .visible-setting {
-    flex: none;
-  }
-
-  .hot-count {
-    color: var(--color-main-normal);
-  }
-
-  .inserted {
-    font-size: 16px;
-  }
-
-  .info {
-    display: flex;
-    align-items: center;
-    background: rgba(255, 255, 255, 0.1);
-    border-radius: 4px;
-    height: 34px;
-    padding: 0 10px;
-    color: #fff;
-    font-size: 12px;
-    margin-bottom: 10px;
-
-    .icon {
-      font-size: 18px;
-      margin-right: 6px;
-      color: #f59a41;
-    }
-  }
-}

+ 0 - 169
src/views/measure/constant.ts

@@ -1,169 +0,0 @@
-import { DataSetAtom } from "@/sdk";
-import { MeasuresRaw, MeasureType } from "@/store";
-import { MeasureAtom, MeasureUnit, unit } from "@/store/measure";
-import { Group, Ctrl } from "@/components/control-panl";
-import { Measure, StartMeasure } from "@/sdk";
-import { round } from "@/utils/index";
-import { reactive } from "vue";
-import { ui18n } from "@/lang";
-
-export { MeasureUnit } from "@/store/measure";
-
-type Desc = { [key in MeasureUnit]: string };
-export const unitDesc: Desc = {
-  [MeasureUnit.meter]: ui18n.t("measure.unit.meter"),
-  [MeasureUnit.inch]: ui18n.t("measure.unit.inch"),
-};
-
-type Options = Array<{ value: MeasureUnit; label: Desc[MeasureUnit] }>;
-export const unitOptions: Options = [
-  { value: MeasureUnit.meter, label: unitDesc[MeasureUnit.meter] },
-  { value: MeasureUnit.inch, label: unitDesc[MeasureUnit.inch] },
-];
-
-export type SetMeasureAtom = Omit<DataSetAtom, "children"> & {
-  children: MeasuresRaw;
-};
-export type SetMeasures = Array<SetMeasureAtom>;
-
-export type Types = MeasureType;
-export const infos = {
-  LINE: { name: ui18n.t("measure.len"), icon: "f-l" } as const,
-  SERIES: { name: ui18n.t("measure.len"), icon: "icon_f_z_n" } as const,
-  AREA: { name: ui18n.t("measure.area"), icon: "f-m" } as const,
-  L_LINE: { name: ui18n.t("measure.len"), icon: "h-l" } as const,
-  L_SERIES: { name: ui18n.t("measure.len"), icon: "icon_h_z_n" } as const,
-  L_AREA: { name: ui18n.t("measure.area"), icon: "h-r" } as const,
-  L_RECTANGLE: { name: ui18n.t("measure.area"), icon: "h-m" } as const,
-  V_LINE: { name: ui18n.t("measure.len"), icon: "v-l" } as const,
-  V_SERIES: { name: ui18n.t("measure.len"), icon: "icon_v_z_n" } as const,
-  V_AREA: { name: ui18n.t("measure.area"), icon: "v-m" } as const,
-  V_RECTANGLE: { name: ui18n.t("measure.area"), icon: "v-r" } as const,
-} as const;
-type InfoType = typeof infos[Types]["name"];
-
-export type CtrlType = Types | "magnifier" | "viewMode";
-export type CtrlAtom = Ctrl & { value: CtrlType; key?: string; guide?: string };
-
-export const ctrolGroup = reactive([
-  {
-    ctrls: [
-      {
-        icon: "magnify",
-        value: "magnifier",
-        makeup: true,
-        desc: ui18n.t("tool.magnify"),
-      },
-    ],
-  },
-  {
-    apart: true,
-    label: ui18n.t("tool.free"),
-    ctrls: [
-      {
-        icon: infos["LINE"].icon,
-        value: "LINE",
-        desc: infos["LINE"].name,
-      },
-      {
-        icon: infos["SERIES"].icon,
-        value: "SERIES",
-        desc: ui18n.t("tool.series"),
-      },
-      { icon: infos["AREA"].icon, value: "AREA", desc: ui18n.t("tool.area") },
-    ],
-  },
-  {
-    label: ui18n.t("tool.lfree"),
-    ctrls: [
-      {
-        icon: infos["L_LINE"].icon,
-        value: "L_LINE",
-        desc: infos["L_LINE"].name,
-      },
-      {
-        icon: infos["L_SERIES"].icon,
-        value: "L_SERIES",
-        desc: ui18n.t("tool.series"),
-      },
-      {
-        icon: infos["L_AREA"].icon,
-        value: "L_RECTANGLE",
-        desc: ui18n.t("tool.rect"),
-      },
-      {
-        icon: infos["L_RECTANGLE"].icon,
-        value: "L_AREA",
-        desc: ui18n.t("tool.area"),
-      },
-    ],
-  },
-  {
-    label: ui18n.t("tool.vfree"),
-    ctrls: [
-      {
-        icon: infos["V_LINE"].icon,
-        value: "V_LINE",
-        desc: infos["V_LINE"].name,
-      },
-      {
-        icon: infos["V_SERIES"].icon,
-        value: "V_SERIES",
-        desc: ui18n.t("tool.series"),
-      },
-      {
-        icon: infos["V_RECTANGLE"].icon,
-        value: "V_RECTANGLE",
-        desc: ui18n.t("tool.rect"),
-      },
-      {
-        icon: infos["V_AREA"].icon,
-        value: "V_AREA",
-        desc: ui18n.t("tool.area"),
-      },
-    ],
-  },
-  {
-    ctrls: [
-      {
-        icon: "a-2d",
-        value: "viewMode",
-        makeup: true,
-      },
-    ],
-    apart: true,
-  },
-]) as Group<CtrlAtom>;
-
-export type CanvasMeasures = Array<CanvasMeasureAtom>;
-export type CanvasMeasureAtom = { raw: MeasureAtom; canvas: Measure };
-export type TempCanvasMeasureAtom = Omit<CanvasMeasureAtom, "canvas"> & {
-  canvas: StartMeasure;
-};
-
-export type MeasureLocal = [DataSetAtom, MeasureAtom];
-export type MeasureShareAtom = {
-  measure: CanvasMeasureAtom;
-  local: MeasureLocal;
-};
-export type ShareMeasures = Array<MeasureShareAtom>;
-
-export const getUnit = (item: CanvasMeasureAtom) => {
-  const key = unit.value === MeasureUnit.meter ? "value" : "string";
-  const type = infos[item.raw.type].name;
-  const origin =
-    type === ui18n.t("measure.len")
-      ? item.canvas.getDistance()
-      : item.canvas.getArea();
-  if (origin) {
-    const val =
-      key === "value"
-        ? type === ui18n.t("measure.len")
-          ? `${round(origin[key], 2)} m`
-          : `${round(origin[key], 2)} m²`
-        : origin[key];
-    return val;
-  } else {
-    return "0";
-  }
-};

+ 0 - 238
src/views/measure/control.vue

@@ -1,238 +0,0 @@
-<template>
-  <ContrlPanl
-    class="measure-control"
-    v-model="runs"
-    :group="ctrolGroup"
-    :show="show"
-    :full="true"
-    :count="count"
-  />
-</template>
-
-<script setup lang="ts">
-import ContrlPanl from "@/components/control-panl/index.vue";
-import { ctrolGroup, CtrlAtom, Types, TempCanvasMeasureAtom, infos } from "./constant";
-import { watch, shallowRef, ref, computed } from "vue";
-import { TemploraryID } from "@/store";
-import { MeasureUnit, Mode } from "@/sdk/index";
-import { store, MeasureAtom } from "@/store";
-import { inRevise, asyncTimeout } from "@/utils";
-import { hotDisabledStack, useSDK, customMap, laserModeStack } from "@/hook";
-import {
-  spiltViewModeStack,
-  magnifierModeStack,
-  mapDisabledStack,
-  fullViewStack,
-} from "@/hook";
-import { unTemp } from "@/store";
-import { Message } from "@kankan/components/index";
-import { ui18n } from "@/lang";
-
-const laser = useSDK();
-const runs = shallowRef<Array<CtrlAtom>>([]);
-const props = defineProps<{
-  show: boolean;
-  unit: MeasureUnit;
-  count: number;
-}>();
-
-const emit = defineEmits<{
-  (e: "addMeasure", data: MeasureAtom): void;
-  (e: "startMeasure"): void;
-  (e: "endMeasure"): void;
-}>();
-
-const tempMeasure: { [key in Types]?: TempCanvasMeasureAtom } = {};
-const currentMeasure = shallowRef<TempCanvasMeasureAtom>(null);
-
-const endMeasure = () => {
-  const type = Object.keys(tempMeasure).find(
-    (key) => tempMeasure[key] === currentMeasure.value
-  );
-  emit("endMeasure");
-
-  if (currentMeasure.value) {
-    currentMeasure.value.canvas.clear();
-    currentMeasure.value.canvas.bus.off("end", endHandler);
-    currentMeasure.value.canvas.bus.off("quit", quitHandler);
-    currentMeasure.value = null;
-  }
-  delete tempMeasure[type];
-};
-
-const quitMeasure = () => {
-  if (currentMeasure.value) {
-    currentMeasure.value.canvas.quit();
-  }
-  endMeasure();
-};
-
-const repeat = () => {
-  const newRuns = runs.value.filter((item) => item.makeup);
-  if (inRevise(runs.value, newRuns)) {
-    ctrlsHandler(runs.value, newRuns);
-  }
-};
-
-let isShowTip = false;
-const endHandler = () => {
-  currentMeasure.value.raw.points = currentMeasure.value.canvas.getPoints();
-  currentMeasure.value.raw.dataset_points = currentMeasure.value.canvas.getDatasetLocations();
-  currentMeasure.value.raw.datasetIds = currentMeasure.value.canvas.getDatasets();
-  currentMeasure.value.raw.dataSet = unTemp;
-
-  emit("addMeasure", currentMeasure.value.raw);
-  endMeasure();
-  repeat();
-
-  if (!isShowTip) {
-    isShowTip = true;
-    const atom = runs.value.find(({ icon }) =>
-      Object.values(infos).some((info) => info.icon === icon)
-    );
-    if (atom) {
-      atom.key = "measure-line";
-      atom.guide = ui18n.t("measure.toolTip");
-    }
-  }
-};
-const quitHandler = () => {
-  quitMeasure();
-  repeat();
-};
-
-const ctrlsHandler = async (ctrls: Array<CtrlAtom>, oldCtrls: Array<CtrlAtom>) => {
-  if (oldCtrls) {
-    const delCtrls = oldCtrls.filter((item) => !ctrls.includes(item));
-
-    for (const { value: type } of delCtrls) {
-      switch (type) {
-        case "magnifier":
-          hotDisabledStack.pop();
-          magnifierModeStack.pop();
-          break;
-        case "viewMode":
-          spiltViewModeStack.pop();
-          break;
-        default:
-          quitMeasure();
-      }
-    }
-  }
-
-  const addCtrls = oldCtrls ? ctrls.filter((item) => !oldCtrls.includes(item)) : ctrls;
-
-  for (const { value: type } of addCtrls) {
-    switch (type) {
-      case "magnifier":
-        hotDisabledStack.push(ref(true));
-        magnifierModeStack.push(ref(true));
-        break;
-      case "viewMode":
-        spiltViewModeStack.push(ref(0.5));
-        break;
-      default:
-        await asyncTimeout(1);
-        const measure = laser.scene.startMeasure(type, props.unit);
-        const raw = {
-          id: TemploraryID,
-          dataSet: unTemp,
-          type: type,
-          points: [],
-          show: true,
-          dataset_points: null,
-          datasetIds: null,
-        };
-        emit("startMeasure");
-        currentMeasure.value = tempMeasure[type] = {
-          raw: raw,
-          canvas: measure,
-        };
-        tempMeasure[type].canvas.bus.on("quit", quitHandler);
-        tempMeasure[type].canvas.bus.on("end", endHandler);
-        tempMeasure[type].canvas.bus.on(
-          "invalidPoint",
-          (msg = ui18n.t("measure.invalidPoint")) => {
-            Message.warning(msg);
-          }
-        );
-        setTimeout(() => {
-          console.log("???", runs.value);
-          if (!runs.value.some((item) => item.value === "magnifier")) {
-            runs.value = [ctrolGroup[0].ctrls[0], ...runs.value];
-          }
-        }, 500);
-    }
-  }
-};
-
-watch(runs, ctrlsHandler, { immediate: true });
-
-const exportObject = {
-  stopMeasure() {
-    if (currentMeasure.value) {
-      currentMeasure.value.canvas.end();
-      setTimeout(() => {
-        quitMeasure();
-        runs.value = runs.value.filter(
-          (atom) => atom.makeup && atom.value !== "magnifier"
-        );
-      }, 100);
-    }
-  },
-  measureIng: computed(() => runs.value.some((atom) => !atom.makeup)),
-};
-
-const keyupHandler = (ev) => {
-  if (ev.code === `Escape`) {
-    quitMeasure();
-    runs.value = runs.value.filter((atom) => atom.makeup);
-  }
-};
-
-let inSet = false;
-watch(
-  () => props.show,
-  () => {
-    if (props.show) {
-      runs.value = [ctrolGroup[0].ctrls[0], ctrolGroup[1].ctrls[0]];
-      if (customMap.full === "map") {
-        runs.value.push(ctrolGroup[4].ctrls[0]);
-      }
-
-      document.documentElement.addEventListener("keydown", keyupHandler);
-
-      if (!inSet) {
-        fullViewStack.push(ref("scene"));
-        mapDisabledStack.push(ref(true));
-        laserModeStack.push(ref(Mode.cloud));
-        inSet = true;
-      }
-    } else {
-      runs.value = [];
-      document.documentElement.removeEventListener("keydown", keyupHandler);
-      laser.scene.quitMeasure();
-
-      if (inSet) {
-        mapDisabledStack.pop();
-        fullViewStack.pop();
-        laserModeStack.pop();
-        inSet = false;
-      }
-
-      ctrolGroup.forEach((atom) => {
-        atom.ctrls.forEach((atom) => {
-          delete atom.key;
-          delete atom.guide;
-        });
-      });
-    }
-  }
-);
-
-defineExpose(exportObject);
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 214
src/views/measure/index.vue

@@ -1,214 +0,0 @@
-<template>
-  <ui-editor-toolbox
-    v-model:toolbox="showToolbox"
-    disabledAnimation
-    class="measure"
-  >
-    <div class="btns header-btns">
-      <ui-button
-        class="start-measure"
-        :disabled="measureMode && !ctrlRef.measureIng"
-        :type="!measureMode ? 'primary' : void 0"
-        @click="clickAction"
-        >{{ measureMode ? $t('measure.stop') : $t('measure.start') }}</ui-button
-      >
-      <ui-input
-        v-if="!measureMode"
-        class="unit"
-        type="select"
-        :placeholder="$t('sys.selectPic')"
-        :options="unitOptions"
-        width="120px"
-        v-model="unit"
-      />
-    </div>
-
-    <TreeManage
-      v-if="measures && measures.length"
-      :list="measures"
-      @change-show="
-        (list, show) => execItem(list, ({ raw }) => (raw.show = show))
-      "
-      @delete="deleteList"
-      @update-title="(item, val) => (item.raw.title = val)"
-      @share="data => (shareList = data)"
-    />
-  </ui-editor-toolbox>
-
-  <Control
-    :ref="ctrl => (ctrlRef = ctrl)"
-    :show="measureMode"
-    :unit="unit"
-    @add-measure="addMeasureHandler"
-    @start-measure="measureIng = true"
-    @end-measure="measureIng = false"
-    :count="measures.length"
-  />
-  <Share
-    v-if="shareList.length"
-    :list="shareList"
-    :measures="measures"
-    @close="shareList = []"
-  />
-</template>
-
-<script lang="ts" setup>
-import TreeManage from './tree-manage.vue'
-import Control from './control.vue'
-import Share from './share/index.vue'
-import { ref, computed, watchEffect, watch, nextTick } from 'vue'
-import {
-  list,
-  unit,
-  backups,
-  recovery,
-  storeSave,
-  getBackups
-} from '@/store/measure'
-import {
-  unitOptions,
-  CanvasMeasures,
-  CanvasMeasureAtom,
-  ShareMeasures
-} from './constant'
-import { inRevise } from '@/utils'
-import { isLogin, showToolbox } from '@/store'
-import {
-  editBus,
-  useDesaveAssist,
-  useEdit,
-  useSDK,
-  useEmitLeave,
-  useParams,
-  useViewStack,
-  customMap,
-  toolDisabled,
-  searchDisabledStack,
-  useFlyMeasure
-} from '@/hook'
-import { Mode, Pose } from '@/sdk/types/sdk'
-import { os } from '@/utils'
-
-const laser = useSDK()
-const measureIng = ref<boolean>(false)
-const shareList = ref<ShareMeasures>([])
-const ctrlRef = ref<any>()
-const measures = computed(() => {
-  const map = laser.carry.measureMap
-  const measures: CanvasMeasures = []
-
-  for (const item of list.value) {
-    if (!map.has(item)) {
-      continue
-    }
-    measures.push({
-      raw: item,
-      canvas: map.get(item)
-    })
-  }
-  return measures
-})
-
-const saveStatus = useDesaveAssist(list, {
-  auto: true,
-  save: storeSave,
-  intercept: () =>
-    isLogin.value &&
-    inRevise(
-      getBackups().list,
-      list.value.map(item => ({ ...item, show: true }))
-    ),
-  backup: backups,
-  recovery
-})
-
-const addMeasureHandler = data => {
-  list.value.splice(0, 0, data)
-}
-
-const menusDisabled = ref(false)
-const measureMode = ref(false)
-
-watch(measureMode, () => {
-  if (measureMode.value) {
-    const handler = () => (measureMode.value = false)
-    useEdit()
-    editBus.on('leave', handler, { last: true })
-    editBus.on('save', handler, { last: true })
-    menusDisabled.value = true
-    if (!os.isPc) {
-      toolDisabled.push(ref(true))
-      searchDisabledStack.push(ref(true))
-    }
-  } else {
-    if (!saveStatus.desave.value) {
-      useEmitLeave()
-    }
-    menusDisabled.value = false
-    if (!os.isPc) {
-      toolDisabled.pop()
-      searchDisabledStack.pop()
-    }
-  }
-})
-
-const clickAction = () => {
-  if (!measureMode.value) {
-    measureMode.value = true
-  } else {
-    ctrlRef.value.stopMeasure()
-  }
-}
-
-const execItem = (
-  list: CanvasMeasures,
-  fn: (item: CanvasMeasureAtom) => void
-) => {
-  list.forEach(fn)
-}
-
-const deleteList = (delList: CanvasMeasures) => {
-  execItem(delList, item => {
-    const listIndex = list.value.indexOf(item.raw)
-    ~listIndex && list.value.splice(listIndex, 1)
-  })
-}
-
-const params = useParams()
-if (params.flymid) {
-  customMap.mode = Mode.cloud
-  const stopWatch = watchEffect(() => {
-    if (laser && params.flymid) {
-      const item = laser.store.measure.list.find(
-        ({ id }) => id === params.flymid
-      )
-      if (item && laser.carry.measureMap.has(item)) {
-        setTimeout(() => {
-          try {
-            if (params.pose) {
-              const position: Pose = JSON.parse(decodeURI(params.pose));
-              laser.scene.setPose(position);
-            } else {
-              throw new Error("无效pose")
-            }
-          } catch (e) {
-            useFlyMeasure(item.points, laser.carry.measureMap.get(item))
-          }
-        }, 1000)
-        nextTick(stopWatch)
-      }
-    }
-  })
-}
-
-useViewStack(() => {
-  laser.enterMeasurement()
-  return () => {
-    laser.leaveMeasurement()
-  }
-})
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 11
src/views/measure/share/constant.ts

@@ -1,11 +0,0 @@
-import { MeasureAtom } from '@/store'
-
-export type ShareAtom = {
-    title: string
-    desc: MeasureAtom['title']
-    dis: string
-    disName: string
-    img: string
-    link: string
-}
-export type ShareList = Array<ShareAtom>

+ 0 - 122
src/views/measure/share/index.vue

@@ -1,122 +0,0 @@
-<template>
-  <ui-dialog v-if="list.length">
-    <template v-slot:header>
-      {{ $t("measure.export") }}
-      <ui-icon type="close" ctrl @click="emit('close')" />
-    </template>
-    <div>
-      <div class="share-content" :class="{ pc: os.isPc }">
-        <ShareItem :data="item" v-for="item in shareList" />
-        <PdfTemp :list="shareList" ref="pdfvm" v-if="showDownPdf" />
-      </div>
-    </div>
-    <template v-slot:footer>
-      <ui-button type="submit" @click="emit('close')">{{ $t("sys.cancel") }}</ui-button>
-      <ui-button type="primary" @click="downPDF()" v-if="!os.isWX">
-        {{ $t("measure.exportPDF") }}
-      </ui-button>
-    </template>
-  </ui-dialog>
-</template>
-
-<script lang="ts" setup>
-import ShareItem from "./item.vue";
-import PdfTemp from "./pdf.vue";
-import { ref, watchEffect, nextTick, onMounted } from "vue";
-import { ShareMeasures, infos, getUnit, CanvasMeasures } from "../constant";
-import { asyncTimeout } from "@/utils";
-import { Loading } from "@kankan/components/index";
-import { ShareList } from "./constant";
-import { paramsToStr, saveAs } from "@/utils";
-import { TemploraryID } from "@/store";
-import { unit } from "@/store/measure";
-import { useParams, laserLoadingDisabled, Params, useSDK } from "@/hook";
-import { os } from "@/utils";
-import { Message } from "@kankan/components/index";
-import { ui18n, lang } from "@/lang";
-
-const props = defineProps<{
-  list: ShareMeasures;
-  measures: CanvasMeasures;
-}>();
-const emit = defineEmits<{
-  (e: "close"): void;
-}>();
-
-const laser = useSDK();
-const shareList = ref<ShareList>([]);
-os.isWX &&
-  onMounted(() => {
-    Message.warning(ui18n.t("measure.wxError"));
-  });
-
-watchEffect(async () => {
-  await asyncTimeout();
-  laserLoadingDisabled.push(ref(false));
-  Loading.show({}, Math.random());
-
-  const params = useParams();
-  const shares: ShareList = [];
-
-  for (const { local, measure } of props.list) {
-    const { dataUrl: img, pose } = await measure.canvas.toDataURL(1000, 500);
-    // const [img, pose] = await Promise.all([getImagePromise, laser.scene.getPose()])
-    // const img = await getImagePromise;
-    // const pose = await laser.scene.getPose()
-    console.log(img, pose);
-    const disName = infos[measure.raw.type].name;
-    const include: Array<keyof Params> = ["m", "flymid", "unit", "lang", "pose"];
-    const args = {
-      ...params,
-      pose: encodeURI(JSON.stringify(pose)),
-      lang: lang,
-      unit: unit.value.toString(),
-      flymid: measure.raw.id,
-    };
-    for (const [key] of Object.entries(args)) {
-      if (!include.includes(key as keyof Params)) {
-        delete args[key];
-      }
-    }
-
-    const link =
-      measure.raw.id !== TemploraryID
-        ? location.origin + location.pathname + paramsToStr(args) + location.hash
-        : null;
-
-    console.log(args, link, lang);
-    shares.push({
-      title: local[0].title,
-      desc: measure.raw.title,
-      dis: `${getUnit(measure)}`,
-      disName,
-      img: img,
-      link: link,
-    });
-  }
-
-  shareList.value = shares;
-
-  nextTick(() => {
-    laserLoadingDisabled.pop();
-    Loading.hideAll();
-  });
-});
-
-const pdfvm = ref(null);
-const showDownPdf = ref(false);
-const downPDF = async () => {
-  showDownPdf.value = true;
-  Loading.show();
-  await asyncTimeout(100);
-  const pdf = await pdfvm.value.downPDF();
-  Loading.hide();
-  showDownPdf.value = false;
-  saveAs(pdf.output("blob"), `${ui18n.t("measure.downloadName")}.pdf`);
-  Message.success(ui18n.t("sys.downloadSuccess"));
-};
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 41
src/views/measure/share/item.vue

@@ -1,41 +0,0 @@
-<template>
-  <div class="share-item">
-    <div class="share-info">
-      <div class="main-info">
-        <p class="name">{{ data.disName }}</p>
-        <p class="dis">{{ data.dis }}</p>
-      </div>
-      <p class="title">{{ data.title || "-" }}</p>
-      <p class="link" v-if="data.link">
-        <a :href="data.link" :class="{ isPdf }" target="_blank">{{ data.link }}</a>
-        <ui-icon type="copy" class="icon" @click="copyLink" ctrl v-if="!isPdf" />
-      </p>
-      <p v-else class="link">{{ $t("measure.unSave") }}</p>
-      <p class="desc" :title="data.desc">{{ data.desc || "-" }}</p>
-    </div>
-    <div class="img">
-      <img :src="data.img" />
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import { ShareAtom } from "./constant";
-import { copyText } from "@/utils";
-import { Message } from "@kankan/components/index";
-import { ui18n } from "@/lang";
-
-const props = defineProps<{
-  data: ShareAtom;
-  isPdf?: boolean;
-}>();
-
-const copyLink = () => {
-  copyText(props.data.link);
-  Message.success(ui18n.t("measure.copy"));
-};
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 126
src/views/measure/share/pdf.vue

@@ -1,126 +0,0 @@
-<template>
-  <div class="pdf-temp" :class="{ pc: os.isPc && !os.isTablet }">
-    <div v-for="(group, i) in groups" :ref="(vm) => (vms[i] = vm)">
-      <div class="header">
-        <h1>{{ $t("measure.downloadName") }}</h1>
-        <img :src="logo[lang]" alt="" />
-      </div>
-      <ShareItem :data="item" v-for="item in group" is-pdf />
-      <div class="footer">
-        <p>{{ date }}</p>
-        <span>
-          {{ $t("measure.pageMark", { index: i + 1, length: groups.length }) }}
-        </span>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import { ref, computed } from "vue";
-import { ShareList } from "./constant";
-import ShareItem from "./item.vue";
-import { formatDate } from "@/utils";
-import { jsPDF } from "jspdf";
-import html2canvas from "html2canvas";
-import { lang, langNameEum } from "@/lang";
-import { os } from "@/utils";
-
-const logo = {
-  [langNameEum.zh]: new URL("@/assets/images/logo_4dage_cn.png", import.meta.url).href,
-};
-
-const date = formatDate(new Date(), "yyyy-MM-dd hh:mm:ss");
-const props = defineProps<{ list: ShareList }>();
-const groups = computed(() => {
-  const groups: Array<ShareList> = [];
-
-  for (let i = 0; i < props.list.length; i++) {
-    const group = [props.list[i]];
-    if (i + 1 < props.list.length) {
-      group.push(props.list[++i]);
-    }
-    groups.push(group);
-  }
-  return groups;
-});
-const vms = ref([]);
-
-const SCALE = 1.5;
-
-const WIDTH = 595.28 * SCALE;
-const HEIGHT = 841.89 * SCALE;
-
-const getLinkText = (str: string) => {
-  if (str.length > 100) {
-    return str.substring(0, 100) + "...";
-  } else {
-    return str;
-  }
-};
-
-const downPDF = async () => {
-  // const pdf = new jsPDF('p', 'pt', 'a4')
-  const pdf = new jsPDF("p", "px", [WIDTH, HEIGHT]);
-  pdf.setFontSize(12 * SCALE);
-  pdf.setTextColor("rgb(0, 200, 175)");
-
-  for (let i = 0; i < vms.value.length; i++) {
-    const canvas = await html2canvas(vms.value[i]);
-    const contentWidth = canvas.width;
-    const contentHeight = canvas.height;
-
-    //一页pdf显示html页面生成的canvas高度;
-    const pageHeight = (contentWidth / WIDTH) * HEIGHT;
-    //未生成pdf的html页面高度
-    let leftHeight = contentHeight;
-    //页面偏移
-    let position = 0;
-    //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
-    const imgWidth = WIDTH;
-    const imgHeight = (WIDTH / contentWidth) * contentHeight;
-
-    const pageData = canvas.toDataURL("image/jpeg", 1.0);
-
-    if (leftHeight < pageHeight) {
-      pdf.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
-      if (groups.value[i][0].link) {
-        pdf.textWithLink(getLinkText(groups.value[i][0].link), 50 * SCALE, 143 * SCALE, {
-          url: groups.value[i][0].link,
-        });
-      }
-
-      if (groups.value[i][1] && groups.value[i][1].link) {
-        pdf.textWithLink(
-          getLinkText(groups.value[i][1].link),
-          50 * SCALE,
-          HEIGHT / 2 + 60 * SCALE,
-          { url: groups.value[i][1].link }
-        );
-      }
-    } else {
-      while (leftHeight > 0) {
-        pdf.addImage(pageData, "JPEG", 0, position, imgWidth, imgHeight);
-        leftHeight -= pageHeight;
-        position -= HEIGHT;
-        //避免添加空白页
-        // if (leftHeight > 0) {
-        //     pdf.addPage()
-        // }
-      }
-    }
-    if (i !== vms.value.length - 1) {
-      pdf.addPage();
-    }
-  }
-  return pdf;
-};
-
-defineExpose({
-  downPDF,
-});
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 142
src/views/measure/share/style.scss

@@ -1,142 +0,0 @@
-.share-content {
-  --scale: 1.4;
-  text-align: left;
-  overflow-y: auto;
-  padding-right: 20px;
-  margin-right: -20px;
-  color: #fff;
-
-  &.pc {
-    width: 840px;
-    height: 640px;
-    max-width: 90vw;
-    max-height: calc(90vh - 220px);
-  }
-
-  &:not(.pc) {
-    width: 90vw;
-    max-width: 840px;
-    max-height: calc(90vh - 220px);
-  }
-}
-
-.share-item {
-  margin-bottom: calc(19.2px * var(--scale));
-  width: 100%;
-
-  .share-info {
-    font-size: calc(7px * var(--scale));
-
-    .main-info {
-      display: flex;
-      justify-content: space-between;
-      font-size: calc(10px * var(--scale));
-      align-items: center;
-      font-size: calc(10px * var(--scale));
-
-      .name {
-        font-weight: bold;
-      }
-    }
-
-    .title {
-      margin: calc(9.6px * var(--scale)) 0 calc(4.8px * var(--scale));
-      height: calc(10px * var(--scale));
-    }
-
-    .link {
-      margin-bottom: calc(4.8px * var(--scale));
-      display: flex;
-      align-items: center;
-
-      .isPdf {
-        opacity: 0;
-      }
-
-      a {
-        color: var(--colors-primary-base);
-        flex: 0 1 auto;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-      }
-
-      .icon {
-        margin-left: 11px;
-        font-size: 1.4em;
-        cursor: pointer;
-      }
-    }
-    .desc {
-      color: #999999;
-      cursor: pointer;
-      width: 100%;
-      white-space: nowrap;
-      text-overflow: ellipsis;
-      overflow: hidden;
-      word-break: break-all;
-      cursor: pointer;
-    }
-
-    margin-bottom: calc(9.6px * var(--scale));
-  }
-
-  .img {
-    width: 100%;
-    padding-top: 49.999%;
-    position: relative;
-    img {
-      position: absolute;
-      left: 0;
-      top: 0;
-      width: 100%;
-      height: 100%;
-      object-fit: cover;
-    }
-  }
-}
-
-.pdf-temp {
-  &.pc {
-    --scale: 4;
-  }
-  &:not(.pc) {
-    --scale: 1.2;
-  }
-  position: absolute;
-  left: -10000px;
-  top: -100000px;
-  width: calc(595px * var(--scale));
-  background-color: #fff;
-  color: #333333;
-  > div {
-    padding: calc(40px * var(--scale)) calc(50px * var(--scale));
-  }
-
-  .header {
-    display: flex;
-    justify-content: space-between;
-    align-items: flex-end;
-    padding-bottom: calc(10px * var(--scale));
-    border-bottom: calc(1px * var(--scale)) solid #cccccc;
-    margin-bottom: calc(10px * var(--scale));
-
-    h1 {
-      font-size: calc(24px * var(--scale));
-    }
-
-    img {
-      height: calc(24px * var(--scale));
-    }
-  }
-
-  .footer {
-    margin-top: calc(10px * var(--scale));
-    padding-top: calc(10px * var(--scale));
-    border-top: calc(1px * var(--scale)) solid #cccccc;
-    font-size: calc(7px * var(--scale));
-    color: #999999;
-    display: flex;
-    justify-content: space-between;
-  }
-}

+ 0 - 138
src/views/measure/style.scss

@@ -1,138 +0,0 @@
-.measure {
-  padding: 0;
-}
-
-.btns {
-  display: flex;
-
-  .unit,
-  .start-measure {
-    height: 38px;
-  }
-  .unit {
-    flex: none;
-    margin-left: 10px;
-  }
-
-  .start-measure {
-    flex: 1;
-  }
-}
-
-.header-btns {
-  padding: 20px;
-}
-
-.tree-measure {
-  margin-left: 20px;
-  margin-right: 20px;
-}
-
-.head-ctrl {
-  display: flex;
-  justify-content: space-between;
-
-  .ctrl-more {
-    transition: opacity 0.3s ease;
-  }
-  .ctrl-more .icon {
-    font-size: 16px;
-    color: rgba(255, 255, 255, 0.7);
-    cursor: pointer;
-    transition: color 0.3s ease;
-
-    &:not(:first-child) {
-      margin-left: 22px;
-    }
-
-    &:hover {
-      color: var(--color-main-normal);
-    }
-  }
-}
-
-.measures {
-  display: flex;
-  justify-content: space-between;
-  margin-left: 20px;
-  margin-right: 20px;
-
-  &:not(.un-dataset) {
-    margin-left: 40px;
-  }
-
-  &.first-children {
-    padding-top: 10px;
-  }
-  &.last-children {
-    padding-bottom: 10px;
-  }
-}
-
-.info {
-  color: rgba(255, 255, 255, 0.7);
-  padding-left: 26px;
-  position: relative;
-  flex: 1;
-
-  &.select::after {
-    content: '';
-    position: absolute;
-    top: -10px;
-    bottom: 0;
-    left: -200px;
-    right: -200px;
-    background-color: rgba(var(--colors-primary-base-fill), 0.16);
-    pointer-events: none;
-  }
-
-  .checkbox {
-    position: absolute;
-    left: 0;
-    top: 0;
-  }
-
-  .name {
-    cursor: pointer;
-  }
-
-  p {
-    flex: none;
-    color: #fff;
-    .icon {
-      // margin-left: 6px;
-      font-size: 16px;
-      color: inherit;
-      color: rgba(255, 255, 255, 0.7);
-    }
-  }
-
-  .title {
-    line-height: 3em;
-
-    .enter {
-      width: 30px;
-      height: calc(3em - 4px);
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      background-color: var(--color-main-normal);
-      cursor: pointer;
-      margin-right: -10px;
-      color: rgba(255, 255, 255, 0.7);
-      border-top-right-radius: 4px;
-      border-bottom-right-radius: 4px;
-      cursor: pointer;
-    }
-
-    .marker {
-      display: block;
-      white-space: nowrap;
-      text-overflow: ellipsis;
-      overflow: hidden;
-      word-break: break-all;
-      cursor: pointer;
-      width: 150px;
-    }
-  }
-}

+ 0 - 278
src/views/measure/tree-manage.vue

@@ -1,278 +0,0 @@
-<template>
-  <ui-group border class="tree-measure">
-    <ui-group-option class="head-ctrl">
-      <ui-input type="checkbox" v-model="selectTree.select" />
-      <div class="ctrl-more" :class="{ disabled: selects.length === 0 }">
-        <ui-icon class="icon" type="share" @click="shareHandler" ctrl />
-        <ui-icon class="icon" type="del" @click="emit('delete', getRaws(selects))" ctrl />
-      </div>
-    </ui-group-option>
-  </ui-group>
-  <ui-group
-    v-for="(set, i) in setMeasures"
-    :key="set.id"
-    control
-    show
-    class="tree-group-measure"
-  >
-    <template v-slot:header v-if="set.id !== TemploraryID">
-      <div class="info measure-header">
-        <ui-input
-          type="checkbox"
-          v-model="selectTree.children[i].select"
-          class="checkbox"
-        />
-        <p>
-          <ui-icon type="show_dot_s" class="icon" />
-          {{ set.title }}
-        </p>
-      </div>
-    </template>
-    <ui-group-option
-      v-for="(measure, j) in set.children"
-      class="measures"
-      :key="set.id"
-      :class="{
-        'un-dataset': set.id === TemploraryID,
-        'first-children': j === 0,
-        'last-children': j === set.children.length - 1,
-      }"
-    >
-      <div class="info" :class="{ select: select === measure }">
-        <ui-input
-          type="checkbox"
-          v-model="selectTree.children[i].children[j].select"
-          class="checkbox"
-        />
-        <p
-          class="name"
-          @click="clickHandler(measure)"
-          :class="{ disabled: !measure.show }"
-          @mouseenter="enterHandler(measure)"
-          @mouseleave="leaveHandler(measure)"
-        >
-          <ui-icon :type="infos[measure.type].icon" class="icon" />
-          {{ infos[measure.type].name }}
-        </p>
-        <div class="title" :class="{ disabled: !measure.show }">
-          <ui-input
-            v-if="
-              editMeasures.includes(measure) &&
-              ((os.isPc && mode & modeFlags.EDIT) || !os.isPc)
-            "
-            :placeholder="$t('sys.inputPlc')"
-            @click.stop
-            type="text"
-            class="input measure-input"
-            height="30px"
-            :modelValue="measure.title"
-            :maxlength="70"
-            @update:modelValue="(val) => emit('updateTitle', getRaw(measure), val)"
-          ></ui-input>
-          <template v-else>
-            <span
-              @click="enterEditTitle(measure)"
-              class="marker"
-              :class="{ disabled: !measure.show }"
-              :title="measure.title"
-              >{{ measure.title || $t("measure.titlePlac") }}</span
-            >
-          </template>
-        </div>
-      </div>
-      <p @click="clickHandler(measure)" :class="{ disabled: !measure.show }">
-        {{ attachInfo.get(getRaw(measure)) }}
-      </p>
-    </ui-group-option>
-  </ui-group>
-</template>
-
-<script setup lang="ts">
-import {
-  CanvasMeasures,
-  SetMeasures,
-  CanvasMeasureAtom,
-  infos,
-  ShareMeasures,
-  getUnit,
-} from "./constant";
-import { ref, computed, watchEffect, ComputedRef, UnwrapRef, reactive, watch } from "vue";
-import {
-  MeasuresRaw,
-  MeasureAtom,
-  mode,
-  modeFlags,
-  appEl,
-  TemploraryID,
-  unTemp,
-} from "@/store";
-import { linkageSelectTree, getLinkageTreeLocal, LinkageTree } from "@/utils";
-import { useEdit, useFlyMeasure, useSDK } from "@/hook";
-import { inRevise, os } from "@/utils";
-
-const props = defineProps<{
-  list: CanvasMeasures;
-}>();
-const emit = defineEmits<{
-  (e: "changeShow", list: CanvasMeasures, show: boolean): void;
-  (e: "delete", list: CanvasMeasures): void;
-  (e: "share", shareList: ShareMeasures): void;
-  (e: "updateTitle", item: CanvasMeasureAtom, val): void;
-}>();
-
-const attachInfo = reactive(new WeakMap<CanvasMeasureAtom, string>());
-const select = ref<MeasureAtom>();
-
-const enterHandler = (measure) => {
-  getRaw(measure).canvas.highlight(true);
-  select.value = measure;
-};
-
-const leaveHandler = (measure) => {
-  getRaw(measure).canvas.highlight(false);
-  select.value = null;
-};
-
-const clickHandler = (measure: MeasureAtom) => {
-  useFlyMeasure(measure.points, getRaw(measure).canvas);
-};
-
-const listenAttachInfo = (item: CanvasMeasureAtom) => {
-  const updateUnit = () => {
-    attachInfo.set(item, getUnit(item));
-    item.raw.points = item.canvas.getPoints();
-    item.raw.datasetIds = item.canvas.getDatasets();
-    item.raw.dataset_points = item.canvas.getDatasetLocations();
-    const datasetId = item.canvas.getDatasetId();
-    item.raw.dataSet = unTemp;
-  };
-  item.canvas.bus.off("update");
-  item.canvas.bus.on("update", updateUnit);
-  item.canvas.bus.on("highlight", (inSelect) => {
-    select.value = inSelect ? item.raw : null;
-  });
-  attachInfo.set(item, getUnit(item));
-};
-
-const editMeasures = ref<MeasuresRaw>([]);
-const setMeasures = ref<SetMeasures>(null);
-const selectTree = ref<LinkageTree<any>>(null);
-let tree = null;
-
-watch(
-  () => props.list,
-  (newv, oldv) => {
-    if (!inRevise(newv, oldv)) return;
-
-    const tempMeasures: SetMeasures = [];
-    for (const item of props.list) {
-      const setMeasure = tempMeasures.find((set) => set.id === item.raw.dataSet.id);
-      if (setMeasure) {
-        setMeasure.children.push(item.raw);
-      } else {
-        tempMeasures.push({
-          ...item.raw.dataSet,
-          children: [item.raw],
-        });
-      }
-      listenAttachInfo(item);
-    }
-    tree = { children: tempMeasures };
-    const addOptions = selectTree.value
-      ? newv
-          .filter((atom) => !selectTree.value.options.includes(atom.raw))
-          .map(({ raw }) => raw)
-      : [];
-
-    const selectOptions = selectTree.value
-      ? selectTree.value.selects.concat(addOptions)
-      : props.list.map(({ raw }) => raw);
-
-    selectTree.value = (linkageSelectTree(tree, false) as unknown) as UnwrapRef<
-      LinkageTree<any>
-    >;
-    setMeasures.value = tempMeasures;
-    selectTree.value.selects = selectOptions.filter((atom) =>
-      selectTree.value.options.includes(atom)
-    );
-  },
-  { immediate: true }
-);
-
-const selects = (computed(
-  () => selectTree.value.selects
-) as unknown) as ComputedRef<MeasuresRaw>;
-
-const shareHandler = () => {
-  emit(
-    "share",
-    selects.value.map((select) => ({
-      measure: getRaw(select),
-      local: getLinkageTreeLocal(tree, (select as unknown) as typeof tree).filter(
-        (item) => item !== tree
-      ),
-    }))
-  );
-};
-const enterEditTitle = (measure) => {
-  editMeasures.value.push(measure);
-  if (os.isPc) {
-    useEdit();
-  }
-  setTimeout(() => {
-    const ancestor = appEl.value;
-    const quitHandler = () => {
-      editMeasures.value.splice(editMeasures.value.indexOf(measure), 1);
-      ancestor.removeEventListener("click", quitHandler);
-    };
-    ancestor.addEventListener("click", quitHandler);
-  }, 100);
-};
-
-const getRaw = (item: MeasureAtom) => props.list.find(({ raw }) => raw === item);
-const getRaws = (items: MeasuresRaw) => items.map(getRaw);
-
-watchEffect(
-  () => {
-    const hides = [];
-    const shows = [];
-    for (const option of selectTree.value.options) {
-      if (selects.value.includes(option)) {
-        shows.push(option);
-      } else {
-        hides.push(option);
-      }
-    }
-    emit("changeShow", getRaws(hides), false);
-    emit("changeShow", getRaws(shows), true);
-  },
-  { flush: "post" }
-);
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>
-
-<style lang="scss">
-.tree-group-measure {
-  div.group-title .group-icon {
-    right: 20px;
-  }
-  .measure-header {
-    margin-left: 20px;
-    margin-right: 20px;
-  }
-
-  .group-content {
-    display: block;
-  }
-}
-
-.measure-input .text.suffix input {
-  padding-top: 0;
-  padding-bottom: 0;
-  padding-right: 70px;
-  line-height: 30px;
-}
-</style>

+ 0 - 43
src/views/query/constant.ts

@@ -1,43 +0,0 @@
-import { DensityType, ColorMode, Shape } from '@/store/setting'
-import { ui18n } from '@/lang'
-
-export const densityOptions = [
-    { value: DensityType.low, label: ui18n.t('view.density.low') },
-    { value: DensityType.middle, label: ui18n.t('view.density.middle') },
-    { value: DensityType.high, label: ui18n.t('view.density.high') },
-] as const
-
-export const modelOptions = [
-    { value: ColorMode.fullcolor, label: ui18n.t('view.colorMode.full') },
-    { value: ColorMode.altitude, label: ui18n.t('view.colorMode.altitude') },
-    { value: ColorMode.translucent, label: ui18n.t('view.colorMode.translucent') },
-] as const
-
-export const shapeOptions = [
-    { value: Shape.rectangle, label: ui18n.t('view.shape.rectangle') },
-    { value: Shape.circular, label: ui18n.t('view.shape.circular') },
-] as const
-
-export const rangeOption = {
-    min: 20,
-    max: 1000,
-    step: 1,
-}
-
-export const opacityOption = {
-    min: 0.01,
-    max: 1,
-    step: 0.01,
-}
-
-export const detailOption = {
-    min: 0,
-    max: 1,
-    step: 0.01,
-}
-
-export const sizeOption = {
-    ...opacityOption,
-}
-
-export { DensityType, ColorMode, Shape }

+ 0 - 151
src/views/query/index.vue

@@ -1,151 +0,0 @@
-<template>
-  <ui-editor-toolbox v-model:toolbox="showToolbox" disabledAnimation>
-    <ui-group :title="$t('view.seting')" borderBottom>
-      <ui-group-option>
-        <ui-input
-          type="checkbox"
-          :label="$t('view.showMini')"
-          v-model="showMiniView"
-        />
-      </ui-group-option>
-      <ui-group-option>
-        <ui-input
-          type="checkbox"
-          :label="$t('view.showPano')"
-          v-model="showRoamPos"
-        />
-      </ui-group-option>
-    </ui-group>
-
-    <ui-group :title="$t('view.cloudSeting')" :class="{ disabled: isDisabled }">
-      <template v-slot:icon>
-        <ui-icon
-          type="reset"
-          ctrl
-          size="16px"
-          @click="refreshHandler"
-          class="refresh"
-          :tip="$t('view.reset')"
-          tip-h="right"
-        />
-      </template>
-
-      <ui-group-option :label="$t('view.density.name')">
-        <ui-input
-          type="select"
-          :options="densityOptions"
-          :placeholder="$t('sys.selectPic')"
-          v-model="density"
-          width="100%"
-        />
-      </ui-group-option>
-      <ui-group-option :label="$t('view.colorMode.name')">
-        <ui-input
-          type="select"
-          :options="modelOptions"
-          :placeholder="$t('sys.selectPic')"
-          v-model="colorMode"
-          width="100%"
-        />
-      </ui-group-option>
-    </ui-group>
-
-    <ui-group
-      :title="$t('view.moreSetting')"
-      control
-      :class="{ disabled: isDisabled }"
-    >
-      <ui-group-option :label="$t('view.range')">
-        <ui-input
-          type="range"
-          v-model="range"
-          v-bind="rangeOption"
-          width="100%"
-        />
-      </ui-group-option>
-      <ui-group-option :label="$t('view.opacity')">
-        <ui-input
-          type="range"
-          v-model="opacity"
-          v-bind="opacityOption"
-          width="100%"
-          :disabled="edgeStrong"
-        />
-      </ui-group-option>
-      <ui-group-option :label="$t('view.size')">
-        <ui-input
-          type="range"
-          v-model="size"
-          v-bind="sizeOption"
-          width="100%"
-        />
-      </ui-group-option>
-      <ui-group-option :label="$t('view.detail')">
-        <ui-input
-          type="range"
-          v-model="detail"
-          v-bind="detailOption"
-          width="100%"
-        />
-      </ui-group-option>
-      <ui-group-option :label="$t('view.shape.name')">
-        <ui-input
-          type="select"
-          :options="shapeOptions"
-          :placeholder="$t('sys.selectPic')"
-          v-model="shape"
-          width="100%"
-          dire="top"
-        />
-      </ui-group-option>
-      <ui-group-option v-if="os.isPc && !os.isTablet">
-        <ui-input
-          type="checkbox"
-          :label="$t('view.strong')"
-          v-model="edgeStrong"
-        />
-      </ui-group-option>
-    </ui-group>
-  </ui-editor-toolbox>
-</template>
-
-<script lang="ts" setup>
-import { Mode } from '@/sdk/types'
-import { computed } from 'vue'
-import { showToolbox } from '@/store'
-import { initSenior, store } from '@/store/setting'
-import { customMap } from '@/hook'
-import {
-  density,
-  colorMode,
-  shape,
-  showMiniView,
-  showRoamPos,
-  range,
-  opacity,
-  size,
-  edgeStrong,
-  detail
-} from '@/store/setting'
-import {
-  densityOptions,
-  modelOptions,
-  shapeOptions,
-  rangeOption,
-  opacityOption,
-  sizeOption,
-  detailOption
-} from './constant'
-import { os } from '@/utils'
-
-const isDisabled = computed(() => customMap.mode === Mode.pano)
-const refreshHandler = () => {
-  for (const key in initSenior) {
-    store[key] = initSenior[key]
-  }
-}
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>

+ 0 - 3
src/views/query/style.scss

@@ -1,3 +0,0 @@
-.refresh {
-  cursor: pointer;
-}

+ 6 - 5
src/views/scene/container.vue

@@ -8,26 +8,27 @@
 import {onMounted, ref, watchEffect} from "vue";
 import {setupLaser, useLoading, useParams} from "@/hook";
 import {store} from "@/store";
-import {webSite} from "@/store/setup";
 import {currentApp} from "@/store/app";
-import { axios } from "@/dbo";
+import { axios } from "@/dbo/";
 import { Loading } from '@kankan/components/index'
 
+const emit = defineEmits<{ (e: 'loaded'): void }>()
 const sceneLayoutRef = ref<HTMLCanvasElement>();
 
-onMounted(() => {
-  useLoading(
+onMounted(async () => {
+  await useLoading(
     setupLaser({
       sceneSelector: sceneLayoutRef.value,
       num: useParams().m,
       store: store,
       isDebug: useParams().test,
-      webSite: webSite.value,
+      webSite: "",
       axios,
       basePath: currentApp.basePath,
     })
   );
 
+  emit('loaded')
   setTimeout(() => {
     Loading.hideAll()
   }, 1000)

+ 25 - 4
src/views/scene/covers/fixPoint.vue

@@ -1,11 +1,15 @@
 <template>
   <Cover
       @change-pos="pos => $emit('changePos', pos)"
-      :pos="pos"
+      :pos="data.pos"
       @focus="$emit('focus')"
       @blur="$emit('blur')"
+      class="fix-cover"
   >
-    <img :src="icon" class="label" />
+    <div class="label">
+      <img :src="icon" />
+      <p>{{ data.text }}</p>
+    </div>
   </Cover>
 
 </template>
@@ -14,8 +18,9 @@
 import Cover from './cover.vue'
 import icon from './point1.png'
 import {Pos3D} from '@/sdk'
+import {FixPoint} from "@/store/fixPoint";
 
-const props = defineProps<{ pos: Pos3D }>()
+const props = defineProps<{ data: FixPoint }>()
 defineEmits<{
   (m: 'changePos', pos: Pos3D): void,
   (m: 'focus'): void,
@@ -25,6 +30,22 @@ defineEmits<{
 
 <style scoped lang="scss">
 .label {
-  width: 32px;
+  color: #fff;
+  font-size: 12px;
+  position: relative;
+  img {
+    width: 32px;
+  }
+  p {
+    text-shadow: #000 0 1px 1px;
+    position: absolute;
+    top: 100%;
+    white-space: nowrap;
+    left: 50%;
+    transform: translateX(-50%);
+  }
+  * {
+    pointer-events: none;
+  }
 }
 </style>

+ 79 - 3
src/views/scene/covers/fixPoints.vue

@@ -2,13 +2,33 @@
   <FixPointPanel
     v-for="point in fixPoints"
     :key="point.id"
-    :pos="point.pos"
+    :data="point"
     @change-pos="pos => point.pos = pos"
     @blur="() => active = active === point ? null : active"
     @focus="() => active = point"
   />
 
   <ActionsPanel :menus="activeActionMenus" v-if="active" />
+
+  <div class="edit-fix-point" v-if="edit">
+    <div class="header">
+      <h3>添加名称</h3>
+      <ui-icon type="close" ctrl @click="edit = null" />
+    </div>
+    <ui-input type="text" v-model="edit.text" width="100%" />
+    <div class="select">
+      <span>常用名称</span>
+      <p
+        v-for="option in options"
+        :key="option"
+        class="fun-ctrl"
+        :class="{active: option === edit.text}"
+        @click="edit.text = option"
+      >
+        {{ option }}
+      </p>
+    </div>
+  </div>
 </template>
 
 <script setup lang="ts">
@@ -16,8 +36,25 @@ import { fixPoints, FixPoint } from '@/store/fixPoint'
 import FixPointPanel from './fixPoint.vue'
 import ActionsPanel from './actions.vue'
 import {ref} from "vue";
+import UiIcon from "@/components/base/components/icon/index.vue";
+import UiInput from "@/components/base/components/input/index.vue";
 
 const active = ref<FixPoint>()
+const edit = ref<FixPoint>()
+const options = [
+  "轿车 / 平面",
+  "客车 / 平面",
+  "客车 / 侧面",
+  "货车 / 平面",
+  "牵引车 / 平面",
+  "正三轮机动车 / 平面",
+  "自行车",
+  "伤体",
+  "牲畜",
+  "散落物",
+  "岗台",
+  "桥",
+]
 const activeActionMenus = [
   {
     key: "edit",
@@ -25,7 +62,7 @@ const activeActionMenus = [
     color: "#161A1A",
     iconColor: "#2F8FFF",
     action() {
-
+      edit.value = active.value
     }
   },
   {
@@ -41,4 +78,43 @@ const activeActionMenus = [
     }
   }
 ]
-</script>
+</script>
+
+<style lang="scss" scoped>
+.edit-fix-point {
+  position: absolute;
+  left: 0;
+  top: 0;
+  bottom: 0;
+  z-index: 2;
+  background-color: #161A1A;
+  width: 240px;
+  padding: 10px;
+
+  .header {
+    margin-bottom: 21px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    h3 {
+      font-size: 16px;
+      color: #fff;
+    }
+  }
+
+  .select {
+    span, p {
+      color: #fff;
+    }
+    p {
+      padding: 14px 6px;
+      font-size: 14px;
+    }
+    span {
+      display: inline-block;
+      font-size: 12px;
+      padding: 24px 6px 6px;
+    }
+  }
+}
+</style>

+ 6 - 3
src/views/scene/covers/measure.vue

@@ -12,9 +12,12 @@ const emit = defineEmits<{
   (m: 'blur'): void
 }>()
 
-const sdk = useSDK()
-const map = sdk.carry.measureMap
-const measure = computed(() => map.get(props.data))
+const measure = computed(() => {
+  const sdk = useSDK()
+  if (sdk?.carry?.measureMap) {
+    return sdk.carry.measureMap.get(props.data)
+  }
+})
 
 watchEffect(() => {
   if (measure.value) {

+ 22 - 15
src/views/scene/index.vue

@@ -1,15 +1,17 @@
 <template>
-  <Container />
-  <Mode />
-  <Menus />
-  <BasePoints />
-  <FixPoints />
-  <Measures />
-  <Photo />
+  <Container @loaded="loaded = true" />
 
-  <ButtonPane class="back fun-ctrl" size="48">
-    <ui-icon type="close" class="icon" />
-  </ButtonPane>
+  <template v-if="loaded">
+    <Mode />
+    <Menus />
+    <BasePoints />
+    <FixPoints />
+    <Measures />
+    <Photo />
+    <ButtonPane class="back fun-ctrl" size="48">
+      <ui-icon type="close" class="icon" />
+    </ButtonPane>
+  </template>
 </template>
 
 <script lang="ts" setup>
@@ -21,14 +23,19 @@ import FixPoints from "@/views/scene/covers/fixPoints.vue";
 import Measures from "@/views/scene/covers/measures.vue";
 import Photo from './photo.vue'
 import ButtonPane from '@/components/button-pane'
-import {useAsyncSDK, disabledMap} from "@/hook";
+import {disabledMap, useSDK} from "@/hook";
 import customSetup from "../../hook/custom";
 import UiIcon from "@/components/base/components/icon/index.vue";
+import {ref, watchEffect} from "vue";
 
-
-useAsyncSDK().then(sdk => {
-  customSetup(sdk)
-  disabledMap.measure = false
+const loaded = ref(false)
+const stopReg = watchEffect(() => {
+  if (loaded.value) {
+    const sdk = useSDK();
+    stopReg()
+    customSetup(sdk)
+    disabledMap.measure = false
+  }
 })
 </script>
 

+ 1 - 1
src/views/scene/menus/actions.ts

@@ -72,7 +72,7 @@ const menuActions = {
         hide()
         onComplete()
       },
-      pos => fixPoints.value.push({ id: "aa", pos })
+      pos => fixPoints.value.push({ id: "aa", pos, text: "其他散落物" })
     )
   },
   [menuEnum.MEASURE_ROW]: (menu, onComplete) => {

+ 0 - 229
src/views/setup/index.vue

@@ -1,229 +0,0 @@
-<template>
-  <ui-editor-toolbox v-model:toolbox="showToolbox" disabledAnimation>
-    <div>
-      <ui-group :title="$t('sys.setting.setName')" border-bottom>
-        <ui-group-option>
-          <ui-input
-            type="text"
-            width="100%"
-            v-model="store.title"
-            :maxlength="15"
-            :placeholder="$t('sys.setting.setNamePlace')"
-          />
-        </ui-group-option>
-      </ui-group>
-      <ui-group :title="$t('sys.setting.setPic')" border-bottom>
-        <ui-group-option>
-          <div class="cover">
-            <img :src="getResources(store.initPic)" />
-            <span class="setting-cover" @click="setPhoto">{{ $t("sys.setup") }}</span>
-          </div>
-        </ui-group-option>
-      </ui-group>
-      <ui-group :title="$t('sys.setting.setView')" border-bottom>
-        <ui-group-option>
-          <ui-button @click="disabledMap.lmenu = !disabledMap.lmenu"
-            >{{ disabledMap.lmenu ? $t("sys.close") : $t("sys.open")
-            }}{{ $t("sys.setup") }}</ui-button
-          >
-        </ui-group-option>
-      </ui-group>
-      <ui-group :title="$t('sys.setting.setOpen')">
-        <ui-group-option>
-          <div class="input-item">
-            <ui-input
-              type="radio"
-              :label="$t('sys.setting.public')"
-              :modelValue="store.isOpen"
-              @update:modelValue="(val) => (store.isOpen = val)"
-            />
-          </div>
-          <div class="input-item">
-            <ui-input
-              type="radio"
-              :label="$t('sys.setting.pwd')"
-              :modelValue="!store.isOpen"
-              @update:modelValue="(val) => (store.isOpen = !val)"
-            />
-          </div>
-          <div class="input-item">
-            <ui-input
-              :placeholder="$t('sys.pwdPlace')"
-              type="text"
-              :maxlength="4"
-              width="100%"
-              v-model="store.password"
-              :disabled="store.isOpen"
-            />
-          </div>
-        </ui-group-option>
-      </ui-group>
-    </div>
-  </ui-editor-toolbox>
-
-  <ui-editor-toolbar :toolbar="showToolbar" class="photo">
-    <ui-button type="submit" class="btn" @click="quitPhoto(false)">{{
-      $t("sys.cancel")
-    }}</ui-button>
-    <ui-button type="primary" class="btn" @click="photo">{{
-      $t("sys.setting.setPic")
-    }}</ui-button>
-  </ui-editor-toolbar>
-</template>
-
-<script lang="ts" setup>
-import { showToolbox, showToolbar, isSave, isEdit, appEl } from "@/store";
-import { store, recovery, backups, storeSave } from "@/store/setup";
-import { getResources } from "@/store/app";
-import { axios, URL } from "@/dbo";
-import { ref, watchEffect } from "vue";
-import {
-  useSDK,
-  fullViewStack,
-  editBus,
-  mapDisabledStack,
-  useDesaveAssist,
-  customMap,
-  useAlert,
-  residenMouseMenuDisapbedStack,
-  useViewStack,
-  useEdit,
-  useLeaveEditRaw,
-  genUseLoading,
-  disabledMap,
-  lmenuDisabled,
-} from "@/hook";
-import { writeRouteName } from "@/router";
-import { currentApp } from "@/store/app";
-import { ui18n } from "@/lang";
-import { base64ToBlob } from "@/utils";
-import { Mode } from "@/sdk";
-
-const laser = useSDK();
-let blob: Blob;
-const photo = genUseLoading(async () => {
-  const pose = await laser.scene.getPose();
-  const { dataUrl: base64 } = await laser.scene.screenshot(300, 150);
-  blob = base64ToBlob(base64);
-  store.initPic = base64;
-  const posInfo = laser.scene.getPointByScreen();
-  store.pose = {
-    id: store.pose && store.pose.id,
-    inisDirection: {
-      yaw: pose.yaw,
-      pitch: pose.pitch,
-    },
-    inisPosition: pose.position,
-    datasetId: posInfo?.datasetId,
-  };
-  store.showMode = customMap.mode;
-  quitPhoto();
-});
-
-let photoIng = ref(false);
-const setPhoto = () => {
-  if (photoIng.value) return;
-  useEdit();
-  disabledMap.tool = true;
-  photoIng.value = true;
-  showToolbar.value = true;
-  laser.store.hot.show = false;
-  fullViewStack.push(ref("scene"));
-  mapDisabledStack.push(ref(true));
-  residenMouseMenuDisapbedStack.push(ref(true));
-};
-
-const getModeName = (raw) =>
-  raw === Mode.pano ? "panorama" : raw === Mode.cloud ? "cloudPoint" : "model";
-
-const quitPhoto = (isEdit = false) => {
-  if (!photoIng.value) return;
-  if (!isEdit && !isSave.value) {
-    useLeaveEditRaw();
-  }
-  disabledMap.tool = false;
-  photoIng.value = false;
-  showToolbar.value = false;
-  laser.store.hot.show = true;
-  mapDisabledStack.pop();
-  fullViewStack.pop();
-  residenMouseMenuDisapbedStack.pop();
-};
-
-useViewStack(() => {
-  lmenuDisabled.push(ref(false));
-  const fource = "fource-retain";
-  const stopWatch = watchEffect(
-    () => {
-      if (isEdit.value && !photoIng.value && disabledMap.lmenu) {
-        appEl.value.classList.add(fource);
-      } else {
-        appEl.value.classList.remove(fource);
-      }
-    },
-    { flush: "post" }
-  );
-  const leaveHandler = () => {
-    quitPhoto(true);
-    disabledMap.lmenu = false;
-    setTimeout(() => {
-      editBus.on("leave", leaveHandler, { last: true });
-      editBus.on("save", leaveHandler, { last: true });
-    });
-  };
-  editBus.on("leave", leaveHandler, { last: true });
-  editBus.on("save", leaveHandler, { last: true });
-
-  const initSwitch = disabledMap.switch;
-  const stopMenuWatch = watchEffect(
-    () => {
-      disabledMap.switch = disabledMap.lmenu;
-    },
-    { flush: "post" }
-  );
-
-  return () => {
-    editBus.off("leave", leaveHandler);
-    editBus.off("save", leaveHandler);
-    stopWatch();
-    photoIng.value = false;
-    disabledMap.switch = initSwitch;
-    lmenuDisabled.pop();
-    stopMenuWatch();
-  };
-});
-
-useDesaveAssist([store], {
-  save: async () => {
-    if (!store.title) {
-      useAlert(ui18n.t("sys.setting.setNameErr"));
-      throw new Error("场景名称不能为空!");
-    }
-    if (!store.isOpen && !store.password) {
-      useAlert(ui18n.t("sys.setting.setOpenErr"));
-      throw new Error("请输入加密密码!");
-    }
-    if (blob) {
-      const url = await axios.post(URL.uploadFile, blob, {
-        paths: { type: "setup" },
-      });
-      blob = null;
-      store.initPic = url;
-    }
-    await Promise.all([storeSave()]);
-  },
-  auto: true,
-  backup: backups,
-  recovery,
-});
-</script>
-
-<style lang="sass" scoped>
-@import './style.scss'
-</style>
-
-<style>
-.fource-retain {
-  --editor-menu-left: 0px !important;
-}
-</style>

+ 0 - 71
src/views/setup/style.scss

@@ -1,71 +0,0 @@
-.input-item {
-  margin-bottom: 10px;
-}
-
-.cover {
-  position: relative;
-  border-radius: 4px;
-  overflow: hidden;
-
-  img {
-    width: 100%;
-    display: block;
-    height: 150px;
-    object-fit: cover;
-  }
-
-  span {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    background: linear-gradient(
-      180deg,
-      rgba(0, 0, 0, 0.5) 0%,
-      rgba(0, 0, 0, 1) 100%
-    );
-    opacity: 0.5;
-    text-align: center;
-    height: 32px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    color: #fff;
-    cursor: pointer;
-  }
-}
-
-.photo .btn {
-  width: 160px;
-
-  &:not(:first-child) {
-    margin-left: 20px;
-  }
-}
-
-.menu-view-icon {
-  position: absolute;
-  right: 10px;
-  pointer-events: all;
-  top: 4px;
-  font-size: 14px;
-  width: 24px;
-  height: 24px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  background-color: rgba(0, 0, 0, 0.5);
-  border-radius: 50%;
-
-  &.active {
-    color: var(--colors-primary-base);
-  }
-}
-.btn-view-icon {
-  right: -20px;
-  top: -17px;
-  font-size: 14px;
-}
-.cusom-lmenu {
-  opacity: 1 !important;
-}

BIN
src/views/sys/err/img/archive.png


BIN
src/views/sys/err/img/del.png


BIN
src/views/sys/err/img/err.png


BIN
src/views/sys/err/img/run.png


BIN
src/views/sys/err/img/serveErr.png


BIN
src/views/sys/err/img/un.png


+ 0 - 94
src/views/sys/err/index.vue

@@ -1,94 +0,0 @@
-<template>
-  <div class="layout err-layout">
-    <div v-if="info[status]">
-      <img :src="info[status].cover" />
-      <h2 v-if="info[status].title">{{ info[status].title }}</h2>
-      <div class="content" v-html="info[status].desc"></div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { status, StatusEum } from '@/store/setup'
-import { useI18n } from '@/lang'
-import errImg from './img/err.png'
-import runImg from './img/run.png'
-import serveErrImg from './img/serveErr.png'
-import archiveImg from './img/archive.png'
-import delImg from './img/del.png'
-import unImg from './img/un.png'
-import { computed } from 'vue'
-
-type Info = {
-  cover: string
-  title?: string
-  desc: string
-}
-const i18n = useI18n()
-const info = computed(() => ({
-  [StatusEum.archive]: {
-    cover: archiveImg,
-    desc: i18n.t('err.scene.archive')
-  },
-  [StatusEum.del]: {
-    cover: delImg,
-    desc: i18n.t('err.scene.del')
-  },
-  [StatusEum.webglErr]: {
-    cover: serveErrImg,
-    desc: i18n.t('err.scene.webgl')
-  },
-  [StatusEum.err]: {
-    cover: errImg,
-    desc: i18n.t('err.scene.err')
-  },
-  [StatusEum.run]: {
-    cover: runImg,
-    desc: i18n.t('err.scene.run')
-  },
-  [StatusEum.reRun]: {
-    cover: runImg,
-    desc: i18n.t('err.scene.run')
-  },
-  [StatusEum.un]: {
-    cover: unImg,
-    desc: i18n.t('err.scene.un')
-  },
-  [StatusEum.serverErr]: {
-    cover: serveErrImg,
-    title: i18n.t('err.serve.title'),
-    desc: `<p>${i18n.t('err.serve.desc.0')}</p><p>${i18n.t(
-      'err.serve.desc.1'
-    )}<p>`
-  },
-  [StatusEum.disconnect]: {
-    cover: serveErrImg,
-    desc: i18n.t('err.disconnect')
-  },
-  [StatusEum.sdkErr]: {
-    cover: errImg,
-    desc: i18n.t('err.sdk')
-  },
-  [StatusEum.presetErr]: {
-    cover: serveErrImg,
-    desc: i18n.t('err.preset')
-  }
-}))
-</script>
-
-<style lang="scss" scoped>
-@import './style.scss';
-</style>
-
-<style lang="scss">
-.err-layout {
-  .content {
-    font-weight: 400;
-    font-size: 16px;
-    color: #999;
-    p {
-      margin-top: 10px;
-    }
-  }
-}
-</style>

+ 0 - 27
src/views/sys/err/style.scss

@@ -1,27 +0,0 @@
-.layout {
-  background: #f7f7f7;
-  width: 100%;
-  height: 100%;
-  padding-top: 12vh;
-  text-align: center;
-
-  div {
-    text-align: center;
-
-    img {
-      width: 240px;
-      margin-bottom: 30px;
-    }
-
-    h2 {
-      font-size: 1.5rem;
-      font-weight: inherit;
-      color: #646566;
-      margin-bottom: 10px;
-    }
-
-    .content {
-      padding: 0 20px;
-    }
-  }
-}

+ 29 - 1
yarn.lock

@@ -446,6 +446,24 @@ body-parser@1.20.1:
     type-is "~1.6.18"
     unpipe "1.0.0"
 
+body-parser@^1.20.2:
+  version "1.20.2"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
+  integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
+  dependencies:
+    bytes "3.1.2"
+    content-type "~1.0.5"
+    debug "2.6.9"
+    depd "2.0.0"
+    destroy "1.2.0"
+    http-errors "2.0.0"
+    iconv-lite "0.4.24"
+    on-finished "2.4.1"
+    qs "6.11.0"
+    raw-body "2.5.2"
+    type-is "~1.6.18"
+    unpipe "1.0.0"
+
 brace-expansion@^2.0.1:
   version "2.0.1"
   resolved "http://192.168.0.47:4873/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
@@ -521,7 +539,7 @@ content-disposition@0.5.4:
   dependencies:
     safe-buffer "5.2.1"
 
-content-type@~1.0.4:
+content-type@~1.0.4, content-type@~1.0.5:
   version "1.0.5"
   resolved "http://192.168.0.47:4873/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
   integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
@@ -1053,6 +1071,16 @@ raw-body@2.5.1:
     iconv-lite "0.4.24"
     unpipe "1.0.0"
 
+raw-body@2.5.2:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+  integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+  dependencies:
+    bytes "3.1.2"
+    http-errors "2.0.0"
+    iconv-lite "0.4.24"
+    unpipe "1.0.0"
+
 readdirp@~3.6.0:
   version "3.6.0"
   resolved "http://192.168.0.47:4873/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"