模型库
BIN
resources/java/app/target/graphhopper/edgekv_keys
Normal file
BIN
resources/java/app/target/graphhopper/edgekv_vals
Normal file
BIN
resources/java/app/target/graphhopper/edges
Normal file
BIN
resources/java/app/target/graphhopper/geometry
Normal file
BIN
resources/java/app/target/graphhopper/location_index
Normal file
BIN
resources/java/app/target/graphhopper/nodes
Normal file
BIN
resources/java/app/target/graphhopper/properties
Normal file
BIN
resources/java/app/upload/0123c218d3f448e3bf0b32e2efed801e
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
resources/java/app/upload/09e23d89ad5f4bd6a52645d309592d75.png
Normal file
|
After Width: | Height: | Size: 547 B |
BIN
resources/java/app/upload/0dfbbc0422724d22887fea1d00d86a5c.pbf
Normal file
BIN
resources/java/app/upload/232aff2ab0554ef1907b6ecbd21af1c1.glb
Normal file
BIN
resources/java/app/upload/281f3835d5ff4bff9f531b51dd39448f.png
Normal file
|
After Width: | Height: | Size: 818 B |
BIN
resources/java/app/upload/34122ee24c33423480f0c9385a8f4b9c.glb
Normal file
BIN
resources/java/app/upload/35558ef8c236475cb56d1aaa723d53ab.glb
Normal file
BIN
resources/java/app/upload/43c814039f4a4b2985c3c103bb49b666
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
resources/java/app/upload/4467466a337943cbb94190d837ee05f6
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
resources/java/app/upload/53c0ec558ae74fcd867d4aa26caf4737.pbf
Normal file
BIN
resources/java/app/upload/8464131a67894b11bf142b37c574a91f
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/java/app/upload/b2e8b37fb9d34150b32285196f1c4ed2.pbf
Normal file
BIN
resources/java/app/upload/bb04d60627c741f99a4e4d463ec8fbe9.glb
Normal file
BIN
resources/java/app/upload/cb10be40f66d4ad09f542fbb2e340cc0
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
resources/java/app/upload/d64ca57a83674bf1a94e7e6d33610700.glb
Normal file
BIN
resources/java/app/upload/e09548231eda4389b4702163ee67fff6
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
resources/java/app/upload/f22548bb50774cc3bfe3ef39be48c428.pbf
Normal file
BIN
resources/java/app/upload/fb1b35f596c54768be0bf319eaac27c1.pbf
Normal file
BIN
resources/java/app/upload/fe52021b10ce4a79a9f01c441f02b659
Normal file
|
After Width: | Height: | Size: 11 KiB |
89
src/renderer/src/api/model/index.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import request from '@/axios/request'
|
||||
//模型库
|
||||
export const ModelApi = {
|
||||
//创建模型库
|
||||
createModelDB: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/createModelLibrary`,
|
||||
data
|
||||
})
|
||||
},
|
||||
//导入模型库
|
||||
importModelDB: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/importModelLibrary`,
|
||||
data
|
||||
})
|
||||
},
|
||||
//删除模型
|
||||
delModel: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/deleteModel`,
|
||||
data,
|
||||
})
|
||||
},
|
||||
//删除模型类型
|
||||
delModelType: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/deleteModelType`,
|
||||
data,
|
||||
})
|
||||
},
|
||||
//添加模型类型
|
||||
addModelType: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/addModelType`,
|
||||
data
|
||||
})
|
||||
},
|
||||
//模型类型列表
|
||||
modelTypeList: async () => {
|
||||
return await request.get({
|
||||
url: `/modelLibrary/modelTypeList`
|
||||
})
|
||||
},
|
||||
//添加模型文件
|
||||
addModel: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/addModelFile`,
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
},
|
||||
//根据模型类型查看模型列表
|
||||
showModelByType: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/modelList`,
|
||||
data,
|
||||
// headers: {
|
||||
// 'content-type': 'application/x-www-form-urlencoded'
|
||||
// }
|
||||
})
|
||||
},
|
||||
//更新模型名称和封面
|
||||
updatePoster: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/modelLibrary/uploadModelInfo`,
|
||||
data,
|
||||
headers: {
|
||||
'content-type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
},
|
||||
//默认模型参数设置
|
||||
modelSetting: async (data: any) => {
|
||||
return await request.post({
|
||||
url: `/businessConfig/addBusinessConfig`,
|
||||
data,
|
||||
})
|
||||
},
|
||||
//获取默认模型参数设置
|
||||
getModelSetting: async () => {
|
||||
return await request.get({
|
||||
url: `/businessConfig/list`
|
||||
})
|
||||
},
|
||||
|
||||
}
|
||||
BIN
src/renderer/src/assets/images/model-bg.png
Normal file
|
After Width: | Height: | Size: 924 B |
@ -42,7 +42,7 @@ export const initMapData = async (type, data, cd) => {
|
||||
entityObject = new YJ.Obj.EllipseObject(window.earth, data)
|
||||
break
|
||||
case 'model':
|
||||
entityObject = new YJ.Obj.ModelObject(window.earth, data)
|
||||
entityObject = new YJ.Obj.Model(window.earth, data)
|
||||
break
|
||||
case 'terrain':
|
||||
data.host = baseURL
|
||||
|
||||
@ -74,7 +74,7 @@
|
||||
<template #default="{ row }">
|
||||
<!-- <el-button size="small" @click="handleEdit(row)">编辑</el-button> -->
|
||||
<el-button size="small" @click="handleEdit(row)">预览</el-button>
|
||||
<el-button size="small" @click="handleEdit(row)">更换缩略图</el-button>
|
||||
<el-button size="small" @click="changePhoto(row)">更换缩略图</el-button>
|
||||
<el-button size="small" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -301,6 +301,10 @@ const handleEdit = (row: ModelItem) => {
|
||||
console.log('编辑模型', row)
|
||||
}
|
||||
|
||||
const changePhoto = (row: ModelItem) => {
|
||||
console.log('编辑模型', row)
|
||||
}
|
||||
|
||||
const handleDelete = (row: ModelItem) => {
|
||||
console.log('删除模型', row)
|
||||
}
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
<template>
|
||||
<div class="model-management-container">
|
||||
<div class="equipment_title" style="margin-bottom: 10px">
|
||||
<el-button color="#004b4b" style="border: 1px solid rgba(0, 255, 255, 0.5)">
|
||||
<el-button color="#004b4b" style="border: 1px solid rgba(0, 255, 255, 0.5)" @click="importModelDB">
|
||||
<template #icon>
|
||||
<svg-icon name="leading_in" />
|
||||
</template>
|
||||
<span>选择模型库</span>
|
||||
</el-button>
|
||||
<el-button color="#004b4b" style="border: 1px solid rgba(0, 255, 255, 0.5)">
|
||||
|
||||
<el-button
|
||||
color="#004b4b"
|
||||
style="border: 1px solid rgba(0, 255, 255, 0.5)"
|
||||
@click="createModelDB"
|
||||
>
|
||||
<template #icon>
|
||||
<svg-icon name="leading_in" />
|
||||
</template>
|
||||
@ -26,7 +31,6 @@
|
||||
:data="typeTreeData"
|
||||
draggable
|
||||
ref="treeRef"
|
||||
default-expand-all
|
||||
node-key="id"
|
||||
@node-click="handleTypeClick"
|
||||
@node-contextmenu="handleContextMenu"
|
||||
@ -69,13 +73,12 @@
|
||||
<el-card shadow="hover">
|
||||
<el-table :data="modelList" border style="width: 100%">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="name" label="模型名称" />
|
||||
<el-table-column prop="modelName" label="模型名称" />
|
||||
<el-table-column prop="thumbnail" label="缩略图" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-image
|
||||
style="width: 80px; height: 60px"
|
||||
@click="showImage(row)"
|
||||
:src="row.thumbnail"
|
||||
:src="'http://127.0.0.1:8848' + row.poster"
|
||||
fit="cover"
|
||||
/>
|
||||
</template>
|
||||
@ -83,7 +86,7 @@
|
||||
<el-table-column label="操作">
|
||||
<template #default="{ row }">
|
||||
<!-- <el-button size="small" @click="handleEdit(row)">编辑</el-button> -->
|
||||
<el-button size="small" @click="handleEdit(row)">预览</el-button>
|
||||
<el-button size="small" @click="showImage(row)">预览</el-button>
|
||||
<el-button size="small" @click="handleEdit(row)">更换缩略图</el-button>
|
||||
<el-button size="small" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
@ -107,25 +110,47 @@
|
||||
:menu-items="contextMenu.items"
|
||||
@command="handleMenuCommand"
|
||||
/>
|
||||
|
||||
<!-- 添加类型弹窗 -->
|
||||
<el-dialog v-model="dialogVisible" title="添加模型类型" width="30%" :before-close="handleClose">
|
||||
<el-input v-model="modelType" placeholder="请输入模型类型" />
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="closeDialog">取消</el-button>
|
||||
<el-button type="primary" @click="addType"> 确定 </el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<input ref="fileInput" type="file" hidden @change="handleFileChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, nextTick, onMounted } from 'vue'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import type { TableColumnCtx } from 'element-plus'
|
||||
import contextMenuCom from './contentMenu.vue'
|
||||
import Sortable from 'sortablejs'
|
||||
import { inject } from 'vue'
|
||||
import type { DragEvents } from 'element-plus/es/components/tree/src/model/useDragNode'
|
||||
import type { AllowDropType, NodeDropType, RenderContentContext } from 'element-plus'
|
||||
|
||||
import { ModelApi } from '@/api/model/index'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
$sendElectronChanel,
|
||||
$recvElectronChanel,
|
||||
$changeComponentShow
|
||||
} from '@/utils/communication'
|
||||
const fs = require("fs");
|
||||
const eventBus: any = inject('bus')
|
||||
var clickTreeNode: any = reactive({})
|
||||
|
||||
interface TypeNode {
|
||||
id: string
|
||||
label: string
|
||||
parentId: string | null
|
||||
children?: TypeNode[]
|
||||
createdAt?: string | null
|
||||
updatedAt?: string | null
|
||||
}
|
||||
|
||||
interface ModelItem {
|
||||
@ -133,28 +158,10 @@ interface ModelItem {
|
||||
typeId: string
|
||||
name: string
|
||||
thumbnail: string
|
||||
modelId: string
|
||||
}
|
||||
|
||||
const typeTreeData = ref<TypeNode[]>([
|
||||
{
|
||||
id: '1',
|
||||
label: '一级分类1',
|
||||
parentId: null,
|
||||
children: [
|
||||
{ id: '1-1', label: '二级分类1-1', parentId: '1' },
|
||||
{ id: '1-2', label: '二级分类1-2', parentId: '1' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: '一级分类2',
|
||||
parentId: null,
|
||||
children: [
|
||||
{ id: '2-1', label: '二级分类2-1', parentId: '2' },
|
||||
{ id: '2-2', label: '二级分类2-2', parentId: '2' }
|
||||
]
|
||||
}
|
||||
])
|
||||
const typeTreeData = ref<TypeNode[]>([])
|
||||
|
||||
const modelList = ref<ModelItem[]>([])
|
||||
const currentTypeId = ref<string>('')
|
||||
@ -171,6 +178,140 @@ const treeRef = ref()
|
||||
// @ts-ignore
|
||||
var sortableInstance: any = reactive(null)
|
||||
|
||||
//--------------添加模型类型----------------
|
||||
var dialogVisible: any = ref(false)
|
||||
var modelType: any = ref('')
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
const closeDialog = () => {
|
||||
modelType.value = ''
|
||||
dialogVisible.value = false
|
||||
}
|
||||
const addType = () => {
|
||||
if (!modelType.value) {
|
||||
return ElMessage.warning('请输入模型类型名称')
|
||||
}
|
||||
let params = {
|
||||
name: modelType.value,
|
||||
parentId: clickTreeNode && clickTreeNode.id ? clickTreeNode.id : undefined
|
||||
}
|
||||
ModelApi.addModelType(params).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('添加成功')
|
||||
getModelList()
|
||||
}
|
||||
})
|
||||
modelType.value = ''
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
//获取模型列表
|
||||
eventBus.on('settingPop', (data) => {
|
||||
if (data) {
|
||||
//关闭弹框时更新模型列表
|
||||
// getModelList()
|
||||
getModelListByType(showImageRow.modelTypeId)
|
||||
showImageRow = null
|
||||
}
|
||||
})
|
||||
|
||||
const getModelList = async () => {
|
||||
const res: any = await ModelApi.modelTypeList()
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
let data = transformNestedJson(res.data, 'name', 'label')
|
||||
typeTreeData.value = data
|
||||
}
|
||||
}
|
||||
const transformNestedJson = (data, oldKey, newKey) => {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((item) => transformNestedJson(item, oldKey, newKey))
|
||||
} else if (data && typeof data === 'object') {
|
||||
const newObj = {}
|
||||
for (const key in data) {
|
||||
// 替换键名
|
||||
const currentKey = key === oldKey ? newKey : key
|
||||
// 递归处理子元素
|
||||
newObj[currentKey] = transformNestedJson(data[key], oldKey, newKey)
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
//------------导入模型--------------
|
||||
const fileInput = ref<HTMLInputElement>()
|
||||
|
||||
const triggerUpload = () => {
|
||||
fileInput.value?.click()
|
||||
}
|
||||
const handleFileChange = (e: Event) => {
|
||||
const files = (e.target as HTMLInputElement).files
|
||||
if (files) {
|
||||
const formData = new FormData()
|
||||
formData.append('files', files[0])
|
||||
formData.append('modelTypeId', clickTreeNode.id)
|
||||
ModelApi.addModel(formData).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('导入成功')
|
||||
getModelListByType(clickTreeNode.id)
|
||||
}
|
||||
})
|
||||
// 此处可添加文件验证或预处理逻辑
|
||||
}
|
||||
}
|
||||
//创建模型库
|
||||
const createModelDB = async () => {
|
||||
let option = {
|
||||
title: '创建模型库',
|
||||
filename: 'YJEarth.model',
|
||||
filters: [{ name: '保存库文件', extensions: ['model'] }]
|
||||
}
|
||||
$sendElectronChanel('saveFile', option)
|
||||
$recvElectronChanel('selectedFileItem', (e, path) => {
|
||||
if (path) {
|
||||
let index = path.lastIndexOf('/')
|
||||
let model_lib_path = path.slice(0, index)
|
||||
let model_lib_name = path.slice(index + 1)
|
||||
ModelApi.createModelDB({ name: model_lib_name, path: model_lib_path }).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('创建成功')
|
||||
getModelList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//导入模型库
|
||||
const importModelDB = ()=>{
|
||||
let option = {
|
||||
properties: ["openFile"],
|
||||
filters: [
|
||||
{
|
||||
name: '模型库', //、底图
|
||||
extensions: ['model'],
|
||||
},
|
||||
],
|
||||
};
|
||||
$sendElectronChanel("open-directory-dialog", option);
|
||||
$recvElectronChanel("selectedItem", (e, path) => {
|
||||
if (path.length) addModelDB(path[0]);
|
||||
});
|
||||
}
|
||||
|
||||
const addModelDB = (path)=>{
|
||||
let formData = new FormData()
|
||||
formData.append('modelPath',path)
|
||||
ModelApi.importModelDB(formData).then(res=>{
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('导入成功')
|
||||
getModelList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//拖拽
|
||||
type Node = RenderContentContext['node']
|
||||
|
||||
@ -211,9 +352,9 @@ const allowDrag = (draggingNode: Node) => {
|
||||
//拖拽结束
|
||||
|
||||
//---------------------查看缩略图--------------------
|
||||
|
||||
var showImageRow = null
|
||||
const showImage = (row: any) => {
|
||||
console.log(row, 'image')
|
||||
showImageRow = row
|
||||
eventBus.emit('imagePopDialog', row)
|
||||
eventBus.emit('settingPop', false)
|
||||
}
|
||||
@ -242,6 +383,7 @@ const handleContextMenu = (event: MouseEvent, row: TypeNode) => {
|
||||
{ command: 'delete', label: '删除', icon: 'delModel' }
|
||||
]
|
||||
}
|
||||
clickTreeNode = row
|
||||
|
||||
contextMenu.visible = true
|
||||
}
|
||||
@ -256,18 +398,28 @@ const toggleExpand = (row: any) => {
|
||||
row.collapse()
|
||||
} else {
|
||||
row.expand()
|
||||
// getModelListByType(row.data.id)
|
||||
}
|
||||
} else {
|
||||
// getModelListByType(row.data.id)
|
||||
}
|
||||
getModelListByType(row.data.id)
|
||||
currentTypeId.value = row.id
|
||||
loadModelsByType(row.id)
|
||||
// loadModelsByType(row.id)
|
||||
contextMenu.visible && (contextMenu.visible = false)
|
||||
}
|
||||
const getModelListByType = (id) => {
|
||||
let formData = new FormData()
|
||||
formData.append('modelTypeId', id)
|
||||
ModelApi.showModelByType(formData).then((res) => {
|
||||
modelList.value = res.data
|
||||
})
|
||||
}
|
||||
const divContextMenu = (event: MouseEvent) => {
|
||||
event.preventDefault()
|
||||
contextMenu.x = event.clientX
|
||||
contextMenu.y = event.clientY
|
||||
console.log('空白右击')
|
||||
|
||||
clickTreeNode = null
|
||||
contextMenu.items = [{ command: 'addType', label: '添加类型', icon: 'add' }]
|
||||
|
||||
contextMenu.visible = true
|
||||
@ -275,21 +427,27 @@ const divContextMenu = (event: MouseEvent) => {
|
||||
|
||||
const handleMenuCommand = (command: string) => {
|
||||
const row = contextMenu.currentRow
|
||||
if (!row) return
|
||||
|
||||
switch (command) {
|
||||
case 'add-child':
|
||||
handleAddChildType(row)
|
||||
break
|
||||
case 'import':
|
||||
handleImportModel(row)
|
||||
break
|
||||
case 'rename':
|
||||
handleRenameType(row)
|
||||
break
|
||||
case 'delete':
|
||||
handleDeleteType(row)
|
||||
break
|
||||
if (!row) {
|
||||
//添加类型
|
||||
handleAddType()
|
||||
} else {
|
||||
switch (command) {
|
||||
case 'addType':
|
||||
handleAddType()
|
||||
break
|
||||
case 'add-child':
|
||||
handleAddChildType(row)
|
||||
break
|
||||
case 'import':
|
||||
handleImportModel(row)
|
||||
break
|
||||
case 'rename':
|
||||
handleRenameType(row)
|
||||
break
|
||||
case 'delete':
|
||||
handleDeleteType(row)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,27 +465,30 @@ const handleClick = () => {
|
||||
const loadModelsByType = (typeId: string) => {
|
||||
// 模拟数据加载
|
||||
modelList.value = [
|
||||
{
|
||||
id: '1',
|
||||
typeId: typeId,
|
||||
name: `模型_${typeId}_1`,
|
||||
thumbnail: 'https://picsum.photos/200/150?random=1'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
typeId: typeId,
|
||||
name: `模型_${typeId}_2`,
|
||||
thumbnail: 'https://picsum.photos/200/150?random=2'
|
||||
}
|
||||
// {
|
||||
// id: '1',
|
||||
// typeId: typeId,
|
||||
// name: `模型_${typeId}_1`,
|
||||
// thumbnail: 'https://picsum.photos/200/150?random=1'
|
||||
// },
|
||||
// {
|
||||
// id: '2',
|
||||
// typeId: typeId,
|
||||
// name: `模型_${typeId}_2`,
|
||||
// thumbnail: 'https://picsum.photos/200/150?random=2'
|
||||
// }
|
||||
]
|
||||
}
|
||||
|
||||
const handleAddType = () => {
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const handleAddChildType = (row: TypeNode) => {
|
||||
console.log('添加子类型', row)
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleImportModel = (row: TypeNode) => {
|
||||
console.log('导入模型到', row)
|
||||
triggerUpload()
|
||||
}
|
||||
|
||||
const handleRenameType = (row: TypeNode) => {
|
||||
@ -335,16 +496,147 @@ const handleRenameType = (row: TypeNode) => {
|
||||
}
|
||||
|
||||
const handleDeleteType = (row: TypeNode) => {
|
||||
console.log('删除类型', row)
|
||||
|
||||
ElMessageBox.confirm('是否删除数据?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
let formData = new FormData()
|
||||
formData.append('modelTypeId', row.id)
|
||||
ModelApi.delModelType(formData).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('删除成功')
|
||||
getModelList()
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const handleEdit = (row: ModelItem) => {
|
||||
console.log('编辑模型', row)
|
||||
updatePoster(row)
|
||||
}
|
||||
const updatePoster1 = (row, flag = false, path = '') => {
|
||||
let cb = (c) => {
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('modelId', row.id)
|
||||
formData.append('file', c)
|
||||
ModelApi.updatePoster(formData).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
getModelListByType(row.modelTypeId)
|
||||
ElMessage.success('添加成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!flag) {
|
||||
let option = {
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
{
|
||||
name: '图片',
|
||||
extensions: ['png', 'jpg', 'jpeg']
|
||||
}
|
||||
]
|
||||
}
|
||||
$sendElectronChanel('open-directory-dialog', option)
|
||||
$recvElectronChanel('selectedItem', (e, paths) => {
|
||||
if (paths.length) {
|
||||
cb(paths[0])
|
||||
}
|
||||
})
|
||||
} else {
|
||||
cb(path)
|
||||
}
|
||||
}
|
||||
|
||||
const updatePoster = (row, flag = false, path = "")=> {
|
||||
let that = this;
|
||||
let cb = (c) => {
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('modelId', row.id)
|
||||
formData.append('file', c)
|
||||
ModelApi.updatePoster(formData).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
getModelListByType(row.modelTypeId)
|
||||
ElMessage.success('添加成功')
|
||||
}
|
||||
})
|
||||
};
|
||||
if (!flag) {
|
||||
let option = {
|
||||
properties: ["openFile"],
|
||||
filters: [
|
||||
{
|
||||
name: "图片",
|
||||
extensions: ["png", "jpg", "jpeg"],
|
||||
},
|
||||
],
|
||||
};
|
||||
$sendElectronChanel("open-directory-dialog", option);
|
||||
$recvElectronChanel("selectedItem", (e, paths) => {
|
||||
if (paths.length) {
|
||||
// 取出路径中的文件名
|
||||
let name = getNamefromPath(paths[0]);
|
||||
// 读取文件
|
||||
fs.readFile(paths[0], (err, data) => {
|
||||
const blob = new Blob([data], {
|
||||
type: "image/png, image/jpeg, image/jpg",
|
||||
});
|
||||
var file = new File([blob], `${name}` + ".png");
|
||||
cb(file);
|
||||
});
|
||||
// cb(paths[0]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cb(path);
|
||||
}
|
||||
}
|
||||
|
||||
const getNamefromPath = (path) => {
|
||||
let index = 1;
|
||||
if (path.endsWith(".json")) {
|
||||
index = 2;
|
||||
}
|
||||
let arr = path.split("/");
|
||||
let str = arr[arr.length - index];
|
||||
|
||||
let name = str;
|
||||
if (!path.endsWith(".json")) {
|
||||
let arr1 = str.split(".");
|
||||
arr1.pop();
|
||||
name = arr1.join(".");
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
const handleDelete = (row: ModelItem) => {
|
||||
console.log('删除模型', row)
|
||||
|
||||
ElMessageBox.confirm('是否删除数据?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
let formData = new FormData()
|
||||
formData.append('modelId', row.id)
|
||||
ModelApi.delModel(formData).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('删除成功')
|
||||
getModelListByType(row.modelTypeId)
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
onMounted(() => {
|
||||
getModelList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -486,4 +778,23 @@ const handleDelete = (row: ModelItem) => {
|
||||
color: rgba(255, 255, 255, 1) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
::v-deep .el-input {
|
||||
width: 300px;
|
||||
margin-left: 30px;
|
||||
|
||||
--el-input-placeholder-color: rgba(173, 241, 255, 1) !important;
|
||||
--el-input-placeholder-font-size: 14px;
|
||||
--el-input-text-color: #fff !important;
|
||||
--el-input-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-input-hover-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-input-focus-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
}
|
||||
::v-deep .el-input__wrapper {
|
||||
background-color: rgba(0, 0, 0, 0.5) !important;
|
||||
}
|
||||
::v-deep .el-dialog__title {
|
||||
text-shadow: 0px 0px 9px var(--color-sdk-text-shadow) !important;
|
||||
color: rgba(255, 255, 255, 1) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="set_pup">
|
||||
<el-dialog v-model="isShowPup" :modal="false" draggable>
|
||||
<el-dialog v-model="isShowPup" :modal="false" draggable :close-on-click-modal='false' :destroy-on-close='true'>
|
||||
<template #header>
|
||||
<div class="set_pup_header">
|
||||
<div class="system_title">
|
||||
@ -49,6 +49,7 @@ const activeName = ref('authorize')
|
||||
const isShowPup = ref(false)
|
||||
const open = () => {
|
||||
isShowPup.value = true
|
||||
activeName.value = 'authorize'
|
||||
}
|
||||
const close = () => {
|
||||
isShowPup.value = false
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
<template #content>
|
||||
<div class="content">
|
||||
<span class="custom-divider"></span>
|
||||
<div class="imageCon">
|
||||
<img class="image" :src="rowData.thumbnail" alt="" />
|
||||
<div class="imageCon" ref="threeCanvas">
|
||||
<!-- <img class="image" :src="rowData.thumbnail" alt="" /> -->
|
||||
</div>
|
||||
<div class="inputCon">
|
||||
<span class="label">模型名称</span>
|
||||
@ -33,19 +33,110 @@
|
||||
import { ref, reactive } from 'vue'
|
||||
import { inject } from 'vue'
|
||||
import Dialog from '@/components/dialog/baseDialog.vue'
|
||||
import * as THREE from 'three'
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
|
||||
import { debounce } from '@/utils'
|
||||
import { ModelApi } from '@/api/model/index'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const baseDialog: any = ref(null)
|
||||
const eventBus: any = inject('bus')
|
||||
const viewPointHeight: any = ref(1.8)
|
||||
var rowData: any = reactive([])
|
||||
var imageData: any = ref(null)
|
||||
var newData: any = reactive({
|
||||
name: ''
|
||||
})
|
||||
eventBus.on('imagePopDialog', (data) => {
|
||||
console.log(data, 'data')
|
||||
rowData = data
|
||||
rowData.name = data.modelName
|
||||
baseDialog.value?.open()
|
||||
setTimeout(() => {
|
||||
initThreeJS()
|
||||
loadModel()
|
||||
animate()
|
||||
})
|
||||
})
|
||||
//----------------模型预览---------------
|
||||
const threeCanvas = ref(null)
|
||||
let scene, camera, renderer, model, controls
|
||||
|
||||
const initThreeJS = () => {
|
||||
// 创建场景
|
||||
scene = new THREE.Scene()
|
||||
scene.background = new THREE.Color(0xbfd1e5)
|
||||
// scene.fog = new THREE.Fog(0xbfd1e5, 200, 1000)
|
||||
|
||||
// 创建相机
|
||||
camera = new THREE.PerspectiveCamera(
|
||||
75,
|
||||
threeCanvas.value.clientWidth / threeCanvas.value.clientHeight,
|
||||
0.1,
|
||||
1000
|
||||
)
|
||||
camera.position.set(0, 1, 5)
|
||||
camera.lookAt(0, 0, 0)
|
||||
|
||||
// 创建渲染器并添加到DOM中
|
||||
renderer = new THREE.WebGLRenderer({
|
||||
preserveDrawingBuffer: true,
|
||||
antialias: true
|
||||
})
|
||||
renderer.setSize(threeCanvas.value.clientWidth, threeCanvas.value.clientHeight)
|
||||
renderer.setPixelRatio(window.devicePixelRatio)
|
||||
threeCanvas.value.appendChild(renderer.domElement)
|
||||
|
||||
// 控制器
|
||||
controls = new OrbitControls(camera, renderer.domElement)
|
||||
controls.enableDamping = true // 启用阻尼,增加平滑度
|
||||
controls.dampingFactor = 0.05 // 阻尼系数,默认为0.25
|
||||
controls.screenSpacePanning = false // 平移时是否在屏幕空间中移动,默认false,即在世界空间中移动
|
||||
controls.minDistance = 1 // 最小距离,默认无限制
|
||||
controls.maxDistance = 500 // 最大距离,默认无限制
|
||||
controls.enableZoom = true // 是否可以缩放,默认true
|
||||
controls.zoomSpeed = 1.0 // 缩放速度,默认1.0
|
||||
controls.rotateSpeed = 1.0 // 旋转速度,默认1.0
|
||||
controls.addEventListener('change', render) // 监听控制器变化进行重渲染
|
||||
|
||||
// 添加环境光和点光源
|
||||
const ambientLight = new THREE.AmbientLight(0x404040, 1) // 环境光
|
||||
scene.add(ambientLight)
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
|
||||
scene.add(directionalLight)
|
||||
const light = new THREE.HemisphereLight(0xffffbb, 0x080820, 1)
|
||||
scene.add(light)
|
||||
const pointLight = new THREE.PointLight(0xffffff, 0.8) // 点光源
|
||||
pointLight.position.set(10, 10, 10)
|
||||
pointLight.lookAt(0, 0, 0)
|
||||
scene.add(pointLight)
|
||||
}
|
||||
const loadModel = () => {
|
||||
const loader = new GLTFLoader()
|
||||
loader.load(
|
||||
'http://127.0.0.1:8848' + rowData.data, // 模型路径
|
||||
function (gltf) {
|
||||
// onLoad回调函数
|
||||
model = gltf.scene
|
||||
model.position.set(0, 0, 0)
|
||||
scene.add(model) // 将模型添加到场景中
|
||||
},
|
||||
undefined, // onProgress回调函数,可选参数,用于处理加载进度等,这里不使用所以设置为undefined或提供具体实现函数。
|
||||
function (error) {
|
||||
// onError回调函数,处理加载错误等。
|
||||
console.error('An error happened while loading the model', error)
|
||||
}
|
||||
)
|
||||
}
|
||||
const render = () => {
|
||||
renderer.render(scene, camera) // 重渲染当前场景和相机状态,通常用于控制器监听事件中调用
|
||||
}
|
||||
|
||||
const animate = () => {
|
||||
requestAnimationFrame(animate) // 循环调用animate函数实现动画效果。
|
||||
controls.update() // 更新控制器状态
|
||||
renderer.render(scene, camera) // 渲染场景和相机。
|
||||
}
|
||||
|
||||
const clangeViewPointHeight = () => {}
|
||||
const viewPointHeightInput = () => {
|
||||
@ -57,16 +148,37 @@ const viewPointHeightInput = () => {
|
||||
}
|
||||
}
|
||||
const closeCallBack = (e) => {
|
||||
renderer.domElement.remove() // 从DOM中移除渲染器。
|
||||
imageData.value = null
|
||||
rowData = []
|
||||
newData.name = ''
|
||||
//打开系统设置弹框
|
||||
eventBus.emit('settingPop', true)
|
||||
}
|
||||
|
||||
var posterLoading: any = ref(false)
|
||||
const setImage = (e) => {
|
||||
baseDialog.value?.close()
|
||||
renderer.render(scene, camera) // 确保场景已渲染
|
||||
const canvas = renderer.domElement
|
||||
|
||||
canvas.toBlob((blob) => {
|
||||
imageData.value = blob
|
||||
ElMessage.warning('点击保存是会应用当前图片')
|
||||
}, 'image/png')
|
||||
}
|
||||
const close = (e) => {
|
||||
baseDialog.value?.close()
|
||||
}
|
||||
const save = (e) => {
|
||||
const formData = new FormData()
|
||||
formData.append('modelId', rowData.id)
|
||||
newData.name && formData.append('modelName', newData.name)
|
||||
imageData.value && formData.append('file', imageData.value)
|
||||
ModelApi.updatePoster(formData).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('添加成功')
|
||||
}
|
||||
})
|
||||
baseDialog.value?.close()
|
||||
}
|
||||
</script>
|
||||
|
||||
525
src/renderer/src/views/components/propertyBox/model copy.vue
Normal file
@ -0,0 +1,525 @@
|
||||
<template>
|
||||
<div class="set_pup">
|
||||
<el-dialog v-model="isShowPup" :modal="false" draggable>
|
||||
<template #header>
|
||||
<div class="set_pup_header">
|
||||
<div class="system_title">
|
||||
{{ t('model.title') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="set_detail">
|
||||
<div class="top">
|
||||
<el-input
|
||||
v-model="modelName"
|
||||
class="w-50 m-2"
|
||||
placeholder="请输入模型名称进行搜索"
|
||||
:suffix-icon="Search"
|
||||
/>
|
||||
<button @click="setting" class="btn">
|
||||
<svg-icon
|
||||
name="sys_set"
|
||||
:size="12"
|
||||
color="rgba(var(--color-sdk-base-rgb), 1)"
|
||||
style="margin-right: 5px"
|
||||
></svg-icon
|
||||
>默认模型参数设置
|
||||
</button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<!-- 左侧Tab导航 -->
|
||||
<el-tabs
|
||||
v-model="activeTab"
|
||||
tab-position="left"
|
||||
class="model-tabs"
|
||||
@tab-click="handleTabClick"
|
||||
>
|
||||
<el-tab-pane
|
||||
v-for="(category, index) in categories"
|
||||
:key="index"
|
||||
:label="category.name"
|
||||
:name="index.toString()"
|
||||
>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div class="model-gallery" ref="galleryRef" @scroll="handleScroll">
|
||||
<div
|
||||
v-for="(category, cIndex) in categories"
|
||||
:key="cIndex"
|
||||
class="model-section"
|
||||
:data-category="cIndex"
|
||||
>
|
||||
<h2 class="section-title">{{ category.name }}</h2>
|
||||
<div class="model-grid">
|
||||
<div v-for="(model, mIndex) in category.models" :key="mIndex" class="model-item">
|
||||
<div class="imgbg">
|
||||
<el-image :src="model.thumbnail" fit="cover" class="thumbnail">
|
||||
<template #error>
|
||||
<div class="image-error">加载失败</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</div>
|
||||
|
||||
<div class="model-name">{{ model.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="loading" class="loading-more">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import type { TabsPaneContext } from 'element-plus'
|
||||
const { t } = useI18n()
|
||||
const isShowPup = ref(false)
|
||||
const eventBus: any = inject('bus')
|
||||
var modelName = ref('')
|
||||
|
||||
//tab
|
||||
interface Model {
|
||||
id: string
|
||||
name: string
|
||||
thumbnail: string
|
||||
}
|
||||
|
||||
interface Category {
|
||||
id: string
|
||||
name: string
|
||||
models: Model[]
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const categories = ref<Category[]>([
|
||||
{
|
||||
id: '0',
|
||||
name: '建筑模型',
|
||||
models: Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => ({
|
||||
id: `b${i}`,
|
||||
name: `建筑_${i}`,
|
||||
thumbnail: `https://picsum.photos/300/200?random=${i}`
|
||||
}))
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
name: '海军车',
|
||||
models: Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => ({
|
||||
id: `b${i}`,
|
||||
name: `建筑_${i}`,
|
||||
thumbnail: `https://picsum.photos/300/200?random=${i}`
|
||||
}))
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '装备车',
|
||||
models: Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => ({
|
||||
id: `b${i}`,
|
||||
name: `建筑_${i}`,
|
||||
thumbnail: `https://picsum.photos/300/200?random=${i}`
|
||||
}))
|
||||
}
|
||||
// 其他分类...
|
||||
])
|
||||
|
||||
const activeTab = ref('0')
|
||||
const galleryRef = ref<HTMLElement>()
|
||||
const loading = ref(false)
|
||||
let observer: IntersectionObserver | null = null
|
||||
|
||||
// 处理Tab点击
|
||||
const handleTabClick = (tab: TabsPaneContext) => {
|
||||
const section = document.querySelector(`.model-section[data-category="${tab.index}"]`)
|
||||
section?.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
|
||||
// 初始化交叉观察器
|
||||
const initObserver = () => {
|
||||
observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
const categoryIndex = parseInt(entry.target.getAttribute('data-category') || '0')
|
||||
activeTab.value = categoryIndex.toString()
|
||||
|
||||
// 加载更多检测
|
||||
if (categoryIndex === categories.value.length - 1 && entry.intersectionRatio > 0.5) {
|
||||
loadMoreData()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
threshold: [0, 0.5, 1]
|
||||
}
|
||||
)
|
||||
|
||||
document.querySelectorAll('.model-section').forEach((section) => {
|
||||
observer?.observe(section)
|
||||
})
|
||||
}
|
||||
|
||||
// 模拟加载更多数据
|
||||
const loadMoreData = () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
categories.value.push({
|
||||
id: `${categories.value.length + 1}`,
|
||||
name: `新增分类_${categories.value.length}`,
|
||||
models: Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => ({
|
||||
id: `n${i}`,
|
||||
name: `新增模型_${i}`,
|
||||
thumbnail: `https://picsum.photos/300/200?random=${i + 100}`
|
||||
}))
|
||||
})
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 滚动时检测可见区域
|
||||
const handleScroll = () => {
|
||||
if (!galleryRef.value) return
|
||||
|
||||
const scrollPosition = galleryRef.value.scrollTop + 100
|
||||
const sections = Array.from(document.querySelectorAll('.model-section'))
|
||||
|
||||
sections.forEach((section, index) => {
|
||||
const rect = section.getBoundingClientRect()
|
||||
if (rect.top <= 450 && rect.bottom >= 450) {
|
||||
activeTab.value = index.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initObserver()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
observer?.disconnect()
|
||||
})
|
||||
//end
|
||||
|
||||
eventBus.on('openModel', (data) => {
|
||||
isShowPup.value = data
|
||||
})
|
||||
const open = () => {
|
||||
isShowPup.value = true
|
||||
}
|
||||
const close = () => {
|
||||
isShowPup.value = false
|
||||
}
|
||||
const setting = () => {
|
||||
isShowPup.value = false
|
||||
eventBus.emit('openModelSetting', true)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
close
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.set_pup {
|
||||
width: 40vw;
|
||||
height: 50vh;
|
||||
:deep(.el-dialog) {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(0, 255, 255, 0.2) 0%, rgba(0, 255, 255, 0) 100%),
|
||||
rgba(0, 0, 0, 0.6);
|
||||
border: 1px solid #00c9ff;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
:deep(.el-dialog__headerbtn) {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border-bottom-left-radius: 80%;
|
||||
background-color: #008989;
|
||||
&:hover {
|
||||
background-color: #00ffff;
|
||||
.el-dialog__close {
|
||||
color: rgba(0, 66, 66, 1); // 悬停时改变关闭图标为红色
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-dialog__headerbtn .el-dialog__close) {
|
||||
color: #fff;
|
||||
}
|
||||
.set_pup_header {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// background-color: #00ffff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 20px;
|
||||
.system_title {
|
||||
background: url('@/assets/images/titlebg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
width: 229px;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
text-align: center;
|
||||
font-family: 'alimamashuheiti';
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
.set_detail {
|
||||
box-sizing: border-box;
|
||||
// height: 50vh;
|
||||
:deep(
|
||||
.el-tabs--left .el-tabs__active-bar.is-left,
|
||||
.el-tabs--left .el-tabs__active-bar.is-right,
|
||||
.el-tabs--right .el-tabs__active-bar.is-left,
|
||||
.el-tabs--right .el-tabs__active-bar.is-right
|
||||
) {
|
||||
width: 3px;
|
||||
background: rgba(0, 255, 255, 1);
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
:deep(
|
||||
.el-tabs--left .el-tabs__nav-wrap.is-left::after,
|
||||
.el-tabs--left .el-tabs__nav-wrap.is-right::after,
|
||||
.el-tabs--right .el-tabs__nav-wrap.is-left::after,
|
||||
.el-tabs--right .el-tabs__nav-wrap.is-right::after
|
||||
) {
|
||||
width: 3px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-wrap::after) {
|
||||
background: rgba(204, 204, 204, 0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
// .switchmy {
|
||||
// display: flex;
|
||||
// flex-wrap: wrap;
|
||||
// margin-top: 15px;
|
||||
|
||||
// .center {
|
||||
// width: 33%;
|
||||
// margin-bottom: 15px;
|
||||
// }
|
||||
// }
|
||||
:deep(.el-tabs__content) {
|
||||
height: 50vh;
|
||||
width: 80%;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
// 美化滚动条
|
||||
:deep(.el-tabs__content::-webkit-scrollbar) {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
:deep(.el-tabs__content::-webkit-scrollbar-thumb) {
|
||||
background-color: #0ff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
:deep(.el-tabs__content::-webkit-scrollbar-track) {
|
||||
background-color: rgba(0, 255, 255, 0.2);
|
||||
}
|
||||
:deep(.el-tabs__item) {
|
||||
width: 8vw;
|
||||
color: #fff !important;
|
||||
font-size: 1.1rem;
|
||||
font-family: 黑体;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 3px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:deep(.el-tabs__item:hover) {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 255, 255, 0) 0%,
|
||||
rgba(0, 255, 255, 0.5) 48.91%,
|
||||
rgba(0, 255, 255, 0) 100%
|
||||
);
|
||||
border: 1px solid;
|
||||
box-sizing: border-box;
|
||||
border-image: linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 255, 255, 0) 0%,
|
||||
rgba(0, 255, 255, 1) 55.55%,
|
||||
rgba(0, 255, 255, 0) 100%
|
||||
)
|
||||
1;
|
||||
}
|
||||
:deep(.el-tabs__item.is-active) {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 255, 255, 0) 0%,
|
||||
rgba(0, 255, 255, 0.5) 48.91%,
|
||||
rgba(0, 255, 255, 0) 100%
|
||||
) !important;
|
||||
border: 0.1px solid;
|
||||
// box-sizing: border-box;
|
||||
border-image: linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 255, 255, 0) 0%,
|
||||
rgba(0, 255, 255, 1) 55.55%,
|
||||
rgba(0, 255, 255, 0) 100%
|
||||
)
|
||||
1 !important;
|
||||
}
|
||||
:deep(.el-tabs__header) {
|
||||
height: 50vh !important;
|
||||
width: 8vw;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
:deep(.el-tabs__nav-next, .el-tabs__nav-prev) {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.el-input {
|
||||
width: 300px;
|
||||
margin-left: 30px;
|
||||
|
||||
--el-input-placeholder-color: rgba(173, 241, 255, 1) !important;
|
||||
--el-input-placeholder-font-size: 14px;
|
||||
--el-input-text-color: #fff;
|
||||
--el-input-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-input-hover-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-input-focus-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
}
|
||||
::v-deep .el-input__wrapper {
|
||||
background-color: rgba(0, 0, 0, 0.5) !important;
|
||||
}
|
||||
.btn {
|
||||
float: right;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
background: rgba(var(--color-sdk-base-rgb), 0.2) !important;
|
||||
border: 1px solid rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
border-radius: 4px;
|
||||
color: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.content {
|
||||
margin-top: 20px;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.model-container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
.model-tabs {
|
||||
width: 130px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
}
|
||||
.model-gallery {
|
||||
flex: 1;
|
||||
/* padding: 20px; */
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
width: calc(100% - 130px);
|
||||
float: left;
|
||||
}
|
||||
.model-section {
|
||||
min-height: 10vh;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.model-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* justify-content: space-around; */
|
||||
gap: 20px;
|
||||
}
|
||||
.model-item {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
/* box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); */
|
||||
}
|
||||
.model-name {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
.imgbg {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background: url('@/assets/images/model-bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.thumbnail {
|
||||
width: 66px;
|
||||
height: 66px;
|
||||
margin-left: 2px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.loading-more {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
::v-deep .el-tabs__content {
|
||||
display: none !important;
|
||||
}
|
||||
/* 修改滚动条轨道的颜色 */
|
||||
::v-deep ::-webkit-scrollbar-track {
|
||||
background: rgba(var(--color-sdk-base-rgb), 0.1) !important;
|
||||
}
|
||||
/* 修改滚动条滑块的样式 */
|
||||
::v-deep ::-webkit-scrollbar-thumb {
|
||||
background: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* 当滑块被激活(用户点击或拖动时) */
|
||||
::v-deep ::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
/* 定义背景颜色和圆角 */
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 1em;
|
||||
background-color: rgba(50, 50, 50, 0.3);
|
||||
}
|
||||
/* //定义滚动条轨道 内阴影+圆角 */
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 1em;
|
||||
background-color: rgba(50, 50, 50, 0.1);
|
||||
}
|
||||
</style>
|
||||
@ -8,26 +8,413 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="set_detail"></div>
|
||||
<div class="set_detail">
|
||||
<div class="top">
|
||||
<el-input
|
||||
v-model="modelName"
|
||||
class="w-50 m-2"
|
||||
placeholder="请输入模型名称进行搜索"
|
||||
:suffix-icon="Search"
|
||||
/>
|
||||
<button @click="setting" class="btn">
|
||||
<svg-icon
|
||||
name="sys_set"
|
||||
class="setIcon"
|
||||
:size="12"
|
||||
color="rgba(255,255,255, 1)"
|
||||
style="margin-right: 5px"
|
||||
></svg-icon
|
||||
>默认模型参数设置
|
||||
</button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<!-- 左侧Tab导航 -->
|
||||
<div class="treeCon">
|
||||
<el-tree style="max-width: 600px" :data="typeTreeData" ref="treeRef" node-key="id">
|
||||
<template #default="{ node, data }">
|
||||
<!-- <span> {{ node.label }}</span> -->
|
||||
|
||||
<span
|
||||
:class="{
|
||||
'primary-type': !(node.childNodes.length != 0),
|
||||
'selected-text': node.id === currentTypeId
|
||||
}"
|
||||
@click.stop="toggleExpand(node)"
|
||||
class="allowDrag"
|
||||
>
|
||||
<svg-icon
|
||||
:name="node.expanded ? 'arrow' : 'more'"
|
||||
:size="12"
|
||||
color="rgba(0, 255, 255, 1)"
|
||||
style="margin-right: 5px; margin-left: 5px"
|
||||
v-if="node.childNodes.length != 0"
|
||||
@click.stop="toggleExpand(node)"
|
||||
></svg-icon>
|
||||
{{ node.label }}</span
|
||||
>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
|
||||
<div class="model-gallery" ref="galleryRef">
|
||||
<div class="model-section">
|
||||
<!-- <h2 class="section-title">{{ categories[Number(currentTypeId)].name }}</h2> -->
|
||||
<div class="model-grid">
|
||||
<div
|
||||
v-for="(model, mIndex) in categories"
|
||||
:key="mIndex"
|
||||
class="model-item"
|
||||
@click="modelClick(mIndex, model)"
|
||||
>
|
||||
<div class="imgbg">
|
||||
<el-image
|
||||
:src="'http://127.0.0.1:8848' + model.poster"
|
||||
fit="cover"
|
||||
class="thumbnail"
|
||||
>
|
||||
<template #error>
|
||||
<div class="image-error">加载失败</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</div>
|
||||
|
||||
<div class="model-name" :class="{ isactive: activeIndex == mIndex }">
|
||||
{{ model.modelName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="loading" class="loading-more">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { ModelApi } from '@/api/model/index'
|
||||
import type { TabsPaneContext } from 'element-plus'
|
||||
import { useTreeNode } from '../tree/hooks/treeNode'
|
||||
import { TreeApi } from '@/api/tree'
|
||||
const { t } = useI18n()
|
||||
const { findParentId, findTreeIndex, cusAddNodes } = useTreeNode()
|
||||
const isShowPup = ref(false)
|
||||
const eventBus: any = inject('bus')
|
||||
var modelName = ref('')
|
||||
|
||||
//tab
|
||||
interface Model {
|
||||
id: string
|
||||
name: string
|
||||
thumbnail: string
|
||||
}
|
||||
|
||||
interface Category {
|
||||
id: string
|
||||
modelName: string
|
||||
poster: string
|
||||
data: string
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const categories = ref<Category[]>([])
|
||||
|
||||
const activeTab = ref('0')
|
||||
const galleryRef = ref<HTMLElement>()
|
||||
const loading = ref(false)
|
||||
let observer: IntersectionObserver | null = null
|
||||
|
||||
// 处理Tab点击
|
||||
const handleTabClick = (tab: TabsPaneContext) => {
|
||||
const section = document.querySelector(`.model-section[data-category="${tab.index}"]`)
|
||||
section?.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
|
||||
// 初始化交叉观察器
|
||||
const initObserver = () => {
|
||||
observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
const categoryIndex = parseInt(entry.target.getAttribute('data-category') || '0')
|
||||
activeTab.value = categoryIndex.toString()
|
||||
|
||||
// 加载更多检测
|
||||
if (categoryIndex === categories.value.length - 1 && entry.intersectionRatio > 0.5) {
|
||||
loadMoreData()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
threshold: [0, 0.5, 1]
|
||||
}
|
||||
)
|
||||
|
||||
document.querySelectorAll('.model-section').forEach((section) => {
|
||||
observer?.observe(section)
|
||||
})
|
||||
}
|
||||
|
||||
// 模拟加载更多数据
|
||||
const loadMoreData = () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
categories.value.push({
|
||||
id: `${categories.value.length + 1}`,
|
||||
name: `新增分类_${categories.value.length}`,
|
||||
models: Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => ({
|
||||
id: `n${i}`,
|
||||
name: `新增模型_${i}`,
|
||||
thumbnail: `https://picsum.photos/300/200?random=${i + 100}`
|
||||
}))
|
||||
})
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 滚动时检测可见区域
|
||||
const handleScroll = () => {
|
||||
if (!galleryRef.value) return
|
||||
|
||||
const scrollPosition = galleryRef.value.scrollTop + 100
|
||||
const sections = Array.from(document.querySelectorAll('.model-section'))
|
||||
|
||||
sections.forEach((section, index) => {
|
||||
const rect = section.getBoundingClientRect()
|
||||
if (rect.top <= 450 && rect.bottom >= 450) {
|
||||
activeTab.value = index.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//-----------tree-----------
|
||||
const currentTypeId = ref<string>('')
|
||||
var activeIndex: any = ref(null)
|
||||
|
||||
interface TypeNode {
|
||||
id: string
|
||||
label: string
|
||||
parentId: string | null
|
||||
children?: TypeNode[]
|
||||
}
|
||||
|
||||
const typeTreeData = ref<TypeNode[]>([])
|
||||
const toggleExpand = (row: any) => {
|
||||
console.log('opoop')
|
||||
if (row.childNodes.length != 0) {
|
||||
// row._expanded = !row._expanded
|
||||
// 这里需要调用el-table的toggleRowExpansion方法
|
||||
// 需要通过ref获取table实例
|
||||
// tableRef.value?.toggleRowExpansion(row, row._expanded)
|
||||
|
||||
if (row.expanded) {
|
||||
row.collapse()
|
||||
} else {
|
||||
row.expand()
|
||||
}
|
||||
}
|
||||
getModelListByType(row.data.id)
|
||||
currentTypeId.value = row.id
|
||||
// loadModelsByType(row.id)
|
||||
}
|
||||
|
||||
let typeArr = {
|
||||
point: '点',
|
||||
line: '线',
|
||||
area: '面'
|
||||
}
|
||||
const modelClick = (index, row) => {
|
||||
console.log(row, 'dddddd')
|
||||
activeIndex.value = index
|
||||
// let selectedNode = window.treeObj.getSelectedNodes()[0]
|
||||
// if(!selectedNode){
|
||||
// ElMessage.warning('请选择需要添加的文件夹')
|
||||
// return
|
||||
// }
|
||||
|
||||
if (!isSetting) {
|
||||
ElMessage.warning('请先设置模型默认参数')
|
||||
return
|
||||
}
|
||||
|
||||
isShowPup.value = false
|
||||
let id = new YJ.Tools().randomString()
|
||||
let models = new YJ.Obj.BatchModel(
|
||||
window.earth,
|
||||
{
|
||||
id: id,
|
||||
type: typeArr[isSetting.key],
|
||||
spacing: isSetting['value'] * 1,
|
||||
url: 'http://127.0.0.1:8848' + isSetting[row.data]
|
||||
},
|
||||
function (data) {
|
||||
console.log('data,url,source_id', data, row)
|
||||
|
||||
// posiArr.forEach((item, index) => {
|
||||
// let model = new Model(that.sdk, {
|
||||
// id: 'model' + index,
|
||||
// show: that.options.show,
|
||||
// url: that.options.url,
|
||||
// position: item,
|
||||
// rotate: that.options.type == '点' ? undefined : { x: 0, y: 0, z: array[1] && (array[1][index] || array[1]) }
|
||||
// })
|
||||
// that.pointArr.push(model)
|
||||
// })
|
||||
renderModel(data, row)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const renderModel = async (data, model) => {
|
||||
let selectedNode = window.treeObj.getSelectedNodes()[0]
|
||||
let z
|
||||
if (data.positions.length > 0) {
|
||||
data.positions.forEach(async (position, index) => {
|
||||
// let source_id = this.$md5(new Date().getTime() + model.model_name+index);
|
||||
let id = new YJ.Tools().randomString()
|
||||
if (data.type == '面') {
|
||||
z = data.rotate.z
|
||||
} else if (data.type == '线') {
|
||||
z = data.rotate[index]
|
||||
}
|
||||
|
||||
let option = {
|
||||
id: id,
|
||||
position,
|
||||
name: model.modelName + index,
|
||||
show: true,
|
||||
scale: 1,
|
||||
url: model.data,
|
||||
maximumScale: 1,
|
||||
host: 'http://127.0.0.1:8848',
|
||||
rotate: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z
|
||||
}
|
||||
}
|
||||
let Model = await new YJ.Obj.Model(window.earth, option)
|
||||
|
||||
let DbOption = {
|
||||
params: option,
|
||||
id,
|
||||
sourceName: model.modelName + index,
|
||||
sourceType: 'model',
|
||||
parentId: selectedNode
|
||||
? selectedNode.sourceType == 'directory'
|
||||
? selectedNode.id
|
||||
: selectedNode.parentId
|
||||
: undefined
|
||||
}
|
||||
TreeApi.addOtherSource(DbOption)
|
||||
DbOption.isShow = true
|
||||
DbOption.params = JSON.stringify(DbOption.params)
|
||||
cusAddNodes(window.treeObj, DbOption.parentId, [DbOption])
|
||||
// //鼠标右键点击事件
|
||||
Model.onRightClick = () => {}
|
||||
|
||||
// window._entityMap.set(option.id, Model);
|
||||
// Model.onClick = () => {
|
||||
// leftClick(node);
|
||||
// };
|
||||
// let detailOption = JSON.parse(JSON.stringify(Model.options));
|
||||
// detailOption.url = model.model_id + ".glb";
|
||||
// let node = getNodeData(DbOption, detailOption);
|
||||
// addSource(node).then((res) => {
|
||||
// if ([0, 200].includes(res.code)) {
|
||||
// // cusRenderNode(DbOption) DbOption.p_id
|
||||
// cusAddNodes(this.treeObj, DbOption.p_id, [node]);
|
||||
// }
|
||||
// });
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const getModelListByType = (id) => {
|
||||
let formData = new FormData()
|
||||
formData.append('modelTypeId', id)
|
||||
ModelApi.showModelByType(formData).then((res) => {
|
||||
console.log(res.data, 'cccc')
|
||||
categories.value = res.data
|
||||
})
|
||||
}
|
||||
|
||||
const getModelList = async () => {
|
||||
const res: any = await ModelApi.modelTypeList()
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
let data = transformNestedJson(res.data, 'name', 'label')
|
||||
typeTreeData.value = data
|
||||
}
|
||||
}
|
||||
|
||||
const transformNestedJson = (data, oldKey, newKey) => {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((item) => transformNestedJson(item, oldKey, newKey))
|
||||
} else if (data && typeof data === 'object') {
|
||||
const newObj = {}
|
||||
for (const key in data) {
|
||||
// 替换键名
|
||||
const currentKey = key === oldKey ? newKey : key
|
||||
// 递归处理子元素
|
||||
newObj[currentKey] = transformNestedJson(data[key], oldKey, newKey)
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initObserver()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
observer?.disconnect()
|
||||
})
|
||||
//end
|
||||
|
||||
eventBus.on('openModel', (data) => {
|
||||
isShowPup.value = data
|
||||
if (data) {
|
||||
getModelList()
|
||||
getSetting()
|
||||
}
|
||||
})
|
||||
eventBus.on('closeModelSet', (data) => {
|
||||
isShowPup.value = data
|
||||
if (data) {
|
||||
console.log('设置后')
|
||||
getSetting()
|
||||
}
|
||||
})
|
||||
|
||||
//查看是否有设置模型设置
|
||||
var isSetting = null
|
||||
const getSetting = () => {
|
||||
ModelApi.getModelSetting().then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
isSetting = res.data[res.data.length - 1]
|
||||
console.log(res, 'resres')
|
||||
}
|
||||
})
|
||||
}
|
||||
const open = () => {
|
||||
isShowPup.value = true
|
||||
}
|
||||
const close = () => {
|
||||
isShowPup.value = false
|
||||
}
|
||||
const setting = () => {
|
||||
isShowPup.value = false
|
||||
eventBus.emit('openModelSetting', (true, isSetting))
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
@ -73,7 +460,7 @@ defineExpose({
|
||||
align-items: center;
|
||||
padding-bottom: 20px;
|
||||
.system_title {
|
||||
background: url('../../../../../assets/images/titlebg.png') no-repeat;
|
||||
background: url('@/assets/images/titlebg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
width: 229px;
|
||||
height: 34px;
|
||||
@ -200,5 +587,176 @@ defineExpose({
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.el-input {
|
||||
width: 300px;
|
||||
margin-left: 30px;
|
||||
|
||||
--el-input-placeholder-color: rgba(173, 241, 255, 1) !important;
|
||||
--el-input-placeholder-font-size: 14px;
|
||||
--el-input-text-color: #fff;
|
||||
--el-input-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-input-hover-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-input-focus-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
}
|
||||
::v-deep .el-input__wrapper {
|
||||
background-color: rgba(0, 0, 0, 0.5) !important;
|
||||
}
|
||||
.btn {
|
||||
float: right;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
background: rgba(var(--color-sdk-base-rgb), 0.2) !important;
|
||||
border: 1px solid rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
border-radius: 4px;
|
||||
color: #fff !important;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.btn:hover {
|
||||
color: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
border: 1px solid rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
.setIcon {
|
||||
color: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 20px;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.model-container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
.model-tabs {
|
||||
width: 130px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
}
|
||||
.treeCon {
|
||||
width: 140px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
border-right: 1px solid rgba(204, 204, 204, 0.2);
|
||||
}
|
||||
.model-gallery {
|
||||
flex: 1;
|
||||
/* padding: 20px; */
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
width: calc(100% - 160px);
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.model-section {
|
||||
min-height: 10vh;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.model-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* justify-content: space-around; */
|
||||
gap: 20px;
|
||||
}
|
||||
.model-name {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
.isactive {
|
||||
color: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
}
|
||||
.model-item {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
/* box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); */
|
||||
}
|
||||
.model-item:hover {
|
||||
cursor: pointer !important;
|
||||
color: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
.model-name {
|
||||
color: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.imgbg {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background: url('@/assets/images/model-bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.thumbnail {
|
||||
width: 66px;
|
||||
height: 66px;
|
||||
margin-left: 2px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.loading-more {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
::v-deep .el-tabs__content {
|
||||
display: none !important;
|
||||
}
|
||||
/* 修改滚动条轨道的颜色 */
|
||||
::v-deep ::-webkit-scrollbar-track {
|
||||
background: rgba(var(--color-sdk-base-rgb), 0.1) !important;
|
||||
}
|
||||
/* 修改滚动条滑块的样式 */
|
||||
::v-deep ::-webkit-scrollbar-thumb {
|
||||
background: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* 当滑块被激活(用户点击或拖动时) */
|
||||
::v-deep ::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(var(--color-sdk-base-rgb), 1) !important;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
/* 定义背景颜色和圆角 */
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 1em;
|
||||
background-color: rgba(50, 50, 50, 0.3);
|
||||
}
|
||||
/* //定义滚动条轨道 内阴影+圆角 */
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 1em;
|
||||
background-color: rgba(50, 50, 50, 0.1);
|
||||
}
|
||||
|
||||
/* tree */
|
||||
.el-tree-node__content > .el-tree-node__expand-icon {
|
||||
display: none !important;
|
||||
}
|
||||
.el-tree {
|
||||
background: transparent !important;
|
||||
--el-tree-node-hover-bg-color: rgba(var(--color-sdk-base-rgb), 0.2) !important;
|
||||
color: rgba(255, 255, 255, 1) !important;
|
||||
/* font-size: 12px !important; */
|
||||
width: 130px;
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
::v-deep .el-text {
|
||||
color: rgba(255, 255, 255, 1) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
.selected-text {
|
||||
color: rgba(var(--color-sdk-base-rgb), 1) !important; /* Element UI主色,可自定义 */
|
||||
}
|
||||
::v-deep .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
|
||||
border-right: 1px solid rgba(var(--color-sdk-base-rgb), 0.2) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
479
src/renderer/src/views/components/propertyBox/modelObject.vue
Normal file
@ -0,0 +1,479 @@
|
||||
<template>
|
||||
<Dialog
|
||||
ref="baseDialog"
|
||||
:title="title + '属性'"
|
||||
left="180px"
|
||||
top="100px"
|
||||
className="polygon"
|
||||
:closeCallback="closeCallback"
|
||||
>
|
||||
<template #content>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row" style="align-items: flex-start">
|
||||
<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>
|
||||
|
||||
<div class="div-item">
|
||||
<div class="row" style="align-items: flex-start">
|
||||
<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="input-number input-number-unit-1 height-box"
|
||||
:class="{ disabled: heightMode == 2 }"
|
||||
>
|
||||
<input
|
||||
class="input height"
|
||||
type="number"
|
||||
title=""
|
||||
min="-9999999"
|
||||
max="999999999"
|
||||
v-model="height"
|
||||
/>
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="align-items: flex-start">
|
||||
<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="input-number input-number-unit-1 height-box"
|
||||
:class="{ disabled: heightMode == 2 }"
|
||||
>
|
||||
<input
|
||||
class="input height"
|
||||
type="number"
|
||||
title=""
|
||||
min="-9999999"
|
||||
max="999999999"
|
||||
v-model="height"
|
||||
/>
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="align-items: flex-start">
|
||||
<div class="col">
|
||||
<span class="label">高度</span>
|
||||
<div
|
||||
class="input-number input-number-unit-1 height-box"
|
||||
:class="{ disabled: heightMode == 2 }"
|
||||
>
|
||||
<input
|
||||
class="input height"
|
||||
type="number"
|
||||
title=""
|
||||
min="-9999999"
|
||||
max="999999999"
|
||||
v-model="height"
|
||||
/>
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">固定大小</span>
|
||||
<input class="btn-switch" type="checkbox" v-model="entityOptions.labelShow" />
|
||||
</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">
|
||||
<div class="row">
|
||||
<div class="row">
|
||||
<p class="lable-left-line">旋转</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">x 轴</span>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
v-model="entityOptions.transparency"
|
||||
/>
|
||||
<div
|
||||
class="input-number input-number-unit-1"
|
||||
style="width: auto; margin-left: 10px"
|
||||
>
|
||||
<input
|
||||
style="width: 100px"
|
||||
type="number"
|
||||
title=""
|
||||
min="0"
|
||||
max="360"
|
||||
v-model="entityOptions.transparency"
|
||||
/>
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">y 轴</span>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
v-model="entityOptions.transparency"
|
||||
/>
|
||||
<div
|
||||
class="input-number input-number-unit-1"
|
||||
style="width: auto; margin-left: 10px"
|
||||
>
|
||||
<input
|
||||
style="width: 100px"
|
||||
type="number"
|
||||
title=""
|
||||
min="0"
|
||||
max="360"
|
||||
v-model="entityOptions.transparency"
|
||||
/>
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">z 轴</span>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
v-model="entityOptions.transparency"
|
||||
/>
|
||||
<div
|
||||
class="input-number input-number-unit-1"
|
||||
style="width: auto; margin-left: 10px"
|
||||
>
|
||||
<input
|
||||
style="width: 100px"
|
||||
type="number"
|
||||
title=""
|
||||
min="0"
|
||||
max="360"
|
||||
v-model="entityOptions.transparency"
|
||||
/>
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row">
|
||||
<div width="46%">
|
||||
<p class="lable-left-line">缩放</p>
|
||||
<el-checkbox
|
||||
v-model="entityOptions.transparency"
|
||||
label="是否等比例缩放"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="标准风格" name="3">
|
||||
<div class="row">
|
||||
<!-- <div class="col">
|
||||
<span class="label">面颜色</span>
|
||||
<div class="color" ref="colorRef"></div>
|
||||
</div> -->
|
||||
<div class="col">
|
||||
<span class="label">描边颜色</span>
|
||||
<div class="lineColor" ref="lineColorRef"></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="99"
|
||||
v-model="entityOptions.lineWidth"
|
||||
/>
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="标签风格" name="4">
|
||||
<labelStyle :type="title" :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>
|
||||
<button style="margin-left: 10px" @click="translate">
|
||||
<svg class="icon-py">
|
||||
<use xlink:href="#yj-icon-py"></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 title = ref('面')
|
||||
const baseDialog: any = ref(null)
|
||||
const eventBus: any = inject('bus')
|
||||
const options = ref({})
|
||||
const colorRef = ref(null)
|
||||
const lineColorRef = ref(null)
|
||||
eventBus.on('openPolygonEdit', () => {
|
||||
baseDialog.value?.open()
|
||||
})
|
||||
|
||||
const area = ref(0)
|
||||
const areaUnit = ref('m2')
|
||||
const height = ref(10)
|
||||
const heightModeData = ref([
|
||||
{
|
||||
name: '海拔高度',
|
||||
value: '海拔高度',
|
||||
key: 0
|
||||
},
|
||||
{
|
||||
name: '相对地表',
|
||||
value: '相对地表',
|
||||
key: 1
|
||||
},
|
||||
{
|
||||
name: '依附模型',
|
||||
value: '依附模型',
|
||||
key: 2
|
||||
}
|
||||
])
|
||||
|
||||
const activeName = ref('1')
|
||||
const activeTd = ref({
|
||||
index: -1,
|
||||
name: ''
|
||||
})
|
||||
const positions = ref([])
|
||||
const heightMode = ref(0)
|
||||
const entityOptions: any = ref({})
|
||||
let originalOptions: any
|
||||
let that: any
|
||||
|
||||
const open = async (id: any, type: any) => {
|
||||
if (type && type === 'rectangle') {
|
||||
title.value = '矩形'
|
||||
} else if (type && type === 'rendezvous') {
|
||||
title.value = '集结地'
|
||||
}
|
||||
that = window.earth.entityMap.get(id)
|
||||
originalOptions = structuredClone(that.options)
|
||||
entityOptions.value = that
|
||||
heightMode.value = entityOptions.value.heightMode
|
||||
area.value = entityOptions.value.areaByMeter
|
||||
positions.value = structuredClone(that.options.positions)
|
||||
that.areaChangeCallBack = () => {
|
||||
switch (areaUnit.value) {
|
||||
case 'm2': //平方米
|
||||
area.value = entityOptions.value.areaByMeter
|
||||
break
|
||||
case 'km2': //平方千米
|
||||
area.value = Number((entityOptions.value.areaByMeter / 1000000).toFixed(8))
|
||||
break
|
||||
case 'mu': //亩
|
||||
area.value = Number((entityOptions.value.areaByMeter / 666.6666667).toFixed(4))
|
||||
break
|
||||
case 'ha': //公顷
|
||||
area.value = Number((entityOptions.value.areaByMeter / 10000).toFixed(6))
|
||||
break
|
||||
default:
|
||||
area.value = entityOptions.value.areaByMeter
|
||||
}
|
||||
}
|
||||
heightModeChange(heightMode.value)
|
||||
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)'
|
||||
} //点击清空按钮事件回调
|
||||
})
|
||||
let linecolorPicker = new window.YJColorPicker({
|
||||
el: lineColorRef.value,
|
||||
size: 'mini', //颜色box类型
|
||||
alpha: true, //是否开启透明度
|
||||
defaultColor: entityOptions.value.lineColor,
|
||||
disabled: false, //是否禁止打开颜色选择器
|
||||
openPickerAni: 'opacity', //打开颜色选择器动画
|
||||
sure: (color) => {
|
||||
entityOptions.value.lineColor = color
|
||||
}, //点击确认按钮事件回调
|
||||
clear: () => {
|
||||
entityOptions.value.lineColor = 'rgba(255,255,255,1)'
|
||||
} //点击清空按钮事件回调
|
||||
})
|
||||
}
|
||||
|
||||
const heightModeChange = (val) => {
|
||||
that.heightMode = heightMode.value
|
||||
}
|
||||
|
||||
const heightConfirm = () => {
|
||||
if (entityOptions.value.operate.positionEditing) {
|
||||
that.positionEditing = false
|
||||
entityOptions.value.height = Number(
|
||||
(entityOptions.value.height + Number(height.value)).toFixed(2)
|
||||
)
|
||||
} else {
|
||||
that.closeNodeEdit(this)
|
||||
that.heightMode = that.heightMode
|
||||
setTimeout(() => {
|
||||
entityOptions.value.height = Number(
|
||||
(entityOptions.value.height + Number(height.value)).toFixed(2)
|
||||
)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
const inputDblclick = async (event, i, anme) => {
|
||||
if (heightMode.value == 2) {
|
||||
return
|
||||
}
|
||||
activeTd.value = {
|
||||
index: i,
|
||||
name: anme
|
||||
}
|
||||
await nextTick()
|
||||
let inputElm = event.target.getElementsByClassName('input')[0]
|
||||
if (inputElm) {
|
||||
inputElm.focus()
|
||||
}
|
||||
}
|
||||
const inputBlurCallBack = (event, i, name, digit = 2) => {
|
||||
activeTd.value = {
|
||||
index: -1,
|
||||
name: ''
|
||||
}
|
||||
}
|
||||
|
||||
const translate = () => {
|
||||
that.openPositionEditing(() => {
|
||||
entityOptions.value.options.positions = structuredClone(that.options.positions)
|
||||
})
|
||||
}
|
||||
|
||||
const closeCallback = () => {
|
||||
entityOptions.value.originalOptions = structuredClone(originalOptions)
|
||||
that.positionEditing = false
|
||||
entityOptions.value.closeNodeEdit()
|
||||
entityOptions.value.reset()
|
||||
eventBus.emit('destroyComponent')
|
||||
}
|
||||
|
||||
const nodeEdit = () => {
|
||||
that.nodeEdit((e, positions, areaByMeter) => {
|
||||
console.log('positions', positions)
|
||||
entityOptions.value.options.positions = structuredClone(positions)
|
||||
})
|
||||
}
|
||||
|
||||
const confirm = () => {
|
||||
originalOptions = structuredClone(that.options)
|
||||
baseDialog.value?.close()
|
||||
let params = structuredClone(that.options)
|
||||
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()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => areaUnit.value,
|
||||
(val) => {
|
||||
if ((entityOptions.value.areaByMeter || entityOptions.value.areaByMeter == 0) && that) {
|
||||
that.areaChangeCallBack()
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
close
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
159
src/renderer/src/views/components/propertyBox/modelSetting.vue
Normal file
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<Dialog
|
||||
ref="baseDialog"
|
||||
title="默认模型参数设置"
|
||||
left="180px"
|
||||
top="100px"
|
||||
:closeCallback="closeCallBack"
|
||||
>
|
||||
<template #content>
|
||||
<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">
|
||||
<el-select
|
||||
v-model="type"
|
||||
class="m-2"
|
||||
placeholder="请选择添加方式"
|
||||
style="width: 240px"
|
||||
@change="typeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" v-show="showDis">
|
||||
<span class="label">间距</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input
|
||||
id="modelDistance"
|
||||
type="number"
|
||||
title=""
|
||||
min="0"
|
||||
max="999999"
|
||||
step="0.1"
|
||||
placeholder="请输入数值"
|
||||
v-model="distance"
|
||||
@input="viewPointHeightInput"
|
||||
@change="clangeViewPointHeight"
|
||||
/>
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button @click="save">保存</button>
|
||||
<button @click="close">关闭</button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { inject } from 'vue'
|
||||
import { ModelApi } from '@/api/model/index'
|
||||
import Dialog from '@/components/dialog/baseDialog.vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
const baseDialog: any = ref(null)
|
||||
const eventBus: any = inject('bus')
|
||||
const viewPointHeight: any = ref(1.8)
|
||||
var visibility: any = reactive([])
|
||||
var showDis: any = ref(false)
|
||||
|
||||
var type: any = ref('point')
|
||||
var distance: any = ref(null)
|
||||
|
||||
const options = [
|
||||
{
|
||||
value: 'point',
|
||||
label: '点'
|
||||
},
|
||||
{
|
||||
value: 'line',
|
||||
label: '线'
|
||||
},
|
||||
{
|
||||
value: 'area',
|
||||
label: '面'
|
||||
}
|
||||
]
|
||||
eventBus.on('openModelSetting', (show,data) => {
|
||||
baseDialog.value?.open()
|
||||
show&& (type.value = show.key)
|
||||
show&& (distance.value = show.value * 1)
|
||||
typeChange()
|
||||
console.log(show,'data')
|
||||
})
|
||||
|
||||
const typeChange = () => {
|
||||
switch (type.value) {
|
||||
case 'point':
|
||||
showDis.value = false
|
||||
break
|
||||
case 'line':
|
||||
showDis.value = true
|
||||
break
|
||||
case 'area':
|
||||
showDis.value = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const clangeViewPointHeight = () => {}
|
||||
const viewPointHeightInput = () => {
|
||||
let dom: any = document.getElementById('modelDistance')
|
||||
if (viewPointHeight.value < dom.min * 1) {
|
||||
viewPointHeight.value = dom.min * 1
|
||||
} else if (viewPointHeight.value > dom.max * 1) {
|
||||
viewPointHeight.value = dom.max * 1
|
||||
}
|
||||
}
|
||||
const closeCallBack = (e) => {
|
||||
type.value = 'point'
|
||||
distance.value = null
|
||||
eventBus.emit('closeModelSet', true)
|
||||
}
|
||||
const close = () => {
|
||||
baseDialog.value?.close()
|
||||
}
|
||||
const save = () => {
|
||||
ModelApi.modelSetting({
|
||||
key: type.value,
|
||||
value: showDis.value ? distance.value : ''
|
||||
}).then((res) => {
|
||||
if (res.code == 0 || res.code == 200) {
|
||||
ElMessage.success('设置成功')
|
||||
baseDialog.value?.close()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
::v-deep .el-select__wrapper {
|
||||
background-color: rgba(0, 0, 0, 0.5) !important;
|
||||
box-shadow: 0 0 0 1px rgba(var(--color-sdk-base-rgb), 0.5) inset !important;
|
||||
}
|
||||
::v-deep .el-select {
|
||||
--el-select-input-focus-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-select-text-color: #fff;
|
||||
--el-select-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-select-hover-border-color: rgba(var(--color-sdk-base-rgb), 0.5) !important;
|
||||
--el-select-multiple-input-color: #fff !important;
|
||||
}
|
||||
::v-deep .el-select__placeholder {
|
||||
color: rgba(204, 204, 204, 1) !important;
|
||||
}
|
||||
</style>
|
||||
@ -10,8 +10,14 @@
|
||||
<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>
|
||||
@ -37,6 +43,8 @@
|
||||
|
||||
<!-- 图标列表 -->
|
||||
<selectImg ref="selectImgRef"></selectImg>
|
||||
<modelSetting ref="modelsetting"></modelSetting>
|
||||
<modelObject ref="modelobject"></modelObject>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@ -97,6 +105,8 @@ import imagePop from '../components/propertyBox/imagePop.vue'
|
||||
import model from '../components/propertyBox/model.vue'
|
||||
import waterSurface from '../components/propertyBox/waterSurface.vue'
|
||||
import { addMapSource } from '../../common/addMapSource'
|
||||
import modelSetting from '../components/propertyBox/modelSetting.vue'
|
||||
import modelObject from '../components/propertyBox/modelObject.vue'
|
||||
|
||||
import { GisApi } from '@/api/gisApi'
|
||||
|
||||
@ -219,6 +229,8 @@ eventBus.on('openDialog', async (sourceType: any, id: any) => {
|
||||
break
|
||||
case 'scanStereoscopic':
|
||||
currentComponent.value = radarScanStereoscopic
|
||||
case 'model':
|
||||
currentComponent.value = modelObject
|
||||
await nextTick()
|
||||
dynamicComponentRef.value?.open(id)
|
||||
break
|
||||
@ -268,8 +280,7 @@ eventBus.on('destroyComponent', (id) => {
|
||||
dynamicComponentRef.value?.close()
|
||||
currentComponent.value = undefined
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
currentComponent.value = undefined
|
||||
}
|
||||
})
|
||||
@ -298,7 +309,7 @@ const createEarth = async () => {
|
||||
// })
|
||||
break
|
||||
case 'attribute':
|
||||
let node = window.treeObj.getNodeByParam("id", object.id, null);
|
||||
let node = window.treeObj.getNodeByParam('id', object.id, null)
|
||||
rightMenus.edit.callback(eventBus, node)
|
||||
break
|
||||
}
|
||||
@ -361,9 +372,9 @@ const getStatus = (time) => {
|
||||
const currentTimestamp = Date.now()
|
||||
|
||||
if (timestamp > currentTimestamp) {
|
||||
(window as any).checkAuthIsValid = true
|
||||
;(window as any).checkAuthIsValid = true
|
||||
} else {
|
||||
(window as any).checkAuthIsValid = false
|
||||
;(window as any).checkAuthIsValid = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||