This commit is contained in:
zh
2025-09-11 18:27:56 +08:00
parent a1f5a61252
commit b1bfadb635
186 changed files with 8815 additions and 442 deletions

View File

@ -1,10 +1,10 @@
import { app, shell, BrowserWindow, ipcMain, globalShortcut } from 'electron'
import { app, shell, BrowserWindow, ipcMain, globalShortcut, dialog } from 'electron'
import path, { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/earth.png?asset'
import fs from 'fs'
import { exec } from 'child_process'
const { exec } = require('child_process');
// 开发环境路径处理 - 确保添加正确的file协议
const devSplashPath = path.resolve(
@ -53,6 +53,11 @@ if (prodSplashPath) {
// 最终的启动页URL
const splashURL = process.env.NODE_ENV === 'development' ? devSplashURL : prodSplashURL
let startBatPath = path.join(process.resourcesPath, 'app.asar.unpacked', 'resources', 'java', 'start.bat')
startBatPath = process.platform === 'win32' ? startBatPath.replace(/^(\w:)/, '/$1') : startBatPath
let stopBatPath = path.join(process.resourcesPath, 'app.asar.unpacked', 'resources', 'java', 'stop.bat')
stopBatPath = process.platform === 'win32' ? stopBatPath.replace(/^(\w:)/, '/$1') : stopBatPath
// const splashURL =
// process.env.NODE_ENV === 'development'
// ? `${join(app.getAppPath(), 'src/renderer/public/startUp/startUp.html')}`
@ -126,6 +131,23 @@ function createWindow(): void {
}, 200)
})
})
ipcMain.on("open-directory-dialog", (event, option) => {
// @ts-ignore
dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), {
properties: option.properties,
filters: option.filters,
})
.then((files) => {
let arr = [];
if (!files.canceled) {
files.filePaths.forEach((url) => {
// @ts-ignore
arr.push(url.replace(/\\/g, "/"));
});
}
event.sender.send("selectedItem", arr);
});
});
// 设置窗口标题和图标
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
@ -156,6 +178,26 @@ function createWindow(): void {
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
// alert(devSplashURL)
// alert(prodSplashURL)
// dialog.showMessageBox({
// type: 'info',
// title: '信息1',
// message: devSplashURL,
// buttons: ['确定']
// })
// 执行批处理文件
exec(startBatPath.substring(1, 200), (error, stdout, stderr) => {
if (error) {
console.error(`执行错误: ${error.message}`);
return;
}
if (stderr) {
console.error(`错误输出: ${stderr}`);
return;
}
console.log(`批处理输出: ${stdout}`);
});
// Set app user model id for windows
electronApp.setAppUserModelId('com.electron')
@ -189,6 +231,18 @@ app.on('window-all-closed', () => {
// 退出时注销所有快捷键
app.on('will-quit', () => {
globalShortcut.unregisterAll()
// 关闭后台服务
exec(stopBatPath.substring(1, 200), (error, stdout, stderr) => {
if (error) {
console.error(`执行错误: ${error.message}`);
return;
}
if (stderr) {
console.error(`错误输出: ${stderr}`);
return;
}
console.log(`批处理输出: ${stdout}`);
});
})
// In this file you can include the rest of your app's specific main process

View File

@ -12,6 +12,7 @@
<body>
<div id="app"></div>
<script src="/tree/jquery-1.4.4.min.js"></script>
<script src="/exif/exif.min.js"></script>
<script type="module" src="/src/main.ts"></script>
<script src="/sdk/YJEarth.min.js"></script>
</body>

8
src/renderer/public/exif/exif.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,7 +1,7 @@
import request from '@/axios/request'
export const GisApi = {
// 查询活动分页
//文件上传
linkFile: async (data: any) => {
return await request.post({
url: `/fileInfo/upload`,

View File

@ -7,6 +7,13 @@ export const TreeApi = {
url: `/source/list`
})
},
// 新增资源 /source/addModelSource
addModelSource: async (data: any) => {
return await request.post({
url: `/source/addModelSource`,
data
})
},
// 新增其他资源 /source/addOtherSource
addOtherSource: async (data: any) => {
return await request.post({
@ -25,11 +32,6 @@ export const TreeApi = {
return await request.post({
url: `/source/addDirectory`,
data
}).then((res) => {
ElMessage({
message: '添加成功',
type: 'success'
})
});
},
// 更新节点信息
@ -47,7 +49,7 @@ export const TreeApi = {
//删除节点
removeDirectory: async (data: any) => {
return await request.post({
url: `/yjearth4/api/v1/source/del`,
url: `/source/delete`,
data
})
},

View File

@ -10,14 +10,15 @@ import type {
const pendingRequests = new Map<string, AbortController>()
let baseURL: any
if (window && window.process && window.process.type === 'renderer') {
baseURL = localStorage.getItem('ip') ||'http://192.168.110.25:8848'|| 'http://127.0.0.1:8808'
// baseURL = localStorage.getItem('ip') ||'http://192.168.110.25:8848'|| 'http://127.0.0.1:8808'
baseURL = 'http://127.0.0.1:8848'
} else {
baseURL = ''
baseURL = 'http://192.168.110.25:8848'
}
// 创建自定义配置的axios实例
const service: AxiosInstance = axios.create({
baseURL:'http://192.168.110.25:8848',
baseURL:baseURL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',

View File

@ -0,0 +1,47 @@
import { TreeApi } from '@/api/tree'
import { useTreeNode } from '../views/components/tree/hooks/treeNode'
import { initMapData } from './initMapData'
export const addMapSource = async ({ type, id, sourceName = '未命名对象', opt = {} }) => {
const { cusAddNodes } = useTreeNode()
if (!id) {
id = new YJ.Tools().randomString()
}
let options: any = await initMapData(type, opt)
let selectedNodes = window.treeObj.getSelectedNodes()
let node = selectedNodes && selectedNodes[selectedNodes.length - 1]
let parentId
if (node) {
if (node.sourceType === 'directory') {
parentId = node.id
}
else {
parentId = node.parentId
}
}
delete options.host
switch (type) {
case 'rendezvous':
case 'attackArrow':
case 'pincerArrow':
delete options.label.ground
delete options.label.position
break;
case 'path':
delete options.label.text
break;
}
console.log('options', options)
let params: any = {
id: id,
sourceName: sourceName,
sourceType: type,
// isShow: 1,
parentId: parentId,
// "treeIndex": 0,
params: options
}
TreeApi.addOtherSource(params)
params.params = JSON.stringify(params.params)
params.isShow = true
cusAddNodes(window.treeObj, params.parentId, [params])
}

View File

@ -1,7 +1,6 @@
export const initMapData = async (type, data) => {
let entityObject
let options
console.log('data', type, data)
switch (type) {
case 'groundText':
entityObject = new YJ.Obj.GroundText(window.earth, data)
@ -52,6 +51,18 @@ export const initMapData = async (type, data) => {
data.host = 'http://192.168.110.25:8848'
entityObject = new YJ.Obj.Tileset(window.earth, data)
break
case 'path':
entityObject = new YJ.Obj.TrajectoryMotion(window.earth, data)
break
case 'wallStereoscopic':
entityObject = new YJ.Obj.WallStereoscopic(window.earth, data)
break
case 'diffuseScan':
entityObject = new YJ.Obj.CircleDiffuse(window.earth, data)
break
case 'radarScan':
entityObject = new YJ.Obj.RadarScan(window.earth, data)
break
default:
return
break

View File

@ -10,13 +10,8 @@
</div>
</div>
<div class="boxBody">
<el-form
:model="form"
:rules="rules"
ref="ruleForm"
label-width="80px"
@keyup.enter.native="submitForm(ruleForm)"
>
<el-form :model="form" :rules="rules" ref="ruleForm" label-width="80px"
@keyup.enter.native="submitForm(ruleForm)">
<el-form-item label="名称:" prop="sourceName">
<!-- @input="removeSpaces" -->
<el-input v-model.trim="form.sourceName" placeholder="图层文件夹"></el-input>
@ -70,9 +65,10 @@ const add = throttle(async () => {
const res: any = await TreeApi.addDirectory({
id: new YJ.Tools().randomString(),
sourceName: form.sourceName,
parentId
parentId: parentId || undefined
})
if (res.code == 0) {
console.log(res)
if (res.code == 0 || res.code == 200) {
const node = {
...res.data
}
@ -87,7 +83,11 @@ const add = throttle(async () => {
tree_index: item.getIndex()
}
})
await updateTree(newNode)
ElMessage({
message: '添加成功',
type: 'success'
})
cancel()
} else {
ElMessage({
message: '添加失败',
@ -227,11 +227,14 @@ const cancel = () => {
.el-form-item__label {
color: #fff;
}
.el-input__wrapper {
background-color: rgba(0, 0, 0, 0.5);
border: 0.2px solid rgba(0, 255, 255, 0.5);
box-shadow: 0 0 0 0.2px rgba(0, 255, 255, 0.5) inset !important; /* 新增此行 */
box-shadow: 0 0 0 0.2px rgba(0, 255, 255, 0.5) inset !important;
/* 新增此行 */
}
.el-input__inner {
background-color: transparent;
color: #fff;

View File

@ -16,10 +16,7 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { inject } from 'vue'
import { TreeApi } from '@/api/tree'
import { initMapData } from '../tree/initMapData'
import { useTreeNode } from '../tree/hooks/treeNode'
const { cusAddNodes } = useTreeNode()
import { addMapSource } from '../../../common/addMapSource'
const { t } = useI18n()
const eventBus: any = inject('bus')
@ -70,27 +67,16 @@ const bottomMenuList = ref([
}
let id = new YJ.Tools().randomString()
let name = '点标注'
let options: any = await initMapData('point', {
id: id,
name: name,
position: position
})
let selectedNodes = window.treeObj.getSelectedNodes()
delete options.host
let params = {
await addMapSource({
type: 'point',
id: id,
sourceName: name,
sourceType: 'point',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
position: position
}
})
})
}
},
@ -109,26 +95,16 @@ const bottomMenuList = ref([
}
let id = new YJ.Tools().randomString()
let name = '线标注'
let options: any = await initMapData('line', {
id: id,
name: name,
positions: positions
})
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'line',
id: id,
sourceName: name,
sourceType: 'line',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
positions: positions
}
})
})
}
},
@ -145,26 +121,16 @@ const bottomMenuList = ref([
}
let id = new YJ.Tools().randomString()
let name = '曲线标注'
let options: any = await initMapData('curve', {
id: id,
name: name,
positions: positions
})
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'curve',
id: id,
sourceName: name,
sourceType: 'curve',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
positions: positions
}
})
})
}
},
@ -186,28 +152,16 @@ const bottomMenuList = ref([
let id = new YJ.Tools().randomString()
// let id = 'aaa'
let name = '面标注'
let options: any = await initMapData('panel', {
id: id,
name: name,
positions: positions
})
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'panel',
id: id,
sourceName: name,
sourceType: 'panel',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
console.log(params)
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
positions: positions
}
})
})
}
},
@ -221,30 +175,16 @@ const bottomMenuList = ref([
Draw.start(async (a, opt) => {
let id = new YJ.Tools().randomString()
let name = '圆'
let options: any = await initMapData('circle', {
id: id,
name: name,
center: opt.center, radius: opt.radius
})
delete options.host
console.log('options', options)
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'circle',
id: id,
sourceName: name,
sourceType: "circle",
// isShow: 1,
parentId: (selectedNodes && selectedNodes[selectedNodes.length - 1]) ? selectedNodes[selectedNodes.length - 1].id : undefined,
// "treeIndex": 0,
params: options
}
// eventBus.emit("openDialog", 'circle');
// TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
center: opt.center, radius: opt.radius
}
})
})
}
},
@ -264,31 +204,17 @@ const bottomMenuList = ref([
return
}
let id = new YJ.Tools().randomString()
// let id = 'aaa'
let name = '矩形'
let options: any = await initMapData('panel', {
id: id,
name: name,
positions: positions
})
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'rectangle',
id: id,
sourceName: name,
sourceType: 'rectangle',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
console.log(params)
// eventBus.emit("openDialog", 'panel');
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
positions: positions
}
})
})
}
},
@ -308,33 +234,17 @@ const bottomMenuList = ref([
return
}
let id = new YJ.Tools().randomString()
// let id = 'aaa'
let name = '集结地'
let options: any = await initMapData('rendezvous', {
id: id,
name: name,
positions: positions
})
delete options.label.ground
delete options.label.position
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'rendezvous',
id: id,
sourceName: name,
sourceType: 'rendezvous',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
console.log(params)
// eventBus.emit("openDialog", 'panel');
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
positions: positions
}
})
})
}
},
@ -354,33 +264,17 @@ const bottomMenuList = ref([
return
}
let id = new YJ.Tools().randomString()
// let id = 'aaa'
let name = '箭头'
let options: any = await initMapData('attackArrow', {
id: id,
name: name,
positions: positions
})
delete options.label.ground
delete options.label.position
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'attackArrow',
id: id,
sourceName: name,
sourceType: 'attackArrow',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
console.log(params)
// eventBus.emit("openDialog", 'panel');
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
positions: positions
}
})
})
}
},
@ -401,32 +295,17 @@ const bottomMenuList = ref([
return
}
let id = new YJ.Tools().randomString()
// let id = 'aaa'
let name = '双箭头'
let options: any = await initMapData('pincerArrow', {
id: id,
name: name,
positions: positions
})
delete options.label.ground
delete options.label.position
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
await addMapSource({
type: 'pincerArrow',
id: id,
sourceName: name,
sourceType: 'pincerArrow',
// isShow: 1,
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
// "treeIndex": 0,
params: options
}
// eventBus.emit("openDialog", 'panel');
TreeApi.addOtherSource(params)
cusAddNodes(window.treeObj, params.parentId, [params])
opt: {
id: id,
name: name,
positions: positions
}
})
})
}
}
@ -584,4 +463,4 @@ const addMarker = (item: any) => {
transform: rotate(270deg);
cursor: pointer;
}
</style>
</style>

View File

@ -3,31 +3,29 @@
<div class="leftSideSecondBox">
<template v-if="obj">
<div class="menuItem" v-for="value in obj.children" @click="handleClick(value)">
<img
:src="'src/assets/images/second/' + `${value}` + '.png'"
style="color: rgb(255, 0, 0)"
alt=""
/>
<img :src="'src/assets/images/second/' + `${value}` + '.png'" style="color: rgb(255, 0, 0)" alt="" />
<span :style="{ color: !clickChange[value] ? 'var(--color-text)' : 'rgb(255,0,0)' }">{{
t(`${obj.key}.${value}`)
}}</span>
t(`${obj.key}.${value}`)
}}</span>
</div>
</template>
</div>
</div>
</template>
<script setup>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { ref, reactive, getCurrentInstance } from 'vue'
import { initMapData } from '../../../common/initMapData'
import { useTreeNode } from '../tree/hooks/treeNode'
import { TreeApi } from '@/api/tree'
import { renderMethods } from '../tree/hooks/renderTreeNode'
import { addMapSource } from '../../../common/addMapSource'
const { proxy } = getCurrentInstance()
const { t } = useI18n()
const { findParentId, findTreeIndex, cusAddNodes } = useTreeNode()
const obj = ref(null)
const obj: any = ref(null)
const isclick = ref(false)
const eventBus = inject('bus')
const eventBus: any = inject('bus')
const initList = (value) => {
obj.value = value
}
@ -38,61 +36,104 @@ var clickChange = reactive({
videoRecord: false
})
var graffitiObjArr = reactive([])
eventBus.on('graffitiObj', (data) => {
eventBus.on('graffitiObj', (data: never) => {
graffitiObjArr.push(data)
})
const methodMap = {
// 轨迹运动
trajectoryMotion: ()=>{
// let draw = new YJ.Draw.DrawPolyline(window.earth)
// draw.start((err, positions) => {
// if (positions.length > 1) {}
// })
trajectoryMotion: () => {
let draw = new YJ.Draw.DrawPolyline(window.earth)
draw.start(async (err, positions) => {
if (positions && positions.length > 1) {
let id = new YJ.Tools().randomString()
let name = '轨迹运动'
await addMapSource({
type: 'path',
id: id,
sourceName: name,
opt: {
id: id,
name: name,
model: {
show: true,
url: "http://localhost:5173/tank.glb",
},
line: {
show: true,
positions: positions,
}
}
})
}
})
},
// 电子围墙
electronicFence: () => {
let draw = new YJ.Draw.DrawPolyline(window.earth)
draw.start((err, positions) => {
if (positions.length > 1) {
let alt = positions[0].alt
positions.forEach((item) => {
if (item.alt < alt) alt = item.alt
let id = new YJ.Tools().randomString()
let name = '电子围墙'
addMapSource({
type: 'wallStereoscopic',
id: id,
sourceName: name,
opt: {
id: id,
name: name,
positions: positions,
}
})
// let id = new YJ.Tools().randomString()
let id = 'aaa'
let params = {
sourceName: '电子围墙',
id,
sourceType: 'wallStereoscopic',
parentId: findParentId(window.treeObj),
params: {
id,
positions,
color: '#fff',
cornerType: undefined,
extrudedHeight: 2.4,
width: 0.24
},
treeIndex: findTreeIndex(window.treeObj)
}
// console.log(params);
// 渲染电子围墙
renderMethods.renderWallStereoscopic(params)
// 存入数据库
// let res = TreeApi.addOtherSource(params)
// console.log('addOtherSource', res)
// 上树
cusAddNodes(window.treeObj, params.parentId, [params])
eventBus.emit("openDialog", 'wallStereoscopic');
}
})
},
// 扩散光波
radarLightWave: () => {
let draw = new YJ.Draw.DrawCircle(window.earth)
draw.start((err, params) => {
console.log(params)
if (params) {
draw.start((err, options) => {
console.log('options', options)
if (options) {
let id = new YJ.Tools().randomString()
let name = '扩散光波'
addMapSource({
type: 'diffuseScan',
id: id,
sourceName: name,
opt: {
id: id,
name: name,
lng: options.center.lng,
lat: options.center.lat,
circle: [
{
radius: options.radius,
color: '#ff0000',
}
],
}
})
}
})
},
diffusedLightWave: () => {
let draw = new YJ.Draw.DrawCircle(window.earth)
draw.start((err, options) => {
console.log('options', options)
if (options) {
let id = new YJ.Tools().randomString()
let name = '雷达光波'
addMapSource({
type: 'radarScan',
id: id,
sourceName: name,
opt: {
id: id,
name: name,
lng: options.center.lng,
lat: options.center.lat,
radius: options.radius
}
})
}
})
},
@ -190,14 +231,14 @@ const methodMap = {
eventBus.emit('routePlanningDialog')
},
//路径清除
clearRoute() {},
clearRoute() { },
//涂鸦
graffiti() {
eventBus.emit('graffitiDialog')
},
//涂鸦清除
clearGraffiti() {
graffitiObjArr.forEach((item) => {
graffitiObjArr.forEach((item: any) => {
item.remove()
})
},
@ -230,7 +271,7 @@ const methodMap = {
// }
},
//屏幕截图
screenShot() {},
screenShot() { },
//高清出图
highQuality() {
// eventBus.emit('screenShotDialog')
@ -241,25 +282,25 @@ const methodMap = {
clickChange.videoRecord = !clickChange.videoRecord
},
//压模
pressModel() {},
pressModel() { },
//地形开挖
terrainDig() {
eventBus.emit('terrainExcavationDialog')
},
//剖切
tilesetClipping() {},
tilesetClipping() { },
//删除剖切
clearTilesetClipping() {},
clearTilesetClipping() { },
//度分秒
projConvert() {},
projConvert() { },
//投影转换
projectionConvert() {},
projectionConvert() { },
//GDB导入
gdbImport() {},
gdbImport() { },
//圆形统计
circleStatistics() {},
circleStatistics() { },
//多边形统计
polygonStatistics() {}
polygonStatistics() { }
}
const handleClick = (value = 'projectionDistanceMeasure') => {

View File

@ -122,6 +122,7 @@
<use xlink:href="#yj-icon-py"></use>
</svg>平移</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
@ -318,6 +319,11 @@ const close = () => {
baseDialog.value?.close()
}
const remove = () => {
that.remove()
close()
}
watch(
() => areaUnit.value,
(val) => {
@ -329,7 +335,8 @@ watch(
);
defineExpose({
open
open,
close
})
</script>

View File

@ -14,7 +14,7 @@ import { ref } from 'vue'
import { inject } from 'vue'
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import { initMapData } from '../tree/initMapData'
import { initMapData } from '../../../common/initMapData'
import { useTreeNode } from '../tree/hooks/treeNode'
const { cusAddNodes } = useTreeNode()
@ -45,20 +45,28 @@ const confirm = () => {
})
delete options.host
delete options.positions
console.log('options', options)
let selectedNodes = window.treeObj.getSelectedNodes()
let params = {
let node = selectedNodes && selectedNodes[selectedNodes.length - 1]
let parentId
if (node) {
if (node.sourceType === 'directory') {
parentId = node.id
}
else {
parentId = node.parentId
}
}
let params: any = {
id: id,
sourceName: name,
sourceType: 'groundText',
parentId:
selectedNodes && selectedNodes[selectedNodes.length - 1]
? selectedNodes[selectedNodes.length - 1].id
: undefined,
parentId: parentId,
// "treeIndex": 0,
params: options
}
TreeApi.addOtherSource(params)
params.params = JSON.stringify(params.params)
params.isShow = true
cusAddNodes(window.treeObj, params.parentId, [params])
})
}

View File

@ -14,7 +14,10 @@ import { ref } from 'vue'
import { inject } from 'vue'
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import { initMapData } from '../tree/initMapData'
import { initMapData } from '../../../common/initMapData'
import { useTreeNode } from '../tree/hooks/treeNode'
const { cusAddNodes } = useTreeNode()
const baseDialog: any = ref(null)
const eventBus: any = inject('bus')
@ -42,19 +45,30 @@ const confirm = () => {
})
delete options.host
console.log('options', options)
// let selectedNodes = window.treeObj.getSelectedNodes()
// let params = {
// id: id,
// sourceName: name,
// sourceType: 'standText',
// parentId:
// selectedNodes && selectedNodes[selectedNodes.length - 1]
// ? selectedNodes[selectedNodes.length - 1].id
// : undefined,
// // "treeIndex": 0,
// params: options
// }
// TreeApi.addOtherSource(params)
let selectedNodes = window.treeObj.getSelectedNodes()
let node = selectedNodes && selectedNodes[selectedNodes.length - 1]
let parentId
if (node) {
if (node.sourceType === 'directory') {
parentId = node.id
}
else {
parentId = node.parentId
}
}
let params:any = {
id: id,
sourceName: name,
sourceType: 'standText',
parentId: parentId,
// "treeIndex": 0,
params: options
}
TreeApi.addOtherSource(params)
params.params = JSON.stringify(params.params)
params.isShow = true
cusAddNodes(window.treeObj, params.parentId, [params])
})
}
defineExpose({
@ -62,4 +76,4 @@ defineExpose({
})
</script>
<style scoped lang="scss"></style>
<style scoped lang="scss"></style>

View File

@ -145,6 +145,7 @@
<use xlink:href="#yj-icon-py"></use>
</svg>平移</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
@ -360,8 +361,14 @@ watch(
{ immediate: true }
);
const remove = () => {
that.remove()
close()
}
defineExpose({
open
open,
close
})
</script>

View File

@ -3,18 +3,8 @@
<div class="row">
<div class="col attribute-select-box">
<span class="label" style="line-height: 32px">内容类型</span>
<el-select
style="width: 175px"
v-model="attributeType"
@change="attributeChange"
placeholder="请选择"
>
<el-option
v-for="item in attributeSelect"
:key="item.key"
:label="item.name"
:value="item.key"
>
<el-select style="width: 175px" v-model="attributeType" @change="attributeChange" placeholder="请选择">
<el-option v-for="item in attributeSelect" :key="item.key" :label="item.name" :value="item.key">
</el-option>
</el-select>
</div>
@ -45,7 +35,7 @@
<div class="th">操作</div>
</div>
</div>
<div class="table-body" v-if="attribute.link.content && attribute.link.content.length > 0">
<div class="table-body" v-if="attribute.link && attribute.link.content && attribute.link.content.length > 0">
<div class="tr" v-for="(item, index) in attribute.link.content">
<div class="td" v-if="linkEditActive.index === index">
<input class="input" type="text" v-model="linkEditActive.name" />
@ -75,7 +65,7 @@
<div class="row">
<div class="col">
<span class="label">编辑内容</span>
<input class="input" type="text" @model="cameraName" style="width: 100px" />
<input class="input" type="text" v-model="cameraName" style="width: 100px" />
<button class="select btn" @click="cameraSelect">搜索</button>
</div>
</div>
@ -157,7 +147,7 @@
<div class="col">
<span class="label">添加链接</span>
<div style="flex: 1; position: relative">
<input class="input vr_add" type="text" />
<input class="input vr_add" type="text" v-model="addvrInput" />
<i class="vr_add_btn" @click="_addRr"></i>
</div>
</div>
@ -171,48 +161,32 @@
<div class="th">操作</div>
</div>
</div>
<div class="table-body"></div>
<div class="table-empty">
<div class="table-body" v-if="attribute.vr && attribute.vr.content && attribute.vr.content.length > 0">
<div class="tr" v-for="(item, index) in attribute.vr.content">
<div class="td" v-if="vrEditActive.index === index">
<input class="input" type="text" v-model="vrEditActive.name" />
</div>
<div class="td" v-else>{{ item.name }}</div>
<div class="td" v-if="vrEditActive.index === index">
<textarea class="input link-edit" type="text" v-model="vrEditActive.url"></textarea>
</div>
<div class="td" v-else>{{ item.url }}</div>
<div class="td" v-if="vrEditActive.index === index">
<button @click="vrConfirmEdit(index)">确认</button>
<button @click="vrCancelEdit">取消</button>
</div>
<div class="td" v-else>
<button @click="vrEdit(index, item)">编辑</button>
<button @click="vrDelete(index)">删除</button>
</div>
</div>
</div>
<div class="table-empty" v-else>
<div class="empty-img"></div>
<p>暂无数据</p>
</div>
</div>
</div>
<div class="attribute-content attribute-content-goods" v-show="attributeType === 'goods'">
<div>
<div class="row">
<div class="col">
<span class="label">编辑内容</span>
<input
class="input goods-select-input"
type="text"
style="width: 180px; margin-right: 10px"
/>
<button class="select btn" @click="goodsFilter">搜索</button>
</div>
</div>
<div class="table goods-table">
<div class="table-head">
<div class="tr">
<div class="th" style="width: 60px; flex: 0 60px; min-width: 60px">序号</div>
<div class="th" style="flex: 0 0 280px">名称</div>
<div class="th">数量</div>
</div>
</div>
<div class="table-body" style="display: none">
<div class="tr">
<div class="td" style="width: 60px; flex: 0 60px; min-width: 60px">序号</div>
<div class="td" style="flex: 0 0 280px">名称</div>
<div class="td">数量</div>
</div>
</div>
<div class="table-empty">
<div class="empty-img"></div>
<p>暂无数据</p>
</div>
</div>
</div>
</div>
</div>
</template>
@ -220,6 +194,11 @@
import { ref } from 'vue'
import { inject } from 'vue'
let ipcRenderer;
if (window && window.process && window.process.type === 'renderer') {
ipcRenderer = require('electron').ipcRenderer
}
const baseDialog: any = ref(null)
const eventBus: any = inject('bus')
const attributeType = ref('richText')
@ -232,9 +211,10 @@ const props = defineProps({
})
const attribute = ref(props.entityOptions.options.attribute)
props.entityOptions.options.richTextContent = ''
const richTextContent = ref(props.entityOptions.options.richTextContent)
const attributeSelect = ref([
let attributeSelect = ref([
{
name: '富文本',
value: '富文本',
@ -245,43 +225,53 @@ const attributeSelect = ref([
value: '链接',
key: 'link'
}
// {
// name: 'IP摄像头',
// value: 'IP摄像头',
// key: 'camera'
// },
// {
// name: 'ISC摄像头',
// value: 'ISC摄像头',
// key: 'isc'
// },
// {
// name: '传感器',
// value: '传感器',
// key: 'sensor'
// },
// {
// name: '全景图',
// value: '全景图',
// key: 'vr'
// },
// {
// name: '物资',
// value: '物资',
// key: 'goods'
// },
])
if (props.entityOptions.type === 'BillboardObject') {
attributeSelect.value.push(
// {
// name: 'IP摄像头',
// value: 'IP摄像头',
// key: 'camera'
// },
// {
// name: 'ISC摄像头',
// value: 'ISC摄像头',
// key: 'isc'
// },
// {
// name: '传感器',
// value: '传感器',
// key: 'sensor'
// },
{
name: '全景图',
value: '全景图',
key: 'vr'
},
// {
// name: '物资',
// value: '物资',
// key: 'goods'
// },
)
}
const cameraName = ref('')
const addlinkInput = ref('')
const addvrInput = ref('')
const linkEditActive: any = ref({})
const vrEditActive: any = ref({})
const openRichTextEditor = () => {
eventBus.emit('openRichText', props.entityOptions.name, richTextContent.value, (val) => {
eventBus.emit('openRichText', props.entityOptions.name, richTextContent.value, (val: any) => {
richTextContent.value = val
props.entityOptions.options.richTextContent = richTextContent.value
})
}
const _addLink = () => {
const _addLink = async () => {
if (addlinkInput.value) {
let link = {
name: '链接',
@ -290,18 +280,77 @@ const _addLink = () => {
attribute.value.link.content.push(link)
addlinkInput.value = ''
} else {
document.getElementById('fileInputlink')?.click()
eventBus.emit('defineClickAddLinkCb', (list) => {
list.forEach((item) => {
attribute.value.link.content.push({
name: '链接',
url: item.previewUrl
})
})
})
const options = {
properties: ['openFile', 'multiSelections'], // 允许选择多个文件
filters: [
{ name: '图片', extensions: ['jpg', 'jpeg', 'png', 'webp', 'svg', 'bmp'] },
{ name: '音视频', extensions: ['mp4', 'mp3'] },
{ name: 'pdf', extensions: ['pdf'] },
]
};
if (ipcRenderer) {
ipcRenderer.send('open-directory-dialog', options);
// 监听主进程返回的结果
ipcRenderer.once('selectedItem', (event, filePaths) => {
if (filePaths.length > 0) {
filePaths.forEach((item) => {
attribute.value.link.content.push({
name: '链接',
url: item
})
})
}
});
}
else {
// const pickerOpts = {
// types: [
// {
// description: '图片',
// accept:
// {
// 'image/jpg': ['.jpg', '.jpeg'],
// 'image/gif': ['.gif'],
// 'image/webp': ['.webp'],
// 'image/png': ['.png'],
// 'image/svg+xml': ['.svg'],
// 'image/x-ms-bmp': ['.bmp'],
// }
// },
// {
// description: '音视频',
// accept:
// {
// 'video/mp4': ['.mp4'],
// 'audio/mpeg': ['.mp3'],
// }
// },
// {
// description: 'pdf',
// accept:
// {
// 'application/pdf': ['.pdf'],
// }
// }
// ],
// excludeAcceptAllOption: true,
// multiple: true
// };
// if ((window as any).showOpenFilePicker) {
// const fileHandles = await (window as any).showOpenFilePicker(pickerOpts);
// // const files = await Promise.all(fileHandles.map(fileHandle => fileHandle.getFile()));
// // const dataTransfer = new DataTransfer();
// // handleFileImgInput(files, parentId, 'vr')
// }
}
// $sendElectronChanel('open-directory-dialog', (a: any,b: any)=>{
// console.log(a,b)
// })
}
}
const linkEdit = (index, item) => {
const linkEdit = (index: any, item: { name: any; url: any; }) => {
let active = {
index: index,
name: item.name,
@ -309,20 +358,76 @@ const linkEdit = (index, item) => {
}
linkEditActive.value = active
}
const linkDelete = (index) => {
const linkDelete = (index: any) => {
attribute.value.link.content.splice(index, 1)
}
const linkConfirmEdit = (index) => {
const linkConfirmEdit = (index: string | number) => {
attribute.value.link.content[index] = linkEditActive.value
linkEditActive.value = {}
}
const linkCancelEdit = () => {
linkEditActive.value = {}
}
const cameraSelect = () => {}
const _addRr = () => {}
const goodsFilter = () => {}
const attributeChange = () => {}
const cameraSelect = () => { }
const _addRr = () => {
if (addvrInput.value) {
let link = {
name: '全景图',
url: addvrInput.value
}
attribute.value.vr.content.push(link)
addvrInput.value = ''
} else {
const options = {
properties: ['openFile', 'multiSelections'],
filters: [
{ name: '全景图', extensions: ['jpg'] },
]
};
ipcRenderer.send('open-directory-dialog', options);
// 监听主进程返回的结果
ipcRenderer.once('selectedItem', (event, filePaths) => {
if (filePaths.length > 0) {
filePaths.forEach((item) => {
attribute.value.link.content.push({
name: '全景图',
url: item
})
})
}
});
// document.getElementById('fileInputlink')?.click()
// eventBus.emit('defineClickAddLinkCb', (list: any[]) => {
// list.forEach((item: { previewUrl: any; }) => {
// attribute.value.vr.content.push({
// name: '全景图',
// url: item.previewUrl
// })
// })
// })
}
}
const vrEdit = (index: any, item: { name: any; url: any; }) => {
let active = {
index: index,
name: item.name,
url: item.url
}
vrEditActive.value = active
}
const vrDelete = (index: any) => {
attribute.value.vr.content.splice(index, 1)
}
const vrConfirmEdit = (index: string | number) => {
attribute.value.vr.content[index] = vrEditActive.value
vrEditActive.value = {}
}
const vrCancelEdit = () => {
vrEditActive.value = {}
}
const goodsFilter = () => { }
const attributeChange = () => { }
</script>
<style scoped lang="scss"></style>

View File

@ -445,11 +445,11 @@
<div style="position: absolute; left: 24px; display: flex">
<button @click="updateHeight">
<svg class="icon-updateheigh">
<use xlink:href="#yj-icon-updateheight"></use></svg
>更新高程
<use xlink:href="#yj-icon-updateheight"></use></svg>更新高程
</button>
<button style="margin-left: 10px" @click="translate">平移</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
@ -770,8 +770,14 @@ const fontChange = (val) => {
entityOptions.value.labelFontFamily = val
}
const remove = () => {
that.remove()
close()
}
defineExpose({
open
open,
close
})
</script>

View File

@ -0,0 +1,298 @@
<template>
<Dialog ref="baseDialog" title="扩散光波属性" left="180px" top="100px" className="circle-ciffuse"
:closeCallback="closeCallback">
<template #content>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">名称</span>
<input class="input" maxlength="40" type="text" v-model="entityOptions.name">
</div>
<div class="col">
<span class="label">透明度</span>
<input type="range" min="0" max="1" step="0.01" v-model="entityOptions.transparency">
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">经度</span>
<input class="input" type="number" title="" min="-180" max="180" v-model="entityOptions.lng">
</div>
<div class="col">
<span class="label">波纹层数</span>
<div class="input-number input-number-unit">
<input class="input" type="number" title="" min="1" max="10" v-model="entityOptions.count">
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">纬度</span>
<input class="input" type="number" title="" min="-180" max="180" v-model="entityOptions.lat">
</div>
<div class="col">
<span class="label">扩散速度</span>
<div class="input-number input-number-unit">
<input class="input" type="number" title="" min="0" max="20" v-model="entityOptions.speed">
<span class="arrow"></span>
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col input-radius-unit-box" style="margin: 0;">
<span class="label">半径单位</span>
<el-select v-model="radiusUnit" @change="changeRadiusUnit">
<el-option label="米" value="m"></el-option>
<el-option label="千米" value="km"></el-option>
</el-select>
</div>
<div class="col" style="margin: 0;">
</div>
<div class="col" style="margin: 0;">
</div>
</div>
<div class="row circle-content-box">
<div class="row" v-for="(item, index) in circle" :key="index">
<div class="col">
<span class="label">半径</span>
<input class="input" type="number" title="" min="0" max="999999" v-model="item.radius"
@input="changeRadius(index)">
</div>
<div class="col" style="flex-direction: row-reverse;">
<div class="color" :ref="el => colorRefs[index] = el"></div>
<span class="label">扩散颜色</span>
</div>
<div class="col" style="flex-direction: row-reverse;">
<button class="circle-add" style="margin-left: 5px;" @click="addCircle"
v-show="index == circle.length - 1"><svg class="icon-add2">
<use xlink:href="#yj-icon-add2"></use>
</svg></button>
<button class="circle-minus" @click="minusCircle(index)" v-show="circle.length != 1">
<svg class="icon-minus">
<use xlink:href="#yj-icon-minus"></use>
</svg></button>
</div>
</div>
</div>
</div>
<div class="div-item">
<div class="row">
<el-tabs v-model="activeName">
<el-tab-pane label="属性信息" name="1">
<attribute :entityOptions="entityOptions"></attribute>
</el-tab-pane>
<el-tab-pane label="标签风格" name="2">
<labelStyle :entityOptions="entityOptions"></labelStyle>
</el-tab-pane>
</el-tabs>
</div>
</div>
<span class="custom-divider"></span>
</template>
<template #footer>
<div style="position: absolute; left: 24px; display: flex;">
<button style="margin-left: 10px" @click="translate">平移</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { inject } from "vue";
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import attribute from './attribute.vue'
import labelStyle from './labelStyle.vue'
import { useTreeNode } from '@/views/components/tree/hooks/treeNode'
const { cusUpdateNode } = useTreeNode()
const baseDialog: any = ref(null);
const eventBus: any = inject("bus");
eventBus.on("openStandTextAdd", () => {
baseDialog.value?.open()
});
const radiusUnit = ref('m')
const activeName = ref('1')
const entityOptions: any = ref({});
let originalOptions: any
let that: any
const circle:any = ref([])
const colorRefs = ref<(Element | ComponentPublicInstance | null)[]>([])
const open = async (id: any) => {
that = window.earth.entityMap.get(id)
originalOptions = structuredClone(that.options)
entityOptions.value = that
circle.value = structuredClone(that.options.circle)
baseDialog.value?.open()
await nextTick()
for (let i = 0; i < colorRefs.value.length; i++) {
let colorPicker = new window.YJColorPicker({
el: colorRefs.value[i],
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: entityOptions.value.options.circle[i].color,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: color => {
entityOptions.value.options.circle[i].color = color
circle.value[i].color = color
entityOptions.value.circle = entityOptions.value.options.circle
}, //点击确认按钮事件回调
clear: () => {
entityOptions.value.options.circle[i].color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
}
}
const addCircle = async () => {
circle.value.push({
radius: 0,
color: entityOptions.value.options.color
})
entityOptions.value.options.circle.push({
radius: 0,
color: entityOptions.value.options.color
})
entityOptions.value.circle = entityOptions.value.options.circle
await nextTick()
for (let i = 0; i < colorRefs.value.length; i++) {
let colorPicker = new window.YJColorPicker({
el: colorRefs.value[i],
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: entityOptions.value.options.circle[i].color,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: color => {
entityOptions.value.options.circle[i].color = color
circle.value[i].color = color
entityOptions.value.circle = entityOptions.value.options.circle
}, //点击确认按钮事件回调
clear: () => {
entityOptions.value.options.circle[i].color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
}
}
const minusCircle = async (index) => {
circle.value.splice(index, 1)
entityOptions.value.options.circle.splice(index, 1)
entityOptions.value.circle = entityOptions.value.options.circle
await nextTick()
for (let i = 0; i < colorRefs.value.length; i++) {
let colorPicker = new window.YJColorPicker({
el: colorRefs.value[i],
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: entityOptions.value.options.circle[i].color,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: color => {
entityOptions.value.options.circle[i].color = color
circle.value[i].color = color
entityOptions.value.circle = entityOptions.value.options.circle
}, //点击确认按钮事件回调
clear: () => {
entityOptions.value.options.circle[i].color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
}
}
const changeRadius = async (index) => {
let newCircle = JSON.parse(JSON.stringify(circle.value))
if (radiusUnit.value == 'km') {
for (let i = 0; i < newCircle.length; i++) {
newCircle[i].radius = newCircle[i].radius * 1000
}
}
entityOptions.value.circle = newCircle
await nextTick()
for (let i = 0; i < colorRefs.value.length; i++) {
let colorPicker = new window.YJColorPicker({
el: colorRefs.value[i],
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: entityOptions.value.options.circle[i].color,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: color => {
entityOptions.value.options.circle[i].color = color
circle.value[i].color = color
entityOptions.value.circle = entityOptions.value.options.circle
}, //点击确认按钮事件回调
clear: () => {
entityOptions.value.options.circle[i].color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
}
}
const changeRadiusUnit = () => {
if (radiusUnit.value == 'm') {
for (let i = 0; i < circle.value.length; i++) {
circle.value[i].radius = circle.value[i].radius * 1000
}
}
else {
for (let i = 0; i < circle.value.length; i++) {
circle.value[i].radius = circle.value[i].radius / 1000
}
}
}
const confirm = () => {
originalOptions = structuredClone(that.options)
baseDialog.value?.close()
let params = structuredClone(that.options)
// 删除不必要的属性
delete params.host
console.log('params', params)
let params2 = {
"id": params.id,
"sourceName": params.name,
"params": params,
"isShow": params.show ? 1 : 0,
}
TreeApi.updateDirectoryInfo(params2)
cusUpdateNode({ "id": params.id, "sourceName": params.name, "params": JSON.stringify(params) })
}
const close = () => {
baseDialog.value?.close()
}
const remove = () => {
entityOptions.value.remove()
close()
}
const translate = () => {
that.openPositionEditing(() => {
entityOptions.value.lng = that.lng
entityOptions.value.lat = that.lat
})
}
const closeCallback = () => {
entityOptions.value.originalOptions = structuredClone(originalOptions)
that.positionEditing = false
that.reset()
eventBus?.emit("destroyComponent")
}
defineExpose({
open,
close
})
</script>
<style scoped lang="scss"></style>

View File

@ -272,11 +272,11 @@
<div style="position: absolute; left: 24px; display: flex">
<button @click="nodeEdit">
<svg class="icon-edit">
<use xlink:href="#yj-icon-edit"></use></svg
>二次编辑
<use xlink:href="#yj-icon-edit"></use></svg>二次编辑
</button>
<button style="margin-left: 10px" @click="translate">平移</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
@ -288,7 +288,6 @@ import { ref, getCurrentInstance } from 'vue'
import { inject } from 'vue'
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import { initMapData } from '../tree/initMapData'
import { getFontList } from './fontSelect'
import attribute from './attribute.vue'
import labelStyle from './labelStyle.vue'
@ -546,6 +545,11 @@ const close = () => {
baseDialog.value?.close()
}
const remove = () => {
that.remove()
close()
}
watch(
() => lengthUnit.value,
(val) => {
@ -560,7 +564,8 @@ watch(
{ immediate: true }
)
defineExpose({
open
open,
close
})
</script>
@ -588,4 +593,4 @@ defineExpose({
}
}
}
</style>
</style>

View File

@ -87,7 +87,6 @@ import { ref } from 'vue';
import { inject } from "vue";
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import { initMapData } from '../tree/initMapData'
import { useTreeNode } from '@/views/components/tree/hooks/treeNode'
const { cusUpdateNode } = useTreeNode()
@ -158,7 +157,8 @@ const closeCallback = () => {
}
defineExpose({
open
open,
close
})
</script>

View File

@ -0,0 +1,96 @@
<template>
<Dialog ref="baseDialog" title="底图属性" left="calc(50% - 160px)" top="calc(50% - 120px)" :closeCallback="closeCallback">
<template #content>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">名称</span>
<input class="input" v-model="entityOptions.name">
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">透视</span>
<input type="range" min="0" max="1" step="0.01" v-model="entityOptions.alpha">
</div>
</div>
</div>
</template>
<template #footer>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { inject } from 'vue'
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import { useTreeNode } from '../tree/hooks/treeNode'
const { cusUpdateNode } = useTreeNode()
const baseDialog: any = ref(null)
const eventBus: any = inject('bus')
const text = ref('')
eventBus.on('openStandTextAdd', () => {
baseDialog.value?.open()
})
const entityOptions: any = ref({});
let originalOptions: any
let that: any
const closeCallback = () => {
entityOptions.value.originalOptions = structuredClone(originalOptions)
that.positionEditing = false
entityOptions.value.reset()
eventBus.emit("destroyComponent")
}
const open = async (id: any) => {
that = window.earth.entityMap.get(id)
originalOptions = structuredClone(that.options)
entityOptions.value = that
baseDialog.value?.open()
await nextTick()
}
const confirm = () => {
originalOptions = structuredClone(that.options)
baseDialog.value?.close()
let params = {
alpha: entityOptions.value.alpha,
brightness: entityOptions.value.brightness,
name: entityOptions.value.name,
show: entityOptions.value.show,
id: entityOptions.value.id,
}
// 删除不必要的属性
delete params.host
let params2 = {
"id": params.id,
"sourceName": params.name,
"params": params,
"isShow": params.show ? 1 : 0
}
TreeApi.updateDirectoryInfo(params2)
cusUpdateNode({ "id": params.id, "sourceName": params.name, "params": JSON.stringify(params) })
}
const close = () => {
baseDialog.value?.close()
}
const remove = () => {
that.remove()
close()
}
defineExpose({
open,
close
})
</script>
<style scoped lang="scss"></style>

View File

@ -122,6 +122,7 @@
<use xlink:href="#yj-icon-py"></use>
</svg>平移</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
@ -325,6 +326,11 @@ const close = () => {
baseDialog.value?.close()
}
const remove = () => {
that.remove()
close()
}
watch(
() => areaUnit.value,
(val) => {
@ -336,7 +342,8 @@ watch(
);
defineExpose({
open
open,
close
})
</script>

View File

@ -277,15 +277,14 @@
<div style="position: absolute; left: 24px; display: flex">
<button @click="nodeEdit">
<svg class="icon-edit">
<use xlink:href="#yj-icon-edit"></use></svg
>二次编辑
<use xlink:href="#yj-icon-edit"></use></svg>二次编辑
</button>
<button style="margin-left: 10px" @click="translate">
<svg class="icon-py">
<use xlink:href="#yj-icon-py"></use></svg
>平移
<use xlink:href="#yj-icon-py"></use></svg>平移
</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
@ -553,6 +552,11 @@ const close = () => {
baseDialog.value?.close()
}
const remove = () => {
that.remove()
close()
}
watch(
() => lengthUnit.value,
(val) => {
@ -567,7 +571,8 @@ watch(
{ immediate: true }
)
defineExpose({
open
open,
close
})
</script>

View File

@ -0,0 +1,179 @@
<template>
<Dialog ref="baseDialog" title="雷达光波属性" left="180px" top="100px" className="circle-ciffuse"
:closeCallback="closeCallback">
<template #content>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">名称</span>
<input class="input" maxlength="40" type="text" v-model="entityOptions.name">
</div>
<div class="col">
<span class="label">扫描颜色</span>
<div class="color" ref="colorRef"></div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">经度</span>
<input class="input" type="number" title="" min="-180" max="180" v-model="entityOptions.lng">
</div>
<div class="col">
<span class="label">扫描半径</span>
<div class="input-number input-number-unit-2 input-radius">
<input class="input" type="number" title="" data-min="0.1" max="999999" v-model="radius" @input="changeRadius">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
<el-select v-model="radiusUnit" @change="changeRadiusUnit">
<el-option label="米" value="m"></el-option>
<el-option label="千米" value="km"></el-option>
</el-select>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">纬度</span>
<input class="input" type="number" title="" min="-90" max="90" v-model="entityOptions.lat">
</div>
<div class="col">
<span class="label">扫描速度</span>
<input class="input" type="number" title="" min="0" max="100" v-model="entityOptions.speed">
</div>
</div>
</div>
<div class="div-item">
<div class="row">
<el-tabs v-model="activeName">
<el-tab-pane label="属性信息" name="1">
<attribute :entityOptions="entityOptions"></attribute>
</el-tab-pane>
<el-tab-pane label="标签风格" name="2">
<labelStyle :entityOptions="entityOptions"></labelStyle>
</el-tab-pane>
</el-tabs>
</div>
</div>
<span class="custom-divider"></span>
</template>
<template #footer>
<div style="position: absolute; left: 24px; display: flex;">
<button style="margin-left: 10px" @click="translate">平移</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { inject } from "vue";
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import attribute from './attribute.vue'
import labelStyle from './labelStyle.vue'
import { useTreeNode } from '@/views/components/tree/hooks/treeNode'
const { cusUpdateNode } = useTreeNode()
const baseDialog: any = ref(null);
const eventBus: any = inject("bus");
eventBus.on("openStandTextAdd", () => {
baseDialog.value?.open()
});
const radiusUnit = ref('m')
const activeName = ref('1')
const radius = ref(0)
const entityOptions: any = ref({});
let originalOptions: any
let that: any
const colorRef = ref(null)
const open = async (id: any) => {
that = window.earth.entityMap.get(id)
originalOptions = structuredClone(that.options)
entityOptions.value = that
radius.value = entityOptions.value.radius
baseDialog.value?.open()
await nextTick()
let colorPicker = new window.YJColorPicker({
el: colorRef.value,
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: entityOptions.value.color,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: color => {
entityOptions.value.color = color
}, //点击确认按钮事件回调
clear: () => {
entityOptions.value.color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
}
const confirm = () => {
originalOptions = structuredClone(that.options)
baseDialog.value?.close()
let params = structuredClone(that.options)
// 删除不必要的属性
delete params.host
console.log('params', params)
let params2 = {
"id": params.id,
"sourceName": params.name,
"params": params,
"isShow": params.show ? 1 : 0,
}
TreeApi.updateDirectoryInfo(params2)
cusUpdateNode({ "id": params.id, "sourceName": params.name, "params": JSON.stringify(params) })
}
const close = () => {
baseDialog.value?.close()
}
const remove = () => {
entityOptions.value.remove()
close()
}
const changeRadius = (val)=>{
if (radiusUnit.value == 'km') {
entityOptions.value.radius = radius.value * 1000
}
else {
entityOptions.value.radius = radius.value
}
}
const changeRadiusUnit = () => {
if (radiusUnit.value == 'm') {
radius.value = radius.value * 1000
}
else {
radius.value = radius.value / 1000
}
}
const translate = () => {
that.openPositionEditing(() => {
entityOptions.value.lng = that.lng
entityOptions.value.lat = that.lat
})
}
const closeCallback = () => {
entityOptions.value.originalOptions = structuredClone(originalOptions)
that.positionEditing = false
that.reset()
eventBus?.emit("destroyComponent")
}
defineExpose({
open,
close
})
</script>
<style scoped lang="scss"></style>

View File

@ -1,5 +1,5 @@
<template>
<Dialog ref="baseDialog" title="立体t文字属性" left="180px" top="100px" className="ground-text"
<Dialog ref="baseDialog" title="立体文字属性" left="180px" top="100px" className="ground-text"
:closeCallback="closeCallback">
<template #content>
<span class="custom-divider"></span>
@ -61,7 +61,6 @@ let originalOptions: any
let that: any
const colorRef = ref(null)
const open = async (id: any) => {
id = (window as any).standTextid
that = window.earth.entityMap.get(id)
originalOptions = structuredClone(that.options)
entityOptions.value = that
@ -91,12 +90,12 @@ const confirm = () => {
delete params.name
let params2 = {
"id": params.id,
"sourceName": params.name,
"sourceName": params.text,
"params": params,
"isShow": params.show ? 1 : 0,
}
TreeApi.updateDirectoryInfo(params2)
cusUpdateNode({ "id": params.id, "sourceName": params.name, "params": JSON.stringify(params) })
cusUpdateNode({ "id": params.id, "sourceName": params.text, "params": JSON.stringify(params) })
}
const close = () => {
baseDialog.value?.close()
@ -117,7 +116,8 @@ const closeCallback = () => {
}
defineExpose({
open
open,
close
})
</script>

View File

@ -0,0 +1,108 @@
<template>
<Dialog ref="baseDialog" title="倾斜摄影属性" left="calc(50% - 160px)" top="calc(50% - 120px)" :closeCallback="closeCallback">
<template #content>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">名称</span>
<input class="input" v-model="entityOptions.name">
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">高度</span>
<div class="input-number input-number-unit-3">
<input class="input" type="number" title="" v-model="entityOptions.height">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
<span class="label">精度</span>
<div class="input-number input-number-unit-3">
<input class="input" type="number" title="" min="0.1" max="10" step="0.1" v-model="entityOptions.accuracy">
<span class="unit"></span>
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">透视</span>
<input type="range" min="0" max="1" step="0.01" v-model="entityOptions.transparency">
</div>
</div>
</div>
</template>
<template #footer>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { inject } from 'vue'
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import { useTreeNode } from '../tree/hooks/treeNode'
const { cusUpdateNode } = useTreeNode()
const baseDialog: any = ref(null)
const eventBus: any = inject('bus')
const text = ref('')
eventBus.on('openStandTextAdd', () => {
baseDialog.value?.open()
})
const entityOptions: any = ref({});
let originalOptions: any
let that: any
const closeCallback = () => {
entityOptions.value.originalOptions = structuredClone(originalOptions)
that.positionEditing = false
entityOptions.value.reset()
eventBus.emit("destroyComponent")
}
const open = async (id: any) => {
that = window.earth.entityMap.get(id)
originalOptions = structuredClone(that.options)
entityOptions.value = that
baseDialog.value?.open()
await nextTick()
}
const confirm = () => {
originalOptions = structuredClone(that.options)
baseDialog.value?.close()
let params = structuredClone(that.options)
// 删除不必要的属性
delete params.host
let params2 = {
"id": params.id,
"sourceName": params.text,
"params": params,
"isShow": params.show ? 1 : 0,
}
TreeApi.updateDirectoryInfo(params2)
cusUpdateNode({ "id": params.id, "sourceName": params.name, "params": JSON.stringify(params) })
}
const close = () => {
baseDialog.value?.close()
}
const remove = () => {
that.remove()
close()
}
defineExpose({
open,
close
})
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,307 @@
<template>
<Dialog ref="baseDialog" title="轨迹运动属性" left="calc(50% - 160px)" top="calc(50% - 120px)" className="trajectory-motion"
:closeCallback="closeCallback">
<template #content>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 70px;">名称</span>
<input class="input" maxlength="40" type="text" v-model="entityOptions.name">
</div>
<div class="col"></div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 70px;">起始点高度</span>
<div class="input-number input-number-unit-1 height-box">
<input class="input" type="number" title="" min="-9999999" max="999999999" v-model="entityOptions.height">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
<span class="label">模型倍数</span>
<div class="input-number input-number-unit-2">
<input class="input" type="number" title="" min="0" max="99999" step="1" v-model="entityOptions.scale">
<span class="unit"></span>
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 70px;">运行速度</span>
<div class="input-number input-number-unit-3">
<input class="input" type="number" title="" min="0" max="99999999" step="1" v-model="entityOptions.speed">
<span class="unit">m/s</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
<span class="label">延迟运动</span>
<div class="input-number input-number-unit-3">
<input class="input" type="number" title="" min="0" max="9999999" v-model="entityOptions.delay">
<span class="unit">ms</span>
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 70px;">更换模型</span>
<button class="btn" @click="clickChangeModel">选择</button>
</div>
<div class="col">
<span class="label">模型方向</span>
<button class="btn model-rotate-btn" @click="modelRotate">开始调整</button>
<svg class="icon-rubric" @mouseover="handleMouseOver" @mouseout="handleMouseOut">
<use xlink:href="#yj-icon-rubric"></use>
</svg>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<div class="btn-group">
<button class="btn" :class="{ 'is-active': entityOptions.firstPersonView }"
style="border-radius: 5px 0 0 5px;" name="firstPerson" data-state="true"
@click="changeFirstPersonView(true)"><span>第一视角</span></button>
<button class="btn" :class="{ 'is-active': !entityOptions.firstPersonView }"
style="border-radius: 0 5px 5px 0;" name="firstPerson" data-state="false"
@click="changeFirstPersonView(false)"><span>第三视角</span></button>
</div>
</div>
</div>
</div>
<div class="div-item div-item-switch">
<div class="row">
<div class="col">
<span class="label">路径显隐</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.lineShow">
</div>
<div class="col">
<span class="label">模型显隐</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.modelShow">
</div>
<div class="col">
<span class="label">实时路径</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.realTimeRoute">
</div>
</div>
<div class="row">
<div class="col">
<span class="label">编辑</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.lineEdit">
</div>
<div class="col">
<span class="label">路径圆滑</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.smooth">
</div>
<div class="col">
<span class="label">环线</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.noseToTail">
</div>
</div>
<div class="row">
<div class="col">
<span class="label">轨迹贴地</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.ground">
</div>
<div class="col">
<span class="label">轨迹循环</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.loop">
</div>
<div class="col">
<span class="label">轨迹动画</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.state">
</div>
</div>
<div class="row">
<div class="col">
<span class="label">路径方向</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.routeDirection">
</div>
<div class="col" style="margin-right: 33px;">
<span class="label">视角跟随</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.viewFollow">
</div>
<div class="col" style="margin: 0px;">
<span class="label">模型动画</span>
<div class="input input-select model-animate-select"></div>
<el-select class="model-animate-select" v-model="entityOptions.modelAnimate" v-if="entityOptions.model && entityOptions.model.loader && entityOptions.model.loader.components && entityOptions.model.loader.components.animations">
<el-option label="无"></el-option>
<el-option v-for="item in entityOptions.model.loader.components.animations" :label="item.name"
:value="item.name"></el-option>
</el-select>
<el-select class="model-animate-select" v-model="entityOptions.modelAnimate" v-else>
<el-option label="无"></el-option>
</el-select>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">文字开关</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.labelShow">
</div>
<div class="col"></div>
</div>
<div class="row">
<div class="col" style="flex: 0 0 120px;">
<span class="label">字体颜色</span>
<div class="labelColor" ref="labelColorRef"></div>
</div>
<div class="col font-select-box">
<span class="label" style="flex: none;">字体选择</span>
<el-select class="input input-select font-select" v-model="entityOptions.labelFontFamily">
<el-option v-for="item in fontList" :key="item.key" :label="item.name" :value="item.key">
</el-option>
</el-select>
</div>
<div class="col">
<span class="label">字体大小</span>
<div class="input-number input-number-unit-2" style="width: 82px;">
<input class="input" type="number" title="" min="1" max="99" v-model="entityOptions.labelFontSize">
<span class="unit">px</span>
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col" style="flex: 0 0 120px;">
<span class="label">视野缩放</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.labelScaleByDistance">
</div>
<div class="col">
<span class="label">最近距离</span>
<div class="input-number input-number-unit-1" style="width: 82px;">
<input class="input" type="number" title="" min="1" max="99999999" v-model="entityOptions.labelNear">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
<span class="label">最远距离</span>
<div class="input-number input-number-unit-1" style="width: 82px;">
<input class="input" type="number" title="" min="1" max="99999999" v-model="entityOptions.labelFar">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="custom-rubric-box" v-show="tip"
style="transform-origin: center bottom; position: absolute; top: 180px; right: 3px; padding: 5px 10px; background-color: rgb(62, 66, 73); border-radius: 5px; font-size: 12px; color: rgb(255, 87, 51);pointer-events: none;">
场景正东方向为轨迹前进正方向<div x-arrow="" class="custom__popper__arrow" style="left: 59px;"></div>
</div>
</template>
<template #footer>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { inject } from 'vue'
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import { useTreeNode } from '../tree/hooks/treeNode'
import { getFontList } from './fontSelect'
const { cusUpdateNode } = useTreeNode()
const baseDialog: any = ref(null)
const eventBus: any = inject('bus')
const text = ref('')
const fontList = ref(getFontList())
const labelColorRef = ref(null)
const tip = ref(false)
eventBus.on('openStandTextAdd', () => {
baseDialog.value?.open()
})
const entityOptions: any = ref({});
let originalOptions: any
let that: any
const closeCallback = () => {
entityOptions.value.originalOptions = structuredClone(originalOptions)
that.positionEditing = false
entityOptions.value.reset()
eventBus.emit("destroyComponent")
}
const open = async (id: any) => {
that = window.earth.entityMap.get(id)
originalOptions = structuredClone(that.options)
entityOptions.value = that
baseDialog.value?.open()
await nextTick()
let labelColorPicker = new (window as any).YJColorPicker({
el: labelColorRef.value,
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: entityOptions.value.labelColor,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: (color) => {
entityOptions.value.labelColor = color
}, //点击确认按钮事件回调
clear: () => {
entityOptions.value.labelColor = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
}
const confirm = () => {
originalOptions = structuredClone(that.options)
baseDialog.value?.close()
let params = structuredClone(that.options)
// 删除不必要的属性
delete params.host
delete params.label.text
let params2 = {
"id": params.id,
"sourceName": params.name,
"params": params,
"isShow": params.show ? 1 : 0
}
console.log(params)
TreeApi.updateDirectoryInfo(params2)
cusUpdateNode({ "id": params.id, "sourceName": params.name, "params": JSON.stringify(params) })
}
const close = () => {
baseDialog.value?.close()
}
const remove = () => {
that.remove()
close()
}
const clickChangeModel = () => { }
const modelRotate = () => {
that.modelRotate()
}
const changeFirstPersonView = (state) => {
entityOptions.value.firstPersonView = state
}
const handleMouseOver = () => {
tip.value = true
}
const handleMouseOut = () => {
tip.value = false
}
defineExpose({
open,
close
})
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,186 @@
<template>
<Dialog ref="baseDialog" title="电子围墙属性" left="180px" top="100px" className="wall-stereoscopic"
:closeCallback="closeCallback">
<template #content>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">名称</span>
<input class="input" maxlength="40" type="text" v-model="entityOptions.name">
</div>
<div class="col">
<span class="label">颜色</span>
<div class="color" ref="colorRef"></div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">拉伸高度</span>
<div class="input-number input-number-unit-1">
<input class="input" type="number" title="" min="0" max="999999999"
v-model="entityOptions.extrudedHeight">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col material-box">
<span class="label">材质样式</span>
<el-select class="input input-select input-select-line-type" style="margin-left: 20px"
v-model="entityOptions.material">
<el-option v-for="item in material" :key="item.key" :label="item.name" :value="item.key">
<i class="yj-custom-icon" :class="item.icon"></i>
{{ item.name }}
</el-option>
</el-select>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">墙体闭合</span>
<input class="btn-switch" type="checkbox" v-model="entityOptions.noseToTail">
</div>
<div class="col">
</div>
</div>
</div>
<div class="div-item">
<div class="row">
<el-tabs v-model="activeName">
<el-tab-pane label="属性信息" name="1">
<attribute :entityOptions="entityOptions"></attribute>
</el-tab-pane>
<el-tab-pane label="标签风格" name="2">
<labelStyle :entityOptions="entityOptions"></labelStyle>
</el-tab-pane>
</el-tabs>
</div>
</div>
<span class="custom-divider"></span>
</template>
<template #footer>
<div style="position: absolute; left: 24px; display: flex;">
<button @click="nodeEdit">
<svg class="icon-edit">
<use xlink:href="#yj-icon-edit"></use>
</svg>二次编辑
</button>
</div>
<button @click="remove">删除</button>
<button @click="confirm">确定</button>
<button @click="close">关闭</button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { inject } from "vue";
import { TreeApi } from '@/api/tree'
import Dialog from '@/components/dialog/baseDialog.vue'
import attribute from './attribute.vue'
import labelStyle from './labelStyle.vue'
import { useTreeNode } from '@/views/components/tree/hooks/treeNode'
const { cusUpdateNode } = useTreeNode()
const baseDialog: any = ref(null);
const eventBus: any = inject("bus");
const material = ref([
{
name: '纯色墙',
value: '纯色墙',
key: 0,
icon: 'icon-wall'
},
{
name: '上升墙',
value: '上升墙',
key: 1,
icon: 'icon-wall-gradient'
},
{
name: '箭头墙',
value: '箭头墙',
key: 2,
icon: 'icon-wall-arrow'
},
{
name: '警戒墙',
value: '警戒墙',
key: 3,
icon: 'icon-wall-warn'
}
])
eventBus.on("openStandTextAdd", () => {
baseDialog.value?.open()
});
const activeName = ref('1')
const entityOptions: any = ref({});
let originalOptions: any
let that: any
const colorRef = ref(null)
const open = async (id: any) => {
that = window.earth.entityMap.get(id)
originalOptions = structuredClone(that.options)
entityOptions.value = that
baseDialog.value?.open()
await nextTick()
let colorPicker = new window.YJColorPicker({
el: colorRef.value,
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: entityOptions.value.color,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: color => {
entityOptions.value.color = color
}, //点击确认按钮事件回调
clear: () => {
entityOptions.value.color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
}
const confirm = () => {
originalOptions = structuredClone(that.options)
baseDialog.value?.close()
let params = structuredClone(that.options)
// 删除不必要的属性
delete params.host
console.log('params', params)
let params2 = {
"id": params.id,
"sourceName": params.name,
"params": params,
"isShow": params.show ? 1 : 0,
}
TreeApi.updateDirectoryInfo(params2)
cusUpdateNode({ "id": params.id, "sourceName": params.name, "params": JSON.stringify(params) })
}
const close = () => {
baseDialog.value?.close()
}
const remove = () => {
entityOptions.value.remove()
close()
}
const nodeEdit = () => {
that.nodeEdit()
}
const closeCallback = () => {
entityOptions.value.originalOptions = structuredClone(originalOptions)
that.positionEditing = false
that.reset()
eventBus?.emit("destroyComponent")
}
defineExpose({
open,
close
})
</script>
<style scoped lang="scss"></style>

View File

@ -2,6 +2,9 @@ import { TreeApi } from '@/api/tree'
import { $changeComponentPop } from '@/utils/communication'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useTreeNode } from '@/views/components/tree/hooks/treeNode'
import { initMapData } from '../../../../../common/initMapData'
import { GisApi } from '@/api/gisApi'
const { cusAddNodes } = useTreeNode()
export const useRightOperate = () => {
const { getSelectedNodes, cusRemoveNode, cusUpdateNode } = useTreeNode()
@ -11,11 +14,157 @@ export const useRightOperate = () => {
$changeComponentPop('.adddirectoryBox', true)
}
//添加资源
const addResource = () => { }
const addResource = () => {
const { ipcRenderer } = require('electron')
const options = {
properties: ['openFile'], // 允许选择多个文件
filters: [
{ name: '模型、影像、地形', extensions: ['clt', 'json', 'jct', 'mbtiles', 'pak'] },
{ name: '矢量数据', extensions: ['kmz', 'kml', 'shp', 'tab', 'mif', 'geojson'] },
]
};
let selectedNodes = window.treeObj.getSelectedNodes()
let node = selectedNodes && selectedNodes[selectedNodes.length - 1]
let parentId
if (node) {
if (node.sourceType === 'directory') {
parentId = node.id
}
else {
parentId = node.parentId
}
}
ipcRenderer.send('open-directory-dialog', options);
// 监听主进程返回的结果
ipcRenderer.once('selectedItem', async (event, filePaths) => {
if (filePaths.length > 0) {
let id = new YJ.Tools().randomString()
let params: any = {
id: id,
sourcePath: filePaths[0],
parentId: parentId,
params: '',
}
// filePaths[0].split('\\').pop()
let res = await TreeApi.addModelSource(params)
console.log('res', res)
if (res.code === 0 || res.code === 200) {
ElMessage({
message: '添加成功',
type: 'success'
})
res.data.id = id
if (res.data.params) {
let params = JSON.parse(res.data.params)
if (!params.id) {
params.id = res.data.id
}
initMapData(res.data.sourceType, params)
}
else {
//@ts-ignore
if (res.data.detail) {
//@ts-ignore
let detail = JSON.parse(res.data.detail)
if (!detail.id) {
detail.id = res.data.id
}
initMapData(res.data.sourceType, detail)
}
}
cusAddNodes(window.treeObj, params.parentId, [res.data])
}
}
});
}
//导入全景
const importPanorama = () => { }
const importPanorama = async () => {
let selectedNodes = window.treeObj.getSelectedNodes()
let node = selectedNodes && selectedNodes[selectedNodes.length - 1]
let parentId
if (node) {
if (node.sourceType === 'directory') {
parentId = node.id
}
else {
parentId = node.parentId
}
}
const pickerOpts = {
types: [
{
description: '全景图',
accept:
{
'image/jpg': ['.jpg']
}
}
],
excludeAcceptAllOption: true,
multiple: true
};
if ((window as any).showOpenFilePicker) {
const fileHandles = await (window as any).showOpenFilePicker(pickerOpts);
const files = await Promise.all(fileHandles.map(fileHandle => fileHandle.getFile()));
const dataTransfer = new DataTransfer();
handleFileImgInput(files, parentId, 'vr')
}
else {
let input = document.createElement('input')
input.type = 'file'
input.accept = '.jpg'
input.multiple = true
input.click()
input.addEventListener('input', async (e: any) => {
let files = e.target.files
handleFileImgInput(files, parentId, 'vr')
})
}
}
//图片定位
const pictureLocation = () => { }
const pictureLocation = async () => {
let selectedNodes = window.treeObj.getSelectedNodes()
let node = selectedNodes && selectedNodes[selectedNodes.length - 1]
let parentId
if (node) {
if (node.sourceType === 'directory') {
parentId = node.id
}
else {
parentId = node.parentId
}
}
const pickerOpts = {
types: [
{
description: '无人机航拍',
accept:
{
'image/jpg': ['.jpg']
}
}
],
excludeAcceptAllOption: true,
multiple: true
};
if ((window as any).showOpenFilePicker) {
const fileHandles = await (window as any).showOpenFilePicker(pickerOpts);
const files = await Promise.all(fileHandles.map(fileHandle => fileHandle.getFile()));
const dataTransfer = new DataTransfer();
handleFileImgInput(files, parentId, 'link')
}
else {
let input = document.createElement('input')
input.type = 'file'
input.accept = '.jpg'
input.multiple = true
input.click()
input.addEventListener('input', async (e: any) => {
let files = e.target.files
handleFileImgInput(files, parentId, 'link')
})
}
}
//属性
const showAttr = () => { }
//导入模型
@ -28,9 +177,8 @@ export const useRightOperate = () => {
const editNode = (eventBus) => {
let selectNodes = getSelectedNodes(window.treeObj);
if (selectNodes && selectNodes[selectNodes.length - 1]) {
console.log('------------------',selectNodes[selectNodes.length - 1].params)
let params = JSON.parse(selectNodes[selectNodes.length - 1].params)
eventBus.emit("openDialog", selectNodes[selectNodes.length - 1].sourceType, params.id);
let node = selectNodes[selectNodes.length - 1]
eventBus.emit("openDialog", node.sourceType, node.id);
}
}
//删除
@ -42,14 +190,17 @@ export const useRightOperate = () => {
})
.then(async () => {
let selectNodes = getSelectedNodes(window.treeObj)
const ids = selectNodes.map((item: any) => item.id)
const res = await TreeApi.removeDirectory({ ids })
if (res.code == 0) {
let source_ids = cusRemoveNode(window.treeObj, selectNodes)
const res = await TreeApi.removeDirectory({ ids:source_ids })
if (res.code == 0 || res.code == 200) {
ElMessage({
message: '删除成功',
type: 'success'
})
cusRemoveNode(window.treeObj, selectNodes)
source_ids.forEach(item => {
let entity = window.earth.entityMap.get(item)
entity?.remove?.();
});
} else {
ElMessage({
message: res.msg || '删除失败',
@ -74,7 +225,7 @@ export const useRightOperate = () => {
if (selectNodes && selectNodes[selectNodes.length - 1]) {
let node = selectNodes[selectNodes.length - 1]
let params = JSON.parse(node.params)
if(!params) {
if (!params) {
params = {
name: node.sourceName,
show: node.isShow,
@ -218,6 +369,75 @@ export const useRightOperate = () => {
callback: resetPerspective
}
})
// 图片文件上传后续
async function handleFileImgInput(files: any, parentId: string, type: string) {
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
const element = files[i]
formData.append('files', element)
}
let res = await GisApi.linkFile(formData)
if (res.code == 0 || res.code == 200) {
for (let i = 0; i < files.length; i++) {
let file = files[i]
// 检查文件类型
if (!file.type.match('image*')) {
continue;
}
(window as any).EXIF.getData(file, async function (e) {
let id = new YJ.Tools().randomString()
let name = file.name.split('.')[0]
// 获取所有EXIF数据
// @ts-ignore
const allMetaData = (window as any).getAllTags(this);
let lngDMS = allMetaData.GPSLongitude[0] + '°' + allMetaData.GPSLongitude[1] + "'" + allMetaData.GPSLongitude[2] + '"'
let latDMS = allMetaData.GPSLatitude[0] + '°' + allMetaData.GPSLatitude[1] + "'" + allMetaData.GPSLatitude[2] + '"'
let lngDecimal = window.earth.proj.dmsToDecimal(lngDMS)
let latDecimal = window.earth.proj.dmsToDecimal(latDMS)
if (allMetaData.GPSLongitudeRef === 'W') {
lngDecimal = -(Math.abs(lngDecimal))
}
if (allMetaData.GPSLatitudeRef === 'S') {
latDecimal = -(Math.abs(latDecimal))
}
let options: any = await initMapData('point', {
id: id,
name: name,
position: {
lng: lngDecimal,
lat: latDecimal,
alt: allMetaData.GPSAltitude.valueOf()
},
attribute: {
[type]: {
content: [
{
"name": "带定位照片",
"url": res.data[i].previewUrl
}
]
}
}
})
delete options.host
let params: any = {
id: id,
sourceName: name,
sourceType: 'point',
// isShow: 1,
parentId: parentId,
// "treeIndex": 0,
params: options
}
TreeApi.addOtherSource(params)
params.params = JSON.stringify(params.params)
params.isShow = true
cusAddNodes(window.treeObj, params.parentId, [params])
});
}
}
}
return {
rightMenus
}

View File

@ -1,7 +1,7 @@
import { $changeComponentShow } from '@/utils/communication'
import { useTreeNode } from './treeNode'
import { TreeApi } from '@/api/tree'
import { initMapData } from '../initMapData'
import { initMapData } from '../../../../common/initMapData'
export const useTree = () => {
const rightMenuRef: any = ref() //右键菜单的实例
@ -418,7 +418,8 @@ export const useTree = () => {
})
for (let i = res.data.length - 1; i >= 0; i--) {
if (!res.data[i].id) {
res.data.splice(i, 1);
// res.data.splice(i, 1);
res.data[i].id = generateRandomString(20, false)
}
}
zNodes.value = res.data
@ -430,6 +431,29 @@ export const useTree = () => {
}
}
function generateRandomString(length = 10, includeSpecial = true) {
// 基础字符集:大小写字母和数字
let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
// 如果需要包含特殊字符,则添加到字符集中
if (includeSpecial) {
chars += '!@#$%^&*()_+-=[]{}|;:,.<>?';
}
let result = '';
const charsLength = chars.length;
// 循环生成指定长度的随机字符
for (let i = 0; i < length; i++) {
// 生成0到字符集长度之间的随机索引
const randomIndex = Math.floor(Math.random() * charsLength);
// 将对应索引的字符添加到结果中
result += chars.charAt(randomIndex);
}
return result;
}
const initTreeCallBack = () => {
if (window.earth) {
for (let i = 0; i < zNodes.value.length; i++) {

View File

@ -10,14 +10,8 @@
<firstMenu class="absolute zIndex9" ref="firstMenuRef"></firstMenu>
<!--底部菜单-->
<bottomMenu class="absolute zIndex9" ref="bottomMenuRef"></bottomMenu>
<input
type="file"
id="fileInputlink"
style="display: none"
multiple
accept=".jpeg,.png,.jpg,.mp4,.pdf"
@input="uploadFile"
/>
<input type="file" id="fileInputlink" style="display: none" multiple accept=".jpeg,.png,.jpg,.mp4,.pdf"
@input="uploadFile" />
<!-- 多点视线分析 -->
<Visibility ref="visibility"></Visibility>
@ -65,7 +59,13 @@ import Graffiti from '../components/propertyBox/Graffiti.vue'
import FlyRoam from '../components/propertyBox/FlyRoam.vue'
import CoorLocation from '../components/propertyBox/CoorLocation.vue'
import ScreenShot from '../components/propertyBox/ScreenShot.vue'
import TerrainExcavation from '../components/propertyBox/TerrainExcavation.vue'
import terrainExcavation from '../components/propertyBox/terrainExcavation.vue'
import tileset from '../components/propertyBox/tileset.vue'
import layer from '../components/propertyBox/layer.vue'
import trajectoryMotion from '../components/propertyBox/trajectoryMotion.vue'
import wallStereoscopic from '../components/propertyBox/wallStereoscopic.vue'
import circleDiffuse from '../components/propertyBox/circleDiffuse.vue'
import radarScan from '../components/propertyBox/radarScan.vue'
import { GisApi } from '@/api/gisApi'
@ -77,6 +77,10 @@ let dynamicComponentRef = ref()
let addStandTextRef = ref()
let tree = ref()
eventBus.on('openDialog', async (sourceType: any, id: any) => {
console.log(sourceType, id)
if(dynamicComponentRef.value && dynamicComponentRef.value.close) {
dynamicComponentRef.value.close()
}
switch (sourceType) {
case 'addGroundText':
currentComponent.value = addGroundText
@ -113,7 +117,6 @@ eventBus.on('openDialog', async (sourceType: any, id: any) => {
await nextTick()
dynamicComponentRef.value?.open(id)
break
break
case 'panel':
currentComponent.value = polygonObject
await nextTick()
@ -144,6 +147,36 @@ eventBus.on('openDialog', async (sourceType: any, id: any) => {
await nextTick()
dynamicComponentRef.value?.open(id, 'pincerArrow')
break
case 'tileset':
currentComponent.value = tileset
await nextTick()
dynamicComponentRef.value?.open(id)
break
case 'layer':
currentComponent.value = layer
await nextTick()
dynamicComponentRef.value?.open(id)
break
case 'path':
currentComponent.value = trajectoryMotion
await nextTick()
dynamicComponentRef.value?.open(id)
break
case 'wallStereoscopic':
currentComponent.value = wallStereoscopic
await nextTick()
dynamicComponentRef.value?.open(id)
break
case 'diffuseScan':
currentComponent.value = circleDiffuse
await nextTick()
dynamicComponentRef.value?.open(id)
break
case 'radarScan':
currentComponent.value = radarScan
await nextTick()
dynamicComponentRef.value?.open(id)
break
default:
break
}