Browse Source
- 添加 CatalogDefine 组件,用于编辑楼层目录结构 - 在 ModelMain 中集成 CatalogDefine 组件 - 实现目录树展示、添加目录、添加楼层、删除节点等功能 - 采用 Vue 3 的 <script setup> 语法,支持 TypeScript - 使用 Element Plus组件库master
2 changed files with 266 additions and 2 deletions
@ -0,0 +1,263 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { computed, createVNode, reactive, useTemplateRef } from "vue"; |
||||
|
import { ElButton, ElSpace, ElTree } from "element-plus"; |
||||
|
import YvSrcEditor from "@/components/YvSrcEditor.vue"; |
||||
|
import DataForm from "@/components/data-form/DataForm.vue"; |
||||
|
import lodash from "lodash"; |
||||
|
|
||||
|
defineOptions({ |
||||
|
name: 'CatalogDefine', |
||||
|
}); |
||||
|
|
||||
|
// 组件事件定义 |
||||
|
// const emit = defineEmits<{ |
||||
|
// /** 更新内联表格数据 */ |
||||
|
// "event01": [param01: string]; |
||||
|
// }>(); |
||||
|
|
||||
|
// 定义 Props 类型 |
||||
|
interface CatalogDefineProps { |
||||
|
} |
||||
|
|
||||
|
// 读取组件 props 属性 |
||||
|
const props = withDefaults(defineProps<CatalogDefineProps>(), {}); |
||||
|
|
||||
|
// 定义 State 类型 |
||||
|
interface CatalogDefineState { |
||||
|
// forceUpdateForCatalog: number; |
||||
|
} |
||||
|
|
||||
|
// state 属性 |
||||
|
const state = reactive<CatalogDefineState>({ |
||||
|
// forceUpdateForCatalog: Number.MIN_VALUE, |
||||
|
}); |
||||
|
|
||||
|
// 定义 Data 类型 |
||||
|
interface CatalogDefineData { |
||||
|
} |
||||
|
|
||||
|
// 内部数据 |
||||
|
const data: CatalogDefineData = {}; |
||||
|
const tree = useTemplateRef<InstanceType<typeof ElTree>>("treeRef"); |
||||
|
const worldModel = computed(() => window['worldModel']); |
||||
|
const catalog = computed<Array<any>>(() => { |
||||
|
// state.forceUpdateForCatalog; |
||||
|
return worldModel.value?.state?.catalog; |
||||
|
}); |
||||
|
const catalogTree = computed(() => { |
||||
|
const array = catalog.value; |
||||
|
const tree: Array<any> = []; |
||||
|
if (array) { |
||||
|
for (let item of array) { |
||||
|
const node: any = { |
||||
|
id: item.label, |
||||
|
label: item.label, |
||||
|
data: item, |
||||
|
}; |
||||
|
tree.push(node); |
||||
|
if (item.items && item.items.length > 0) { |
||||
|
node.children = []; |
||||
|
for (let row of item.items) { |
||||
|
const child = { |
||||
|
pid: item.label, |
||||
|
id: `${item.label}_${row.catalogCode}`, |
||||
|
label: row.label, |
||||
|
data: row, |
||||
|
}; |
||||
|
node.children.push(child); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return tree; |
||||
|
}); |
||||
|
const catalogJson = computed(() => { |
||||
|
if (catalog.value) return JSON.stringify(catalog.value, null, 4); |
||||
|
return ""; |
||||
|
}); |
||||
|
|
||||
|
function addCatalog() { |
||||
|
const data = { |
||||
|
label: "", |
||||
|
}; |
||||
|
system.showDialog(createVNode(DataForm, { |
||||
|
style: { |
||||
|
paddingRight: "12px", |
||||
|
}, |
||||
|
data: data, |
||||
|
formFields: [ |
||||
|
{ |
||||
|
dataPath: 'label', label: '目录名称', input: 'Input', |
||||
|
inputProps: { |
||||
|
placeholder: '目录名称', |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
columnCount: 1, |
||||
|
labelWidth: "80px", |
||||
|
}), { |
||||
|
title: '添加目录', |
||||
|
width: 480, |
||||
|
height: 150, |
||||
|
showClose: true, |
||||
|
showMax: false, |
||||
|
showCancelButton: true, |
||||
|
showOkButton: true, |
||||
|
okButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
}).then(() => { |
||||
|
const label = lodash.trim(data.label); |
||||
|
if (!label) { |
||||
|
system.msg("目录名称不能为空"); |
||||
|
return; |
||||
|
} |
||||
|
catalog.value.push({ label, items: [] }); |
||||
|
}).finally(); |
||||
|
} |
||||
|
|
||||
|
function addItem() { |
||||
|
const node = tree.value?.getCurrentNode(); |
||||
|
const catalogData = node?.data; |
||||
|
if (!catalogData?.items) { |
||||
|
system.msg("必须先选择一个目录"); |
||||
|
return; |
||||
|
} |
||||
|
// console.log("node", node); |
||||
|
const data = { |
||||
|
label: "", |
||||
|
catalogCode: "", |
||||
|
}; |
||||
|
system.showDialog(createVNode(DataForm, { |
||||
|
style: { |
||||
|
paddingRight: "12px", |
||||
|
}, |
||||
|
data: data, |
||||
|
formFields: [ |
||||
|
{ |
||||
|
dataPath: 'catalogCode', label: '楼层编码', input: 'Input', |
||||
|
inputProps: { |
||||
|
placeholder: '楼层唯一编码', |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
dataPath: 'label', label: '楼层名称', input: 'Input', |
||||
|
inputProps: { |
||||
|
placeholder: '楼层名称', |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
columnCount: 1, |
||||
|
labelWidth: "80px", |
||||
|
}), { |
||||
|
title: '添加楼层', |
||||
|
width: 480, |
||||
|
height: 150, |
||||
|
showClose: true, |
||||
|
showMax: false, |
||||
|
showCancelButton: true, |
||||
|
showOkButton: true, |
||||
|
okButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
}).then(() => { |
||||
|
const catalogCode = lodash.trim(data.catalogCode); |
||||
|
const label = lodash.trim(data.label); |
||||
|
if (!catalogCode) { |
||||
|
system.msg("楼层编码不能为空"); |
||||
|
return; |
||||
|
} |
||||
|
if (!label) { |
||||
|
system.msg("楼层名称不能为空"); |
||||
|
return; |
||||
|
} |
||||
|
catalogData.items.push({ label, catalogCode }); |
||||
|
}).finally(); |
||||
|
} |
||||
|
|
||||
|
function del() { |
||||
|
const node = tree.value?.getCurrentNode(); |
||||
|
if (!node) { |
||||
|
system.msg("必须先选择一个节点"); |
||||
|
return; |
||||
|
} |
||||
|
// console.log("node", node); |
||||
|
const nodeData = node.data; |
||||
|
if (node.pid) { |
||||
|
let index = catalog.value.findIndex(item => item.label === node.pid); |
||||
|
if (index >= 0) { |
||||
|
const catalogData = catalog.value[index]; |
||||
|
index = catalogData.items.findIndex(item => item.catalogCode === nodeData.catalogCode); |
||||
|
if (index >= 0) { |
||||
|
catalogData.items.splice(index, 1); |
||||
|
// state.forceUpdateForCatalog++; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
const index = catalog.value.findIndex(item => item.label === nodeData.label); |
||||
|
if (index >= 0) { |
||||
|
catalog.value.splice(index, 1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
interface CatalogDefineExpose { |
||||
|
state: CatalogDefineState; |
||||
|
data: CatalogDefineData; |
||||
|
} |
||||
|
|
||||
|
const expose: CatalogDefineExpose = { |
||||
|
state, |
||||
|
data, |
||||
|
}; |
||||
|
// 定义组件公开内容 |
||||
|
defineExpose(expose); |
||||
|
|
||||
|
export type { |
||||
|
CatalogDefineProps, |
||||
|
CatalogDefineState, |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="flex-row-container root"> |
||||
|
<div class="flex-item-fixed flex-column-container left"> |
||||
|
<ElSpace class="flex-item-fixed tools-top"> |
||||
|
<ElButton @click="addCatalog" :disabled="!catalog">添加目录</ElButton> |
||||
|
<ElButton @click="addItem" :disabled="!catalog">添加楼层</ElButton> |
||||
|
<ElButton @click="del" :disabled="!catalog">删除</ElButton> |
||||
|
</ElSpace> |
||||
|
<div class="catalog-tree"> |
||||
|
<ElTree |
||||
|
ref="treeRef" |
||||
|
:data="catalogTree" |
||||
|
nodeKey="id" |
||||
|
:expandOnClickNode="false" |
||||
|
:highlightCurrent="true" |
||||
|
:defaultExpandAll="true" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="flex-item-fill"> |
||||
|
<YvSrcEditor ref="editorRef" language="json" :modelValue="catalogJson"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped> |
||||
|
.root { |
||||
|
height: 100%; |
||||
|
} |
||||
|
|
||||
|
.left { |
||||
|
width: 300px; |
||||
|
border-right: 1px solid #ece2e2; |
||||
|
} |
||||
|
|
||||
|
.tools-top { |
||||
|
padding: 8px; |
||||
|
border-bottom: 1px solid #ece2e2; |
||||
|
} |
||||
|
|
||||
|
.catalog-tree { |
||||
|
|
||||
|
} |
||||
|
</style> |
||||
Loading…
Reference in new issue