|
@@ -0,0 +1,411 @@
|
|
|
+<template>
|
|
|
+ <div class="right-layout">
|
|
|
+ <div class="tile-select">
|
|
|
+ <el-select
|
|
|
+ v-model="tileType"
|
|
|
+ placeholder="选择底图"
|
|
|
+ style="width: 120px"
|
|
|
+ class="tile-type-select"
|
|
|
+ >
|
|
|
+ <el-option v-for="item in tileOptions" :key="item" :label="item" :value="item" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="right-content">
|
|
|
+ <el-form :inline="false" v-if="!queryMode">
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" :icon="Plus" style="width: 100%" @click="addHandler">
|
|
|
+ 添加场景
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div class="tree-layout">
|
|
|
+ <p class="sub-title">全部数据</p>
|
|
|
+ <el-tree
|
|
|
+ style="max-width: 600px"
|
|
|
+ :data="treeNode"
|
|
|
+ :props="{ disabled: 'run' }"
|
|
|
+ node-key="id"
|
|
|
+ ref="treeRef"
|
|
|
+ :show-checkbox="!queryMode"
|
|
|
+ default-expand-all
|
|
|
+ :expand-on-click-node="false"
|
|
|
+ >
|
|
|
+ <template #default="{ node, data }">
|
|
|
+ <div
|
|
|
+ class="tree-item"
|
|
|
+ @click="
|
|
|
+ !data.disable &&
|
|
|
+ (data.type === 'scene' ? flyScene(data) : flyPos(data.raw))
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <el-tooltip
|
|
|
+ v-if="data.type === 'scene'"
|
|
|
+ class="box-item"
|
|
|
+ effect="dark"
|
|
|
+ :content="data.raw.sceneName + ' ' + node.label"
|
|
|
+ placement="top"
|
|
|
+ >
|
|
|
+ <span :class="{ disable: data.disable }" class="title">
|
|
|
+ <el-icon>
|
|
|
+ <Grid />
|
|
|
+ </el-icon>
|
|
|
+ {{ data.raw.sceneName }}
|
|
|
+
|
|
|
+ <span class="tree-scene-name">{{ node.label }}</span>
|
|
|
+ </span>
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip
|
|
|
+ v-else
|
|
|
+ class="box-item"
|
|
|
+ effect="dark"
|
|
|
+ :content="node.label"
|
|
|
+ placement="top"
|
|
|
+ >
|
|
|
+ <div class="title-box">
|
|
|
+ <span :class="{ disable: data.disable }" class="title">
|
|
|
+ <el-icon>
|
|
|
+ <StateGpsIcon v-if="!data.disable" />
|
|
|
+ <DeleteLocation v-else />
|
|
|
+ </el-icon>
|
|
|
+ {{ node.label }}
|
|
|
+ <!-- uu -->
|
|
|
+ </span>
|
|
|
+ <span :class="{ disable: data.disable }" class="name">
|
|
|
+ {{ data.raw.name }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ <span class="oper">
|
|
|
+ <template v-if="!queryMode">
|
|
|
+ <template v-if="data.type === 'scene'">
|
|
|
+ <el-icon color="#409efc" v-if="data.raw.creationMethod !== 2">
|
|
|
+ <Delete @click.stop="delSceneHandler([data.raw])" />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ <el-icon v-else color="#409efc">
|
|
|
+ <Edit @click.stop="inputPoint = data.raw" />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ <el-icon color="#409efc" style="margin-left: 8px">
|
|
|
+ <!-- root -->
|
|
|
+ <template v-if="data.raw.scenePos">
|
|
|
+ <FrameIcon
|
|
|
+ v-if="!data.run"
|
|
|
+ @click.stop="
|
|
|
+ data.type === 'scene'
|
|
|
+ ? gotoScene(data.raw)
|
|
|
+ : gotoPointPage(data.raw)
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <PanoramaIcon
|
|
|
+ v-if="!data.run"
|
|
|
+ @click.stop="
|
|
|
+ data.type === 'scene'
|
|
|
+ ? gotoScene(data.raw)
|
|
|
+ : gotoPointPage(data.raw)
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-icon>
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-tree>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template v-if="!queryMode">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ :icon="Download"
|
|
|
+ style="width: 100%"
|
|
|
+ @click="exportFile(getSelectPoints(), 2, relics?.name)"
|
|
|
+ >
|
|
|
+ 导出本体边界坐标
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ :icon="Download"
|
|
|
+ style="width: 100%; margin-top: 20px; margin-left: 0"
|
|
|
+ @click="exportImage(getSelectPoints(), relics?.name)"
|
|
|
+ >
|
|
|
+ 下载全景图
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <SingleInput
|
|
|
+ :visible="!!inputPoint"
|
|
|
+ @update:visible="inputPoint = null"
|
|
|
+ :value="inputPoint?.name || ''"
|
|
|
+ :update-value="updatePointName"
|
|
|
+ title="测点说明"
|
|
|
+ placeholder="请填写测点说明"
|
|
|
+ />
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { boardDataChange, queryMode } from "./install";
|
|
|
+import {
|
|
|
+ Plus,
|
|
|
+ Delete,
|
|
|
+ Grid,
|
|
|
+ Download,
|
|
|
+ DeleteLocation,
|
|
|
+ Edit,
|
|
|
+} from "@element-plus/icons-vue";
|
|
|
+import { computed, onBeforeUnmount, ref, watchEffect } from "vue";
|
|
|
+import {
|
|
|
+ Scene,
|
|
|
+ scenes,
|
|
|
+ ScenePoint,
|
|
|
+ updateScenePointName,
|
|
|
+ gotoScene,
|
|
|
+ relicsId,
|
|
|
+ refreshScenes,
|
|
|
+ boardData,
|
|
|
+ scenePoints,
|
|
|
+} from "@/store/scene";
|
|
|
+import { relics } from "@/store/relics";
|
|
|
+import SingleInput from "@/components/single-input.vue";
|
|
|
+import { selectScenes } from "../quisk";
|
|
|
+import { addRelicsScenesFetch, delRelicsScenesFetch } from "@/request";
|
|
|
+import { exportFile, exportImage } from "./pc4Helper";
|
|
|
+import { SceneStatus } from "@/store/scene";
|
|
|
+import StateGpsIcon from "@/assets/state_gps.svg";
|
|
|
+import PanoramaIcon from "@/assets/panorama.svg";
|
|
|
+import FrameIcon from "@/assets/frame.svg";
|
|
|
+import { alert } from "@/helper/message";
|
|
|
+import {
|
|
|
+ PolygonsPointAttrib,
|
|
|
+ getWholeLineLinesByPointId,
|
|
|
+ getWholeLinePoint,
|
|
|
+} from "drawing-board";
|
|
|
+import { flyScene, gotoPointPage, tileType, mapManage, tileOptions } from "./install";
|
|
|
+import { board } from "./install";
|
|
|
+
|
|
|
+const inputPoint = ref<ScenePoint | null>(null);
|
|
|
+const updatePointName = async (title: string) => {
|
|
|
+ const point = getWholeLinePoint(
|
|
|
+ boardData.value,
|
|
|
+ inputPoint.value.id.toString()
|
|
|
+ ) as PolygonsPointAttrib;
|
|
|
+ await Promise.all([
|
|
|
+ boardDataChange(() => (point.title = title)),
|
|
|
+ updateScenePointName(inputPoint.value!, title),
|
|
|
+ ]);
|
|
|
+};
|
|
|
+
|
|
|
+const flyPos = (point: ScenePoint) => {
|
|
|
+ mapManage.map.getView().setCenter(point.pos);
|
|
|
+ board.polygon.status.activePointId = point.id.toString();
|
|
|
+};
|
|
|
+
|
|
|
+const relicsName = ref("");
|
|
|
+watchEffect(() => (relicsName.value = relics.value?.name || ""));
|
|
|
+
|
|
|
+const treeRef = ref<any>();
|
|
|
+const treeNode = computed(() =>
|
|
|
+ scenes.value.map((scene) => ({
|
|
|
+ label: scene.sceneCode,
|
|
|
+ id: scene.id,
|
|
|
+ type: "scene",
|
|
|
+ run: scene.calcStatus !== SceneStatus.SUCCESS,
|
|
|
+ disable: scene.scenePos.every((pos) => !pos.pos || pos.pos.length === 0),
|
|
|
+ raw: scene,
|
|
|
+ children: scene.scenePos.map((pos) => ({
|
|
|
+ label: pos.uuid,
|
|
|
+ run: scene.calcStatus !== SceneStatus.SUCCESS,
|
|
|
+ disable: !pos.pos || pos.pos.length === 0,
|
|
|
+ id: pos.id,
|
|
|
+ type: "point",
|
|
|
+ raw: { ...pos, name: pos.name, cameraType: scene.cameraType },
|
|
|
+ })),
|
|
|
+ }))
|
|
|
+);
|
|
|
+
|
|
|
+const getSelectPoints = () =>
|
|
|
+ treeRef
|
|
|
+ .value!.getCheckedNodes(false, false)
|
|
|
+ .filter((option: any) => option.type === "point")
|
|
|
+ .map((option: any) => option.raw) as ScenePoint[];
|
|
|
+
|
|
|
+watchEffect(() => {
|
|
|
+ if (treeRef.value) {
|
|
|
+ board.polygon.status.selectPoiIds = getSelectPoints().map((point) =>
|
|
|
+ point.id.toString()
|
|
|
+ );
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const delScenesBeforeCheck = async (scenes: Scene[]) => {
|
|
|
+ if (scenes.length === 0) return true;
|
|
|
+ for (const scene of scenes) {
|
|
|
+ const que = scene.scenePos.some((pos) => {
|
|
|
+ const id = pos.id.toString();
|
|
|
+ return getWholeLineLinesByPointId(boardData.value, id).length !== 0;
|
|
|
+ });
|
|
|
+ if (que) {
|
|
|
+ await alert("已存在矢量图数据,不可删除。");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const addHandler = async () => {
|
|
|
+ const sceneCodes = scenes.value.map((scene) => scene.sceneCode);
|
|
|
+ await selectScenes({
|
|
|
+ scenes: scenes.value,
|
|
|
+ selfScenes: scenes.value.filter((scene) => scene.creationMethod === 2),
|
|
|
+ submit: async (nScene) => {
|
|
|
+ const requests: Promise<any>[] = [];
|
|
|
+ const delScenes = sceneCodes
|
|
|
+ .filter((sceneCode) => !nScene.some((scene) => scene.sceneCode === sceneCode))
|
|
|
+ .map((sceneCode) => scenes.value.find((scene) => scene.sceneCode === sceneCode)!);
|
|
|
+
|
|
|
+ if (!(await delScenesBeforeCheck(delScenes))) {
|
|
|
+ throw "不可删除";
|
|
|
+ }
|
|
|
+
|
|
|
+ delScenes.length &&
|
|
|
+ requests.push(
|
|
|
+ delRelicsScenesFetch(
|
|
|
+ relicsId.value,
|
|
|
+ delScenes.map((item) => ({ sceneCode: item.sceneCode, id: item.sceneId }))
|
|
|
+ )
|
|
|
+ );
|
|
|
+ const addScenes = nScene.filter(({ sceneCode }) => !sceneCodes.includes(sceneCode));
|
|
|
+ addScenes.length &&
|
|
|
+ requests.push(
|
|
|
+ addRelicsScenesFetch(
|
|
|
+ relicsId.value!,
|
|
|
+ addScenes.map((item) => ({ sceneCode: item.sceneCode, id: item.sceneId }))
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
+ await Promise.all(requests);
|
|
|
+ requests.length && (await refreshScenes());
|
|
|
+ },
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const delSceneHandler = async (scenes: Scene[]) => {
|
|
|
+ if (!(await delScenesBeforeCheck(scenes))) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ await delRelicsScenesFetch(
|
|
|
+ relicsId.value,
|
|
|
+ scenes.map((item) => ({ sceneCode: item.sceneCode, id: item.sceneId }))
|
|
|
+ );
|
|
|
+ await refreshScenes();
|
|
|
+};
|
|
|
+
|
|
|
+const pointClickHandler = ({ id }: { id: any }) => {
|
|
|
+ const point = scenePoints.value.find((point) => point.id.toString() === id);
|
|
|
+ point && gotoPointPage(point);
|
|
|
+};
|
|
|
+
|
|
|
+board.polygon.bus.on("clickPoint", pointClickHandler);
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ board.polygon.bus.off("clickPoint", pointClickHandler);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+:deep(.el-tree-node__content) {
|
|
|
+ --el-tree-node-content-height: 26px;
|
|
|
+ line-height: 26px;
|
|
|
+ user-select: none;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-tree-node__children .el-tree-node__content) {
|
|
|
+ --el-tree-node-content-height: 52px;
|
|
|
+
|
|
|
+ & > label.el-checkbox {
|
|
|
+ padding-top: 6px;
|
|
|
+ align-items: flex-start;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.tree-item {
|
|
|
+ display: flex;
|
|
|
+ width: calc(100% - 50px);
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+ font-size: var(--font14);
|
|
|
+
|
|
|
+ .title {
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ text-overflow: ellipsis; //文本溢出显示省略号
|
|
|
+ white-space: nowrap; //文本不会换行
|
|
|
+ line-height: 26px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title-box {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+
|
|
|
+ .name {
|
|
|
+ padding-left: 15px;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .oper {
|
|
|
+ flex: none;
|
|
|
+ line-height: 26px;
|
|
|
+ vertical-align: middle;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.disable {
|
|
|
+ pointer-events: all;
|
|
|
+}
|
|
|
+
|
|
|
+.tree-layout {
|
|
|
+ p {
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sub-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bolder;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.right-layout {
|
|
|
+ display: flex;
|
|
|
+ height: 100%;
|
|
|
+ flex-direction: column;
|
|
|
+
|
|
|
+ .right-content {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.tree-layout .tree-scene-name {
|
|
|
+ font-size: 10px;
|
|
|
+ margin: 0;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.tile-select {
|
|
|
+ position: absolute;
|
|
|
+ right: 100%;
|
|
|
+ top: 10px;
|
|
|
+ margin-right: 10px;
|
|
|
+}
|
|
|
+</style>
|