修改禅道bug

This commit is contained in:
2025-11-21 14:38:00 +08:00
parent 96f8ae2af0
commit 3ac2fcfe99
13 changed files with 739 additions and 125 deletions

File diff suppressed because one or more lines are too long

View File

@ -297,6 +297,11 @@
flex-wrap: wrap;
}
.YJ-custom-base-dialog>.content .row .input-select-unit-box,
.YJ-custom-base-dialog>.content .row .input-select-fit-unit-box {
flex: 0 0 270px;
}
.YJ-custom-base-dialog>.content .row:last-child {
margin-bottom: 0;
}
@ -419,8 +424,7 @@
}
.YJ-custom-base-dialog>.content .attribute .attribute-content-link .link_add_btn,
.YJ-custom-base-dialog>.content .attribute .attribute-content-vr .vr_add_btn,
.YJ-custom-base-dialog>.content .attribute .attribute-content-rtmp .rtmp_add_btn {
.YJ-custom-base-dialog>.content .attribute .attribute-content-vr .vr_add_btn {
display: inline-block;
width: 20px;
height: 20px;
@ -432,14 +436,12 @@
}
.YJ-custom-base-dialog>.content .attribute .attribute-content-link .link_add,
.YJ-custom-base-dialog>.content .attribute .attribute-content-vr .vr_add,
.YJ-custom-base-dialog>.content .attribute .attribute-content-rtmp .rtmp_add {
.YJ-custom-base-dialog>.content .attribute .attribute-content-vr .vr_add {
padding-right: 30px;
}
.YJ-custom-base-dialog>.content .attribute .attribute-content-link .tr .td:last-child button:first-child,
.YJ-custom-base-dialog>.content .attribute .attribute-content-vr .tr .td:last-child button:first-child,
.YJ-custom-base-dialog>.content .attribute .attribute-content-rtmp .tr .td:last-child button:first-child {
.YJ-custom-base-dialog>.content .attribute .attribute-content-vr .tr .td:last-child button:first-child {
margin-right: 5px;
}
@ -529,8 +531,7 @@
}
.YJ-custom-base-dialog>.content .attribute-content-link .table .table-body,
.YJ-custom-base-dialog>.content .attribute-content-vr .table .table-body,
.YJ-custom-base-dialog>.content .attribute-content-rtmp .table .table-body {
.YJ-custom-base-dialog>.content .attribute-content-vr .table .table-body {
max-height: 172px;
}
@ -2513,9 +2514,7 @@
.YJ-custom-base-dialog.polygon>.content .attribute-content-link .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.polygon>.content .attribute-content-link .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.polygon>.content .attribute-content-vr .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.polygon>.content .attribute-content-vr .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.polygon>.content .attribute-content-rtmp .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.polygon>.content .attribute-content-rtmp .table .tr .td:nth-child(3) {
.YJ-custom-base-dialog.polygon>.content .attribute-content-vr .table .tr .td:nth-child(3) {
flex: 0 0 165px;
width: 165px;
justify-content: center;
@ -2597,9 +2596,7 @@
.YJ-custom-base-dialog.assemble>.content .attribute-content-link .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.assemble>.content .attribute-content-link .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.assemble>.content .attribute-content-vr .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.assemble>.content .attribute-content-vr .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.assemble>.content .attribute-content-rtmp .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.assemble>.content .attribute-content-rtmp .table .tr .td:nth-child(3) {
.YJ-custom-base-dialog.assemble>.content .attribute-content-vr .table .tr .td:nth-child(3) {
flex: 0 0 165px;
width: 165px;
justify-content: center;
@ -2646,20 +2643,14 @@
.YJ-custom-base-dialog.circle>.content .attribute-content-link .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.circle>.content .attribute-content-vr .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.circle>.content .attribute-content-vr .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.circle>.content .attribute-content-rtmp .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.circle>.content .attribute-content-rtmp .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.attackArrow>.content .attribute-content-link .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.attackArrow>.content .attribute-content-link .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.attackArrow>.content .attribute-content-vr .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.attackArrow>.content .attribute-content-vr .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.attackArrow>.content .attribute-content-rtmp .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.attackArrow>.content .attribute-content-rtmp .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.pincerArrow>.content .attribute-content-link .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.pincerArrow>.content .attribute-content-link .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.pincerArrow>.content .attribute-content-vr .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.pincerArrow>.content .attribute-content-vr .table .tr .td:nth-child(3),
.YJ-custom-base-dialog.pincerArrow>.content .attribute-content-rtmp .table .tr .th:nth-child(3),
.YJ-custom-base-dialog.pincerArrow>.content .attribute-content-rtmp .table .tr .td:nth-child(3) {
.YJ-custom-base-dialog.pincerArrow>.content .attribute-content-vr .table .tr .td:nth-child(3) {
flex: 0 0 165px;
width: 165px;
justify-content: center;
@ -2955,9 +2946,8 @@
.YJ-custom-base-dialog.polyline>.content input.input-text {
background-color: rgba(0, 0, 0, 0.5) !important;
border-radius: unset !important;
border: none;
border-top: 1px solid rgba(var(--color-base1), 0.7) !important;
border-bottom: 1px solid rgba(var(--color-base1), 0.7) !important;
border-top: 1px solid rgba(var(--color-base1), 0.5) !important;
border-bottom: 1px solid rgba(var(--color-base1), 0.5) !important;
}
.YJ-custom-base-dialog.polyline>.content>div .input-select-line-type-box .cy_datalist input {
@ -3143,9 +3133,7 @@
.YJ-custom-base-dialog.model>.content .attribute-content-link .table .tr .th:nth-child(2),
.YJ-custom-base-dialog.model>.content .attribute-content-link .table .tr .td:nth-child(2),
.YJ-custom-base-dialog.model>.content .attribute-content-vr .table .tr .th:nth-child(2),
.YJ-custom-base-dialog.model>.content .attribute-content-vr .table .tr .td:nth-child(2),
.YJ-custom-base-dialog.model>.content .attribute-content-rtmp .table .tr .th:nth-child(2),
.YJ-custom-base-dialog.model>.content .attribute-content-rtmp .table .tr .td:nth-child(2) {
.YJ-custom-base-dialog.model>.content .attribute-content-vr .table .tr .td:nth-child(2) {
flex: 0 0 210px;
width: 210px;
justify-content: center;

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M11.9945 3.16658L11.9945 1.72069L11.8696 1.76315C11.7546 1.80224 11.6333 1.82206 11.5089 1.82206C10.8828 1.82206 10.3734 1.31252 10.3734 0.686229C10.3734 0.496399 10.4217 0.307378 10.5131 0.139709L10.5893 0L1.35472 0L1.43096 0.139709C1.52365 0.309763 1.57068 0.493652 1.57068 0.686229C1.57068 1.31252 1.06127 1.82206 0.435165 1.82206C0.32984 1.82206 0.223893 1.80708 0.120231 1.77772L0 1.74355L0 3.98349L0.0024578 4.07801L0.00456869 4.07801C0.0895516 7.30379 1.34444 9.2099 2.38795 10.2433C3.61319 11.4568 5.08176 12 5.99355 12C6.9027 12 8.36882 11.4519 9.59474 10.2273C10.6411 9.18205 11.9068 7.25086 11.9945 3.98491C12.0018 3.72074 12.0018 3.44537 11.9945 3.16658ZM11.0184 3.9475L11.0184 3.94887L11.0184 3.95882C10.9843 5.22756 10.7554 6.37681 10.3381 7.3747C9.98613 8.21526 9.50502 8.94481 8.90823 9.54304C8.42305 10.0295 7.84866 10.4312 7.24719 10.7049C6.64016 10.9811 6.20122 11.0224 5.99355 11.0224C5.73833 11.0224 5.31265 10.9679 4.73454 10.7083C4.14061 10.4421 3.56674 10.0433 3.07487 9.55492C2.47425 8.95903 1.99204 8.23172 1.64167 7.39326C1.22518 6.39326 1.00174 5.24011 0.97739 3.96583L0.974875 2.72766C1.79865 2.51 2.4087 1.8204 2.52529 0.976346L9.41639 0.976346C9.5352 1.83046 10.1786 2.5396 11.0184 2.74058L11.0185 3.19018C11.0258 3.44636 11.0258 3.70115 11.0184 3.9475ZM6.02183 2.0696L4.93329 4.27731L2.49784 4.63114L4.25987 6.34914L3.84349 8.77481L6.02183 7.62984L8.20017 8.77481L7.78392 6.34915L9.54589 4.63115L7.11044 4.27732L6.02183 2.0696ZM6.90338 6.98983L6.02177 6.52686L5.13988 6.99109L5.30783 6.0088L4.59395 5.31303L5.58032 5.16978L6.02065 4.27601L6.46091 5.16978L7.44733 5.31303L6.73327 6.00892L6.90338 6.98983Z" fill="#FFFFFF" ></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12.00048828125" viewBox="0 0 12 12.00048828125" fill="none"><path d="M1.19473 4.35774L1.19473 1.80664C1.19473 1.4693 1.46881 1.19522 1.80615 1.19522L10.1939 1.19522C10.5312 1.19522 10.8053 1.4693 10.8053 1.80664L10.8053 10.1943C10.8053 10.5317 10.5312 10.8058 10.1939 10.8058L7.64275 10.8058C7.31245 10.8058 7.04539 11.0728 7.04539 11.4031C7.04539 11.7334 7.31245 12.0005 7.64275 12.0005L10.7859 12.0005C11.4571 12.0005 12 11.4558 12 10.7864L12 1.21454C12 0.543388 11.4553 0.000488281 10.7859 0.000488281L1.21406 0.000488281C0.542899 0.000488281 0 0.545144 0 1.21454L0 4.35774C0 4.68805 0.267057 4.9551 0.597365 4.9551C0.927672 4.9551 1.19473 4.68805 1.19473 4.35774Z" fill="#FFFFFF" ></path><path d="M6.20029 8.62372L6.19854 8.62196L3.84949 6.27291C3.61581 6.03924 3.23807 6.03924 3.00439 6.27291C2.77072 6.50659 2.77072 6.88433 3.00439 7.11801L4.33792 8.45154L0.597365 8.45154C0.267057 8.45154 0 8.7186 0 9.0489C0 9.37921 0.267057 9.64627 0.597365 9.64627L4.33441 9.64627L3.00439 10.9763C2.77072 11.21 2.77072 11.5877 3.00439 11.8214C3.23807 12.0551 3.61581 12.0551 3.84949 11.8214L6.16164 9.50922C6.29341 9.40029 6.37775 9.23514 6.37775 9.05066C6.37775 8.88199 6.30923 8.73265 6.20029 8.62372Z" fill="#FFFFFF" ></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -66,7 +66,11 @@ const handleClick = (command: string) => {
z-index: 9999;
border: 1.5px solid;
box-sizing: border-box;
border-image: linear-gradient(137.95deg, rgba(var(--color-base1), 1) 6.25%, var(--color-border1) 100%)
border-image: linear-gradient(
137.95deg,
rgba(var(--color-base1), 1) 6.25%,
var(--color-border1) 100%
)
1.5;
font-size: 12px;
}

View File

@ -43,7 +43,12 @@
</div>
<div class="nav_table">
<el-table :data="tableData" height="40vh" style="width: 100%">
<el-table
:data="tableData"
:header-cell-style="{ 'text-align': 'center' }"
height="40vh"
style="width: 100%"
>
<el-table-column prop="cameraName" label="设备名称" width="150" />
<el-table-column prop="deviceType" label="设备类型" width="120">
<template #default="scope">

View File

@ -27,8 +27,8 @@
<el-input
v-model="photoName"
style="max-width: 150px"
placeholder="请输入标名称进行搜索"
style="max-width: 200px; width: 13vw"
placeholder="请输入标名称进行搜索"
class="input-with-select"
:suffix-icon="Search"
>
@ -92,7 +92,12 @@
<!-- 右侧模型列表 -->
<el-col :span="18">
<el-card shadow="hover">
<el-table :data="modelList" border style="width: 100%">
<el-table
:data="modelList"
:header-cell-style="{ 'text-align': 'center' }"
border
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="militaryName" label="名称" />
<el-table-column prop="militaryDataUrl" label="缩略图" width="100">
@ -131,8 +136,14 @@
/>
<!-- 添加类型弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="30%" :before-close="handleClose">
<el-input v-model="modelType" placeholder="请输入数据" />
<el-dialog
v-model="dialogVisible"
:title="dialogTitle"
width="30%"
style="padding: 10px"
:before-close="handleClose"
>
<el-input v-model="modelType" style="width: calc(100% - 60px)" placeholder="请输入数据" />
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
@ -401,19 +412,50 @@ const handleDragEnd = (
ev: DragEvents
) => {
console.log('tree drag end:', dropNode, dropType, ev, draggingNode)
let nodeList = dropNode.childNodes.map((item, index) => {
return {
id: item.data.id,
parentId: dropNode.data.id,
treeIndex: index
if (dropType != 'none') {
let nodeList = []
switch (dropType) {
case 'before':
case 'after':
if (dropNode.parent?.key) {
nodeList = dropNode.parent?.childNodes.map((item, index) => {
return {
id: item.key,
parentId: dropNode.parent?.key,
treeIndex: index
}
})
} else {
nodeList = dropNode.parent?.data.map((item, index) => {
return {
id: item.id,
parentId: null,
treeIndex: index
}
})
}
break
case 'inner':
nodeList = dropNode.data.children.map((item, index) => {
return {
id: item.id,
parentId: dropNode.data.id,
treeIndex: index
}
})
break
default:
break
}
})
GraphApi.dragModelType(nodeList).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('拖拽成功')
getModelList()
}
})
GraphApi.dragModelType(nodeList).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('拖拽成功')
getModelList()
}
})
}
}
const handleDrop = (draggingNode: Node, dropNode: Node, dropType: NodeDropType, ev: DragEvents) => {
console.log('tree drop:', dropNode.label, dropType)
@ -450,7 +492,7 @@ const handleContextMenu = (event: MouseEvent, row: TypeNode) => {
if (row.parentId) {
// 二级分类菜单
contextMenu.items = [
{ command: 'import', label: '导入军标', icon: 'importModel' },
{ command: 'import', label: '导入军标', icon: 'importjb' },
{ command: 'rename', label: '重命名', icon: 'rename' },
{ command: 'delete', label: '删除', icon: 'delModel' }
]
@ -458,7 +500,7 @@ const handleContextMenu = (event: MouseEvent, row: TypeNode) => {
// 一级分类菜单
contextMenu.items = [
{ command: 'add-child', label: '添加子类型', icon: 'add' },
{ command: 'import', label: '导入军标', icon: 'importModel' },
{ command: 'import', label: '导入军标', icon: 'importjb' },
{ command: 'rename', label: '重命名', icon: 'rename' },
{ command: 'delete', label: '删除', icon: 'delModel' }
]
@ -503,7 +545,7 @@ const divContextMenu = (event: MouseEvent) => {
contextMenu.x = event.clientX
contextMenu.y = event.clientY
clickTreeNode = null
contextMenu.items = [{ command: 'addType', label: '添加类型', icon: 'add' }]
contextMenu.items = [{ command: 'addType', label: '添加军标类型', icon: 'add' }]
contextMenu.visible = true
}
@ -575,12 +617,58 @@ const handleAddChildType = (row: TypeNode) => {
dialogVisible.value = true
}
// const handleImportModel = (row: TypeNode) => {
// triggerUpload()
// }
const handleImportModel = (row: TypeNode) => {
triggerUpload()
let option = {
properties: ['openFile', 'multiSelections'],
filters: [
{
name: '军标',
extensions: ['svg']
}
]
}
let imgArr = []
$sendElectronChanel('open-directory-dialog', option)
$recvElectronChanel('selectedItem', (e, paths) => {
if (paths.length) {
console.log(paths, 'paths')
const formData = new FormData()
formData.append('filePaths', paths)
formData.append('militaryTypeId', clickTreeNode.id)
GraphApi.addGraph(formData).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('导入成功')
getModelListByType(clickTreeNode.id)
}
})
}
})
}
const getBase64Image = (src) => {
return new Promise((resolve) => {
let xhr = new XMLHttpRequest()
xhr.open('get', src, true)
xhr.responseType = 'blob'
xhr.onload = function () {
if (this.status == 200) {
let blob = this.response
let oFileReader = new FileReader()
oFileReader.onloadend = function (e) {
const base64 = e.target.result
resolve(base64)
}
oFileReader.readAsDataURL(blob)
}
}
xhr.send()
})
}
const handleRenameType = (row: TypeNode) => {
dialogTitle.value = '军标类型重命名'
dialogTitle.value = '修改军标类型'
modelType.value = row.label
dialogVisible.value = true
}
@ -902,6 +990,7 @@ onMounted(() => {
color: rgba(230, 247, 255, 1) !important;
border-bottom: 1px solid rgba(var(--color-base1), 0.5);
letter-spacing: 1px;
text-align: center;
}
</style>
<style lang="scss">

View File

@ -3,17 +3,7 @@
<div class="equipment_title">
<div>
<el-button
color="#004b4b"
style="border: 1px solid rgba(var(--color-base1), 0.5)"
@click="importModelDB"
>
<template #icon>
<svg-icon name="select" />
</template>
<span>选择模型库</span>
</el-button>
<el-button
class="topBut"
color="#004b4b"
style="border: 1px solid rgba(var(--color-base1), 0.5)"
@click="createModelDB"
@ -23,16 +13,27 @@
</template>
<span>创建模型库</span>
</el-button>
<el-button
class="topBut"
color="#004b4b"
style="border: 1px solid rgba(var(--color-base1), 0.5)"
@click="importModelDB"
>
<template #icon>
<svg-icon name="select" />
</template>
<span>选择模型库</span>
</el-button>
</div>
<el-input
v-model.trim="photoName"
style="max-width: 150px"
style="max-width: 200px; width: 13vw"
placeholder="请输入模型名称进行搜索"
class="input-with-select"
:suffix-icon="Search"
/>
</div>
<el-row :gutter="20">
<el-row :gutter="20" class="modelTreeRowCon">
<!-- 左侧分类树 -->
<el-col :span="6" class="tree">
<el-card shadow="hover">
@ -45,6 +46,7 @@
:data="typeTreeData"
:default-expanded-keys="expandedKeys"
draggable
class="modelTree"
ref="treeRef"
node-key="id"
empty-text=""
@ -90,10 +92,15 @@
<!-- 右侧模型列表 -->
<el-col :span="18">
<el-card shadow="hover">
<el-table :data="modelList" border style="width: 100%">
<el-table
:data="modelList"
:header-cell-style="{ 'text-align': 'center' }"
border
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="modelName" label="模型名称" />
<el-table-column prop="thumbnail" label="缩略图" width="100">
<el-table-column prop="thumbnail" label="缩略图" min-width="100">
<template #default="{ row }">
<el-image
style="width: 80px; height: 60px"
@ -102,7 +109,7 @@
/>
</template>
</el-table-column>
<el-table-column label="操作">
<el-table-column label="操作" width="205">
<template #default="{ row }">
<!-- <el-button size="small" @click="handleEdit(row)">编辑</el-button> -->
<el-button size="small" @click="showImage(row)">预览</el-button>
@ -131,10 +138,20 @@
/>
<!-- 添加类型弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="30%" :before-close="handleClose">
<el-input v-model.trim="modelType" placeholder="请输入模型类型名称" />
<el-dialog
v-model="dialogVisible"
:title="dialogTitle"
width="30%"
style="padding: 10px"
:before-close="handleClose"
>
<el-input
v-model.trim="modelType"
style="width(100% - 60px)"
placeholder="请输入模型类型名称"
/>
<template #footer>
<span class="dialog-footer">
<span class="dialog-footer" style="text-align: center">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="addType"> 确定 </el-button>
</span>
@ -355,7 +372,6 @@ const handleFileChange = (e: Event) => {
//创建模型库
const createModelDB = async () => {
let date = new Date().toISOString().split('T')[0]
console.log(date, 'datedatedatedate')
let option = {
title: '创建模型库',
// filename: 'YJEarth.model',
@ -364,7 +380,6 @@ const createModelDB = async () => {
}
$sendElectronChanel('saveFile', option)
$recvElectronChanel('selectedFileItem', (e, path) => {
console.log(path, 'klklkllllk')
if (path) {
let index = path.lastIndexOf('/')
let model_lib_path = path.slice(0, index)
@ -429,20 +444,74 @@ const handleDragEnd = (
dropType: NodeDropType,
ev: DragEvents
) => {
console.log('tree drag end:', dropNode, dropType, ev, draggingNode)
let nodeList = dropNode.childNodes.map((item, index) => {
return {
id: item.data.id,
parentId: dropNode.data.id,
treeIndex: index
console.log('tree drag end:', dropNode, dropType, ev, draggingNode, draggingNode.parent)
if (dropType != 'none') {
let nodeList = []
switch (dropType) {
case 'before':
case 'after':
if (dropNode.parent?.key) {
nodeList = dropNode.parent?.childNodes.map((item, index) => {
return {
id: item.key,
parentId: dropNode.parent?.key,
treeIndex: index
}
})
} else {
nodeList = dropNode.parent?.data.map((item, index) => {
return {
id: item.id,
parentId: null,
treeIndex: index
}
})
}
break
case 'inner':
nodeList = dropNode.data.children.map((item, index) => {
return {
id: item.id,
parentId: dropNode.data.id,
treeIndex: index
}
})
break
default:
break
}
})
ModelApi.dragModelType(nodeList).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('拖拽成功')
getModelList()
}
})
ModelApi.dragModelType(nodeList).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('拖拽成功')
getModelList()
}
})
}
}
const isEqual = (obj1, obj2) => {
// 基本类型直接比较
if (obj1 === obj2) return true
// 类型不同或有一个为 null
if (typeof obj1 !== 'object' || typeof obj2 !== 'object' || obj1 === null || obj2 === null) {
return false
}
const keys1 = Object.keys(obj1)
const keys2 = Object.keys(obj2)
// 键数量不同
if (keys1.length !== keys2.length) return false
for (let key of keys1) {
// 键不存在
if (!obj2.hasOwnProperty(key)) return false
// 递归比较值
if (!isEqual(obj1[key], obj2[key])) return false
}
return true
}
const handleDrop = (draggingNode: Node, dropNode: Node, dropType: NodeDropType, ev: DragEvents) => {
console.log('tree drop:', dropNode.label, dropType)
@ -473,11 +542,29 @@ const showImage = (row: any) => {
const handleContextMenu = (event: MouseEvent, row: TypeNode) => {
event.stopPropagation()
event.preventDefault()
contextMenu.currentRow = row
console.log(event, 'eventevent')
contextMenu.x = event.clientX
contextMenu.y = event.clientY
// 计算相对于文档的坐标
// if (document.getElementsByClassName('settingPop')[0]?.style.transform.length) {
// document.getElementsByClassName('modelTreeRowCon')[0].style.position = 'relative'
// document.getElementsByClassName('context-menu')[0].style.position = 'absolute'
// contextMenu.x = event.offsetX + 28
// contextMenu.y =
// event.offsetX < 0 || event.offsetX == 0 ? event.offsetY + 145 : event.offsetY + 110
// // let rect = document.getElementsByClassName('modelTreeRowCon')[0].getBoundingClientRect()
// // contextMenu.x = event.clientX - rect.top
// // contextMenu.y = event.clientY - rect.left
// // console.log('x', event.clientX, rect.left, 'y', event.clientY, rect.top)
// } else {
// document.getElementsByClassName('modelTreeRowCon')[0].style.position = 'unset'
// document.getElementsByClassName('context-menu')[0].style.position = 'fixed'
// contextMenu.x = event.clientX
// contextMenu.y = event.clientY
// }
// console.log(contextMenu.x, contextMenu.y, 'kklklkkl')
// if (row.parentId) {
// // 二级分类菜单
// contextMenu.items = [
@ -497,6 +584,14 @@ const handleContextMenu = (event: MouseEvent, row: TypeNode) => {
clickTreeNode = row
contextMenu.visible = true
document.getElementsByClassName('settingPop')[0].addEventListener('mousedown', func)
}
let func = () => {
document.getElementsByClassName('settingPop')[0].removeEventListener('mousedown', func)
setTimeout(() => {
contextMenu.visible = false
}, 100)
}
const toggleExpand = (row: any) => {
if (row.childNodes.length != 0) {
@ -535,8 +630,22 @@ const divContextMenu = (event: MouseEvent) => {
event.preventDefault()
contextMenu.x = event.clientX
contextMenu.y = event.clientY
// if (document.getElementsByClassName('settingPop')[0]?.style.transform.length) {
// document.getElementsByClassName('modelTreeRowCon')[0].style.position = 'relative'
// document.getElementsByClassName('context-menu')[0].style.position = 'absolute'
// contextMenu.x = event.offsetX + 28
// contextMenu.y =
// event.offsetX < 0 || event.offsetX == 0 ? event.offsetY + 145 : event.offsetY + 110
// } else {
// document.getElementsByClassName('modelTreeRowCon')[0].style.position = 'unset'
// document.getElementsByClassName('context-menu')[0].style.position = 'fixed'
// contextMenu.x = event.clientX
// contextMenu.y = event.clientY
// }
clickTreeNode = null
contextMenu.items = [{ command: 'addType', label: '添加类型', icon: 'add' }]
contextMenu.items = [{ command: 'addType', label: '添加模型类型', icon: 'add' }]
contextMenu.visible = true
}
@ -608,12 +717,38 @@ const handleAddChildType = (row: TypeNode) => {
dialogVisible.value = true
}
// const handleImportModel = (row: TypeNode) => {
// triggerUpload()
// }
const handleImportModel = (row: TypeNode) => {
triggerUpload()
console.log('aaaaaaa')
let option = {
properties: ['openFile', 'multiSelections'],
filters: [
{
name: '人工模型',
extensions: ['glb', 'gltf']
}
]
}
$sendElectronChanel('open-directory-dialog', option)
$recvElectronChanel('selectedItem', (e, paths) => {
if (paths.length) {
const formData = new FormData()
formData.append('filePaths', paths)
formData.append('modelTypeId', clickTreeNode.id)
ModelApi.addModel(formData).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('导入成功')
getModelListByType(clickTreeNode.id)
}
})
}
})
}
const handleRenameType = (row: TypeNode) => {
dialogTitle.value = '模型类型重命名'
dialogTitle.value = '修改模型类型'
modelType.value = row.label
dialogVisible.value = true
}
@ -740,6 +875,9 @@ const getNamefromPath = (path) => {
return name
}
import { useTreeNode } from '@/views/components/tree/hooks/treeNode'
const { cusUpdateNode, getSelectedNodes, cusRemoveNode } = useTreeNode()
const handleDelete = (row: ModelItem) => {
ElMessageBox.confirm(
'删除模型将在系统中永久消失,且模型库和添加到场景展示区的数据也将删除,您确定要执行删除操作吗?',
@ -758,6 +896,17 @@ const handleDelete = (row: ModelItem) => {
ElMessage.success('删除成功')
// @ts-ignore
getModelListByType(row.modelTypeId)
if (res.data?.length) {
//删除对应的树数据和地图数据
res.data.forEach((item) => {
let node = window.treeObj.getNodeByParam('id', item, null)
let source_ids = cusRemoveNode(window.treeObj, [node])
;(window as any).earth.entityMap.get(source_ids[0]).remove()
;(window as any)._entityMap.delete(item)
})
}
console.log(res, 'resres')
}
})
})
@ -936,10 +1085,14 @@ onMounted(() => {
color: rgba(230, 247, 255, 1) !important;
border-bottom: 1px solid rgba(var(--color-base1), 0.5);
letter-spacing: 1px;
text-align: center;
}
.equipment_title {
display: flex;
justify-content: space-between;
margin: 0px -10px 10px -10px;
}
.topBut:hover {
color: 1px solid rgba(var(--color-base1), 1) !important;
}
</style>

View File

@ -26,7 +26,7 @@
</div>
<el-input
v-model="photoName"
style="max-width: 150px"
style="max-width: 200px; width: 13vw"
placeholder="请输入图标名称进行搜索"
class="input-with-select"
:suffix-icon="Search"
@ -42,7 +42,7 @@
>
</div> -->
</div>
<el-row :gutter="20">
<el-row :gutter="20" class="photoTreeRowCon">
<!-- 左侧分类树 -->
<el-col :span="6" class="tree">
<el-card shadow="hover">
@ -100,7 +100,12 @@
<!-- 右侧模型列表 -->
<el-col :span="18">
<el-card shadow="hover">
<el-table :data="modelList" border style="width: 100%">
<el-table
:data="modelList"
:header-cell-style="{ 'text-align': 'center' }"
border
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="iconName" label="名称" />
<el-table-column prop="iconDataUrl" label="缩略图" width="100">
@ -163,8 +168,14 @@
/>
<!-- 添加类型弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="30%" :before-close="handleClose">
<el-input v-model="modelType" placeholder="请输入名称" />
<el-dialog
v-model="dialogVisible"
:title="dialogTitle"
width="30%"
style="padding: 10px"
:before-close="handleClose"
>
<el-input v-model="modelType" style="width: calc(100% - 60px)" placeholder="请输入名称" />
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
@ -481,19 +492,48 @@ const handleDragEnd = (
ev: DragEvents
) => {
console.log('tree drag end:', dropNode, dropType, ev, draggingNode)
let nodeList = dropNode.childNodes.map((item, index) => {
return {
id: item.data.id,
parentId: dropNode.data.id,
treeIndex: index
if (dropType != 'none') {
let nodeList = []
switch (dropType) {
case 'before':
case 'after':
if (dropNode.parent?.key) {
nodeList = dropNode.parent?.childNodes.map((item, index) => {
return {
id: item.key,
parentId: dropNode.parent?.key,
treeIndex: index
}
})
} else {
nodeList = dropNode.parent?.data.map((item, index) => {
return {
id: item.id,
parentId: null,
treeIndex: index
}
})
}
break
case 'inner':
nodeList = dropNode.data.children.map((item, index) => {
return {
id: item.id,
parentId: dropNode.data.id,
treeIndex: index
}
})
break
default:
break
}
})
PhotoApi.dragModelType(nodeList).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('拖拽成功')
getModelList()
}
})
PhotoApi.dragModelType(nodeList).then((res) => {
if (res.code == 0 || res.code == 200) {
ElMessage.success('拖拽成功')
getModelList()
}
})
}
}
const handleDrop = (draggingNode: Node, dropNode: Node, dropType: NodeDropType, ev: DragEvents) => {
console.log('tree drop:', dropNode.label, dropType)
@ -527,13 +567,24 @@ const handleContextMenu = (event: MouseEvent, row: TypeNode) => {
}
contextMenu.currentRow = row
contextMenu.x = event.clientX
contextMenu.y = event.clientY
// contextMenu.x = event.clientX
// contextMenu.y = event.clientY
if (document.getElementsByClassName('settingPop')[0]?.style.transform.length) {
document.getElementsByClassName('photoTreeRowCon')[0].style.position = 'relative'
document.getElementsByClassName('context-menu')[0].style.position = 'absolute'
contextMenu.x = event.offsetX
contextMenu.y = event.offsetY + 150
} else {
document.getElementsByClassName('photoTreeRowCon')[0].style.position = 'unset'
document.getElementsByClassName('context-menu')[0].style.position = 'fixed'
contextMenu.x = event.clientX
contextMenu.y = event.clientY
}
if (row.parentId) {
// 二级分类菜单
contextMenu.items = [
{ command: 'import', label: '导入图标', icon: 'importModel' },
{ command: 'import', label: '导入图标', icon: 'importtb' },
{ command: 'rename', label: '重命名', icon: 'rename' },
{ command: 'delete', label: '删除', icon: 'delModel' }
]
@ -541,7 +592,7 @@ const handleContextMenu = (event: MouseEvent, row: TypeNode) => {
// 一级分类菜单
contextMenu.items = [
{ command: 'add-child', label: '添加子类型', icon: 'add' },
{ command: 'import', label: '导入图标', icon: 'importModel' },
{ command: 'import', label: '导入图标', icon: 'importtb' },
{ command: 'rename', label: '重命名', icon: 'rename' },
{ command: 'delete', label: '删除', icon: 'delModel' }
]
@ -592,10 +643,21 @@ const divContextMenu = (event: MouseEvent) => {
return
}
event.preventDefault()
contextMenu.x = event.clientX
contextMenu.y = event.clientY
// contextMenu.x = event.clientX
// contextMenu.y = event.clientY
if (document.getElementsByClassName('settingPop')[0]?.style.transform.length) {
document.getElementsByClassName('photoTreeRowCon')[0].style.position = 'relative'
document.getElementsByClassName('context-menu')[0].style.position = 'absolute'
contextMenu.x = event.offsetX
contextMenu.y = event.offsetY + 150
} else {
document.getElementsByClassName('photoTreeRowCon')[0].style.position = 'unset'
document.getElementsByClassName('context-menu')[0].style.position = 'fixed'
contextMenu.x = event.clientX
contextMenu.y = event.clientY
}
clickTreeNode = null
contextMenu.items = [{ command: 'addType', label: '添加类型', icon: 'add' }]
contextMenu.items = [{ command: 'addType', label: '添加图标类型', icon: 'add' }]
contextMenu.visible = true
}
@ -673,7 +735,7 @@ const handleImportModel = (row: TypeNode) => {
}
const handleRenameType = (row: TypeNode) => {
dialogTitle.value = '图标类型重命名'
dialogTitle.value = '修改图标类型'
modelType.value = row.label
dialogVisible.value = true
}
@ -1066,6 +1128,7 @@ onMounted(() => {
color: rgba(230, 247, 255, 1) !important;
border-bottom: 1px solid rgba(var(--color-base1), 0.5);
letter-spacing: 1px;
text-align: center;
}
.clickButClass {
color: rgba(var(--color-base1), 1);

View File

@ -6,6 +6,7 @@
draggable
:close-on-click-modal="false"
:destroy-on-close="true"
class="settingPop"
>
<template #header>
<div class="set_pup_header">

View File

@ -10,7 +10,7 @@
<template #content>
<div class="content">
<span class="custom-divider"></span>
<div class="imageCon" ref="threeCanvas">
<div class="imageCon" ref="threeCanvas" id="threeCanvas">
<!-- <img class="image" :src="rowData.thumbnail" alt="" /> -->
</div>
<span
@ -47,6 +47,7 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { debounce } from '@/utils'
import { ModelApi } from '@/api/model/index'
import { ElMessage } from 'element-plus'
import { viewGlb, viewGlbByEarth } from './viewGlb'
const baseDialog: any = ref(null)
const eventBus: any = inject('bus')
@ -82,7 +83,7 @@ const initThreeJS = () => {
75,
threeCanvas.value.clientWidth / threeCanvas.value.clientHeight,
0.1,
1000
100000
)
camera.position.set(0, 1, 5)
camera.lookAt(0, 0, 0)
@ -101,8 +102,8 @@ const initThreeJS = () => {
controls.enableDamping = true // 启用阻尼,增加平滑度
controls.dampingFactor = 0.05 // 阻尼系数默认为0.25
controls.screenSpacePanning = false // 平移时是否在屏幕空间中移动默认false即在世界空间中移动
controls.minDistance = 1 // 最小距离,默认无限制
controls.maxDistance = 500 // 最大距离,默认无限制
// controls.minDistance = 1 // 最小距离,默认无限制
// controls.maxDistance = 500 // 最大距离,默认无限制
controls.enableZoom = true // 是否可以缩放默认true
controls.zoomSpeed = 1.0 // 缩放速度默认1.0
controls.rotateSpeed = 1.0 // 旋转速度默认1.0
@ -129,6 +130,7 @@ const loadModel = () => {
model = gltf.scene
model.position.set(0, 0, 0)
scene.add(model) // 将模型添加到场景中
adjustCameraToModel(model, camera)
},
undefined, // onProgress回调函数可选参数用于处理加载进度等这里不使用所以设置为undefined或提供具体实现函数。
function (error) {
@ -146,6 +148,26 @@ const animate = () => {
controls.update() // 更新控制器状态
renderer.render(scene, camera) // 渲染场景和相机。
}
const adjustCameraToModel = (model, camera) => {
// 计算模型包围盒
const box = new THREE.Box3().setFromObject(model)
const center = new THREE.Vector3()
box.getCenter(center)
// 计算包围盒尺寸
const boxSize = box.getSize(new THREE.Vector3()).length()
// 根据视场角计算相机距离
const fov = camera.fov * (Math.PI / 180)
const cameraZ = boxSize / 2 / Math.tan(fov / 2)
// 设置相机位置并指向模型中心
camera.position.set(center.x, center.y, center.z + cameraZ)
camera.lookAt(center)
// 更新相机矩阵
camera.updateProjectionMatrix()
}
const clangeViewPointHeight = () => {}
const viewPointHeightInput = () => {

View File

@ -598,8 +598,7 @@ onBeforeUnmount(() => {
observer?.disconnect()
})
//end
eventBus.on('openModel', (data, cb, type) => {
let func = (data, cb, type) => {
selectCallback = cb
addType.value = type
isShowPup.value = data
@ -607,8 +606,9 @@ eventBus.on('openModel', (data, cb, type) => {
getModelList()
getSetting()
}
})
eventBus.on('closeModelSet', (data) => {
}
let func2 = (data) => {
addType.value = ''
selectCallback = null
isShowPup.value = data
@ -616,6 +616,14 @@ eventBus.on('closeModelSet', (data) => {
getSetting()
clickTreeNode.value && getModelListByType(clickTreeNode.value)
}
}
onMounted(() => {
eventBus.on('openModel', func)
eventBus.on('closeModelSet', func2)
})
onUnmounted(() => {
eventBus.off('openModel', func)
eventBus.off('closeModelSet', func2)
})
//查看是否有设置模型设置

View File

@ -0,0 +1,279 @@
import * as THREE from "three";
//导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
//导入GLTF模型加载器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
class viewGlb {
constructor(selector) {
this.canvasWidth = 900;
this.canvasHeight = 650;
this.container = document.querySelector(selector); //获取容器
this.modelInfo = {};
this.scene = null;
this.camera = null;
this.renderer = null;
this.controls = null;
this.init(); //初始化
this.animate(); //循环函数
}
init() {
// 初始化场景
this.initScene();
// 初始化辅助轴
this.initAxesHelper();
// 初始化灯光
this.initLight();
// 初始化相机
this.initCamera();
// 初始化渲染器
this.initRender();
// 初始化轨道控制器
this.initControls();
// 监听场景大小改变,重新渲染尺寸
window.addEventListener("resize", this.onWindowResize.bind(this));
// this.addGLTFModel()
}
initScene() {
this.scene = new THREE.Scene();
// this.scene.background = new THREE.Color(0xffffff)
}
initAxesHelper() {
const axesHelper = new THREE.AxesHelper(5);
this.scene.add(axesHelper);
}
initLight() {
const hesLight = new THREE.HemisphereLight(0xffffff, 0x444444);
hesLight.intensity = 0.6;
this.scene.add(hesLight);
const dirLight = new THREE.DirectionalLight();
dirLight.position.set(5, 5, 5);
this.scene.add(dirLight);
}
initCamera() {
this.camera = new THREE.PerspectiveCamera(
75,
this.canvasWidth / this.canvasHeight,
0.1,
100
);
// this.camera.position.set(1.5, 1.5, 1.5)
this.camera.position.set(2, 2, 2);
}
initRender() {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
// preserveDrawingBuffer: true
}); //设置抗锯齿
//设置屏幕像素比
this.renderer.setPixelRatio(window.devicePixelRatio);
//渲染的尺寸大小
this.renderer.setSize(this.canvasWidth, this.canvasHeight);
//gltf格式模型纹理贴图
this.renderer.outputEncoding = THREE.sRGBEncoding;
// 设置背景颜色
this.renderer.setClearColor(0x000000, 0);
// 添加到容器
this.container.appendChild(this.renderer.domElement);
}
render() {
this.renderer.render(this.scene, this.camera);
}
animate() {
this.renderer.setAnimationLoop(this.render.bind(this));
}
initControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
}
onWindowResize() {
this.camera.aspect = this.canvasWidth / this.canvasHeight;
this.camera.updateProjectionMatrix(); //更新矩阵将3d内容投射到2d画面上转换
this.renderer.setSize(this.canvasWidth, this.canvasHeight);
}
addGLTFModel(obj) {
this.modelInfo = obj;
return new Promise((resolve, reject) => {
const loader = new GLTFLoader(); //.setPath('3dModels/')
loader.load(obj.model_url, (gltf) => {
console.log(gltf);
this.scene.add(gltf.scene);
resolve("模型添加成功");
});
});
}
canvasToBase(cb) {
this.renderer.render(this.scene, this.camera);
let imgData = this.renderer.domElement.toDataURL("image/png");
console.log(imgData);
let base64 = imgData.replace(/^data:image\/\w+;base64,/, "");
let dataBuffer = new Buffer(base64, "base64");
base64ToFile(base64, "image/png", "poster.png");
console.log(process.cwd());
$root_home_index.$sendElectronChanel("newDir", {
name: this.modelInfo.model_name,
paths: [process.cwd(), "model_thumb"],
buffer: dataBuffer,
});
$root_home_index.$recvElectronChanel("newDirRes", (e, res) => {
// $root_home_index.$message.info(res)
cb(res);
});
/*;*/
}
clearScene() {
this.scene.traverse((child) => {
if (child.material) {
child.material.dispose();
}
if (child.geometry) {
child.geometry.dispose();
}
child = null;
});
this.container.childNodes[1].remove();
this.renderer.forceContextLoss();
this.renderer.dispose();
this.scene.clear();
this.modelInfo = {};
this.scene = null;
this.camera = null;
this.controls = null;
this.renderer.domElement = null;
this.renderer = null;
this.container = null;
}
}
class viewGlbByEarth {
constructor(selector) {
this.viewer = null;
this.modelInfo = null;
this.selector = selector;
this.init(selector);
}
init(selector) {
this.viewer = new Cesium.Viewer(selector, {
skyBox: false,
timeline: false,
navigationHelpButton: false,
homeButton: false,
baseLayerPicker: false,
sceneModePicker: false,
animation: false,
});
const scene = this.viewer.scene;
/*this.viewer.scene.screenSpaceCameraController.tiltEventTypes = [
Cesium.CameraEventType.PINCH,
Cesium.CameraEventType.RIGHT_DRAG,
]*/
scene.screenSpaceCameraController.zoomEventTypes = [
Cesium.CameraEventType.WHEEL,
Cesium.CameraEventType.PINCH,
];
scene.screenSpaceCameraController.tiltEventTypes = [
Cesium.CameraEventType.PINCH,
Cesium.CameraEventType.RIGHT_DRAG,
];
this.viewer._cesiumWidget._creditContainer.style.display = "none";
scene.globe.depthTestAgainstTerrain = true;
// scene.globe.show = false;
// scene.sun.show = false;
// scene.moon.show = false;
// scene.skyBox.show = false;
// scene.fog.enabled = false;
}
addGltf(obj) {
this.modelInfo = obj;
const czml = [
{
id: "aircraft model",
name: "Cesium Air",
position: {
cartographicDegrees: [-77, 37, 10000],
},
model: {
gltf: obj.model_url,
scale: 2.0,
minimumPixelSize: 128,
},
},
];
let entity = this.viewer.entities.add({
position: Cesium.Cartesian3.fromRadians(
106.31593773128115,
29.625102082951624
),
model: {
uri: obj.model_url,
},
});
this.viewer.trackedEntity = entity;
}
canvasToBase(cb) {
// let imgData = $(`#${this.selector}`).find("canvas")[0].toDataURL("image/png");
// console.log(imgData)
this.viewer.render();
let imgData = this.viewer.scene.canvas.toDataURL("image/png");
let base64 = imgData.replace(/^data:image\/\w+;base64,/, "");
let dataBuffer = new Buffer(base64, "base64");
let file = this.base64ToFile(base64, "image/png", "poster.png");
// console.log("ddddddddddddd", file);
cb(file);
// $root_home_index.$sendElectronChanel("newDir", {
// name: this.modelInfo.model_name, //+ "_" + new Date().getTime(),
// paths: [process.cwd(), "model_thumb"],
// buffer: dataBuffer,
// });
// $root_home_index.$recvElectronChanel("newDirRes", (e, res) => {
// // $root_home_index.$message.info(res)
// cb(res);
// });
/*;*/
}
base64ToFile(base64, mime, filename) {
// let arr = base64.split(",");
let type = mime || arr[0].match(/:(.*?);/)[1];
// let suffix = mine.split("/")[1];
// let fileName = filename || `未命名.${suffix}`;
let fileName = filename || `未命名.png`;
let bstr = atob(base64);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], fileName, { type });
}
clearScene() {
this.viewer.destroy();
this.viewer = null;
this.modelInfo = null;
this.selector = "";
}
}
export { viewGlb, viewGlbByEarth };