From 96be59a64cc1d8fcaf1034e787717663c68df4a7 Mon Sep 17 00:00:00 2001 From: 杨磊 <505174330@qq.com> Date: 星期一, 26 五月 2025 10:39:58 +0800 Subject: [PATCH] 2025-5-26提交 --- src/components/TreeMenu.vue | 746 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 648 insertions(+), 98 deletions(-) diff --git a/src/components/TreeMenu.vue b/src/components/TreeMenu.vue index c5e57bc..55716bb 100644 --- a/src/components/TreeMenu.vue +++ b/src/components/TreeMenu.vue @@ -1,127 +1,677 @@ <template> - <div class="tree-menu"> - <SearchBar @search="handleSearch" /> - <el-tree - ref="treeRef" - :data="filteredData" - :props="defaultProps" - :filter-node-method="filterNode" - default-expand-all - @node-click="handleNodeClick" - > - <template #default="{ node, data }"> - <span class="custom-tree-node"> - <el-icon v-if="data.icon"><component :is="data.icon" /></el-icon> - <span>{{ node.label }}</span> - </span> - </template> - </el-tree> + <div class="tree-menu-box"> + <div class="flex"> + <div class="tree-menu" v-if="$route.name == 'landerModel'"> + <div class="topMenu"> + <span class="topMenu-title">{{ menuName }}</span> + <div + class="btnGroup" + v-if="$route.name == 'landerModel' || $route.name == 'systemUse'" + > + <el-dropdown> + <el-icon class="icon1"><FolderAdd /></el-icon> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item @click="addBtn('parent')" + >鏂板缓棰戦亾</el-dropdown-item + > + <el-dropdown-item + :disabled="selectData ? false : true" + @click="addBtn('child')" + >鏂板缓瀛愰閬�</el-dropdown-item + > + </el-dropdown-menu> + </template> + </el-dropdown> + <el-icon class="icon2" @click="editBtn"><Edit /></el-icon> + <el-icon class="icon3" @click="delBtn"><Delete /></el-icon> + </div> + </div> + + <div v-if="loadTree && $route.name == 'landerModel'"> + <el-tree + ref="treeRef" + :key="treeKey" + :props="defaultProps" + :highlight-current="true" + @node-click="handleNodeClick" + :current-node-key="currentNodeKey" + node-key="key" + :data="filteredData" + :load="loadNode" + :expand-on-click-node="false" + lazy + > + <template #default="{ node, data }"> + <span class="custom-tree-node"> + <el-icon v-if="data.icon" + ><component :is="data.icon" + /></el-icon> + <span>{{ node.label }}</span> + </span> + </template> + </el-tree> + </div> + </div> + + <div class="tree-menu" v-if="$route.name.includes('simulation')"> + <span class="topMenu-title">{{ menuName }}</span> + <div + class="btnGroup" + v-if="$route.name == 'landerModel' || $route.name == 'systemUse'" + > + <el-dropdown> + <el-icon class="icon1"><FolderAdd /></el-icon> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item @click="addBtn('parent')" + >鏂板缓棰戦亾</el-dropdown-item + > + <el-dropdown-item + :disabled="selectData ? false : true" + @click="addBtn('child')" + >鏂板缓瀛愰閬�</el-dropdown-item + > + </el-dropdown-menu> + </template> + </el-dropdown> + <el-icon class="icon2" @click="editBtn"><Edit /></el-icon> + <el-icon class="icon3" @click="delBtn"><Delete /></el-icon> + </div> + <el-tree + ref="treeRef" + :key="treeKey" + :data="visualSimulationTreeData" + :props="defaultProps" + node-key="key" + :current-node-key="simulationKey" + :filter-node-method="filterNode1" + :highlight-current="true" + default-expand-all + @node-click="systemClick" + > + <template #default="{ node, data }"> + <span class="custom-tree-node"> + <el-icon v-if="data.icon"><component :is="data.icon" /></el-icon> + <span>{{ node.label }}</span> + </span> + </template> + </el-tree> + </div> + <div class="tree-menu" v-if="seleStore.curTab == 'systemManage'"> + <el-tree + ref="treeRef" + :data="systemManageTreeData" + :props="defaultProps" + :key="systemKey" + :current-node-key="systemKey" + node-key="key" + :filter-node-method="filterNode1" + default-expand-all + @node-click="systemClick" + :highlight-current="true" + > + <template #default="{ node, data }"> + <span class="custom-tree-node"> + <el-icon v-if="data.icon"><component :is="data.icon" /></el-icon> + <span>{{ node.label }}</span> + </span> + </template> + </el-tree> + </div> + </div> </div> + <el-dialog + v-model="dialogFormVisible" + :title="dialogTitle" + width="500" + @close="closeDialog(formRef)" + > + <el-form :model="form" ref="formRef" :rules="formRules" label-width="140px"> + <el-form-item label="鍚嶇О" prop="name"> + <el-input + v-model="form.name" + autocomplete="off" + placeholder="璇疯緭鍏�" + style="width: 240px" + /> + </el-form-item> + <el-form-item label="缂栫爜" prop="refCode"> + <el-input + v-model="form.refCode" + autocomplete="off" + placeholder="璇疯緭鍏�" + style="width: 240px" + /> + </el-form-item> + <el-form-item label="鎻忚堪"> + <el-input + v-model="form.description" + style="width: 240px" + :rows="2" + type="textarea" + placeholder="璇疯緭鍏�" + /> + </el-form-item> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button @click="closeDialog(formRef)">鍙栨秷</el-button> + <el-button type="primary" @click="submitBtn(formRef)"> 纭畾 </el-button> + </div> + </template> + </el-dialog> </template> <script setup lang="ts"> -import { ref, watch } from 'vue' -import { useRouter } from 'vue-router' -import SearchBar from './SearchBar.vue' -import { Document, FolderOpened } from '@element-plus/icons-vue' - -const router = useRouter() -const treeRef = ref() - +import { + ref, + reactive, + defineProps, + onMounted, + inject, + watch, + nextTick, +} from "vue"; +import { useRoute, useRouter } from "vue-router"; +import type { FormInstance, FormRules } from "element-plus"; +import { ElMessage, ElMessageBox } from "element-plus"; +import { Document, FolderOpened } from "@element-plus/icons-vue"; +import { fa } from "element-plus/es/locale"; +const MG: any = inject("MG"); +const toolClass: any = inject("toolClass"); +import { curStoreInfo } from "@/store/index"; +const seleStore = curStoreInfo(); +const router = useRouter(); +const loadTree = ref(false); +const treeRef = ref(null); +const curSelectNode = ref(); +const props = defineProps<{ + menuItem: string; + modelTreeData: any; + storeInfo: any; +}>(); +const menuName = ref("妯″瀷搴�"); +const filteredData = ref(); +const systemMenuName = ref(""); +const currentNodeKey = ref(1); +const treeKey = ref(0); +const systemKey = ref(0); +const simulationKey = ref(0); +const systemData = ref([]); +const selectData = ref(); +const createParent = ref(false); interface TreeNode { - label: string - path?: string - icon?: string - children?: TreeNode[] + label: string; + path?: string; + icon?: string; + children?: TreeNode[]; } - -const treeData = ref<TreeNode[]>([ - { - label: '妯″瀷绠$悊', - icon: 'FolderOpened', - children: [ - { - label: '鏈烘瀯妯″瀷', - path: '/mechanism', - icon: 'Document' - }, - { - label: '杩愬姩瀛︽ā鍨�', - path: '/kinematic', - icon: 'Document' - } - ] - }, - { - label: '鍙鍖栦豢鐪�', - icon: 'FolderOpened', - children: [ - { - label: '浠跨湡閰嶇疆', - path: '/simulation-config', - icon: 'Document' - }, - { - label: '浠跨湡缁撴灉', - path: '/simulation-result', - icon: 'Document' - } - ] - }, - { - label: '绯荤粺绠$悊', - icon: 'FolderOpened', - children: [ - { - label: '鐢ㄦ埛绠$悊', - path: '/system/user', - icon: 'Document' - }, - { - label: '鏉冮檺璁剧疆', - path: '/system/permission', - icon: 'Document' - } - ] - } -]) - const defaultProps = { - children: 'children', - label: 'label' -} + children: "children", + label: "label", + isLeaf: "leaf", + key: "key", +}; +const route = useRoute(); +const visualSimulationTreeData = ref<TreeNode[]>([ + { + label: "娴嬭瘯浠跨湡", + path: "/testSimulation", + icon: "Document", + key: 0, + }, + { + label: "瀹炴椂浠跨湡", + path: "realTimeSimulation", + icon: "Document", + key: 1, + }, + { + label: "鑷富鍔熻兘", + path: "/autonomousFunction", + icon: "Document", + key: 2, + }, +]); -const filteredData = ref(treeData.value) +const systemManageTreeData = ref<TreeNode[]>([ + { + key: 0, + label: "鏈烘瀯鐢ㄦ埛", + path: "/userManage", + icon: "Document", + }, + { key: 1, label: "瑙掕壊鏉冮檺绠$悊", path: "/roleManage", icon: "Document" }, +]); + +const systemTreeData = ref<TreeNode[]>([ + { + label: "501", + path: "", + icon: "Document", + children: [ + { + label: "涓�瀹�", + path: "", + icon: "", + }, + { + label: "浜屽", + path: "", + icon: "", + }, + { + label: "涓夊", + path: "", + icon: "", + }, + ], + }, +]); +const systemTreeData1 = ref<TreeNode[]>([ + { + label: "绯荤粺绠$悊鍛�", + path: "", + icon: "", + }, + { + label: "妯″瀷绠$悊鍛�", + path: "", + icon: "", + }, + { + label: "娴嬭瘯浜哄憳", + path: "", + icon: "", + }, + { + label: "鎶ュ憡鏌ョ湅浜哄憳", + path: "", + icon: "", + }, +]); + +const dialogFormVisible = ref(false); +const dialogTitle = ref(); +const formRef = ref<FormInstance>(); +const form = reactive({ + name: "", + refCode: "", + description: "", +}); + +interface formInfo { + name: string; +} +const formRules = reactive<FormRules<formInfo>>({ + name: [{ required: true, message: "鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }], +}); + +watch( + () => route, + (newRoute) => { + console.log("璺敱鍙樺寲:", newRoute.path); + // 澶勭悊璺敱鍙樺寲閫昏緫 + }, + { deep: true } +); + +watch( + () => seleStore.curTab, // 鐩戝惉 reactive 瀵硅薄锛堥粯璁ゆ繁搴︾洃鍚級 + (newVal) => { + if (newVal) { + if (seleStore.curTab == "model") { + menuName.value = "妯″瀷搴�"; + } else if (seleStore.curTab == "simulation") { + menuName.value = "鍙鍖栦豢鐪�"; + filteredData.value = visualSimulationTreeData.value; + } else if (seleStore.curTab == "systemManage") { + menuName.value = "绯荤粺绠$悊"; + filteredData.value = systemManageTreeData.value; + } else { + filteredData.value = []; + } + systemMenuName.value = systemManageTreeData.value[0].label; + } + } +); + +onMounted(() => { + console.log(route, "route.route"); +}); + +watch( + () => props.storeInfo, // 鐩戝惉 reactive 瀵硅薄锛堥粯璁ゆ繁搴︾洃鍚級 + (newVal) => { + if (newVal) { + loadTree.value = true; + } + } +); + +const loadNode = async (node, resolve) => { + if (node.level == 0) { + const treeData = await getTableData(0); + const list = treeData.filter((item) => item.data.refCode !== "testReport"); + const testReport = treeData.find( + (item) => item.data.refCode === "testReport" + ); + console.log(list, "list"); + console.log(testReport, "testReport"); + nextTick(() => { + currentNodeKey.value = 0; // 纭繚鑺傜偣宸叉覆鏌� + seleStore.setChannelInfo(list[0]); + seleStore.setTestReportChannel(testReport); + selectData.value = list[0]; + }); + return resolve(list); + } + if (node.childNodes.length > 0) { + return resolve([]); + } + // 鏄剧ず鍔犺浇鐘舵�� + node.loading = true; + const childNodes = await getTableData(node.data.data); + resolve(childNodes); +}; + +//澶勭悊鏍戝舰缁撴瀯 +const handleTreeData = (datas: any[], parent, noTriggerSelect = false) => { + let parentData = {}; + if (parent) { + parentData = { ...parent, parent: null }; + } else { + parentData = null; + } + const list = []; + for (let i = 0; i < datas.length; i++) { + const data = datas[i]; + const obj = { + label: data.name, + key: parentData ? parentData.key + "_" + i : i + "", + namePath: parentData ? parentData.namePath + "\\" + data.name : data.name, + icon: data.icon, + data: data, + parent: parentData, + leaf: false, + children: [], + }; + if (data["children"] && data["children"].length) { + obj.leaf = false; + obj.children = handleTreeData( + data["children"], + { + ...data, + key: obj.key, + namePath: obj.namePath, + }, + i == 0 ? false : true // 濡傛灉鏈夊瓙鏁版嵁澶勭悊锛屽彧鏈夌涓�鏉℃暟鎹渶瑕佸睍寮�鍜屽洖璋� + ); + } else { + obj.leaf = + !data["childrenChannelCount"] || data["childrenChannelCount"] == 0; + } + list.push(obj); + } + console.log(list, "list"); + return list; +}; + +const getTableData = async (path) => { + const treeData = await toolClass.getCmsItem({ + path: path.idPath + ? path.idPath + : props.storeInfo.repositoryData.rootChannel.id, + storeId: props.storeInfo.storeId, + repositoryId: props.storeInfo.repositoryId, + type: "\\", + sort: { + LinkOrder: "Asc", + }, + paging: { + Start: 0, + Size: 50, + }, + filters: { + "SysType=": ["CmsChannel"], + }, + fields: { + ChildrenCount: [], + }, + }); + if (treeData && treeData.datas.length > 0) { + const fomartData = handleTreeData( + treeData.datas, + path ? path : null, + false + ); + seleStore.setChannelInfo(fomartData[0]); + seleStore.setChannelList(fomartData); + return fomartData; + } else { + return []; + } +}; const filterNode = (value: string, data: TreeNode) => { - if (!value) return true - return data.label.toLowerCase().includes(value.toLowerCase()) -} + if (!value) return true; + return data.label.toLowerCase().includes(value.toLowerCase()); +}; -const handleSearch = (searchText: string) => { - treeRef.value?.filter(searchText) -} +const filterNode1 = (value: string, data: TreeNode) => { + if (!value) return true; + return data.label.toLowerCase().includes(value.toLowerCase()); +}; const handleNodeClick = (data: TreeNode) => { - if (data.path) { - router.push(data.path) + seleStore.setChannelInfo(data); + selectData.value = data; +}; + +//娣诲姞鐩綍 +const addBtn = (type) => { + if (type == "child") { + dialogTitle.value = "鏂板缓瀛愰閬�"; + createParent.value = false; + } else { + dialogTitle.value = "鏂板缓棰戦亾"; + createParent.value = true; } -} + + dialogFormVisible.value = true; +}; +const submitBtn = async (formEl: FormInstance | undefined) => { + if (!formEl) return; + await formEl.validate(async (valid, fields) => { + if (valid) { + console.log(form.name, "fields"); + + if (dialogTitle.value == "缂栬緫") { + const body = { + accessPath: selectData.value.data.idPath, + accessStoreId: selectData.value.data.storeId, + accessRepositoryId: selectData.value.data.repositoryId, + accessItemId: selectData.value.data.id, + name: form.name, // form.name, + description: form.description, + refCode: form.refCode, + state: selectData.value.data.state, + icon: selectData.value.data.icon, + type: selectData.value.data.type, + }; + const updateCmsItem = await MG.dps5.UpdateCmsItem({ + updateList: [body], + }); + if (updateCmsItem) { + ElMessage({ + message: "缂栬緫鎴愬姛", + type: "success", + }); + dialogFormVisible.value = false; + form.name = ""; + form.refCode = ""; + form.description = ""; + treeKey.value += 1; + } + } else { + const body = { + accessPath: createParent.value + ? props.storeInfo.repositoryData.rootChannel.id + : selectData.value.data.idPath, + accessStoreId: props.storeInfo.storeId, + accessRepositoryId: props.storeInfo.repositoryId, + sysType: "CmsChannel", + linkType: "Link", + cmsItemRequest: { + ...form, + state: "Normal", + type: "Normal", + module: "", + accessType: "Public", + }, + }; + const newCmsItem = await MG.dps5.NewCmsItem(body); + if (newCmsItem) { + ElMessage({ + message: "娣诲姞鎴愬姛", + type: "success", + }); + dialogFormVisible.value = false; + form.name = ""; + form.refCode = ""; + form.description = ""; + treeKey.value += 1; + } else { + ElMessage({ + message: "娣诲姞澶辫触", + type: "error", + }); + } + } + } + }); +}; +const closeDialog = (formEl: FormInstance | undefined) => { + if (!formEl) return; + formEl.resetFields(); + dialogFormVisible.value = false; +}; + +const editBtn = () => { + dialogTitle.value = "缂栬緫"; + form.name = selectData.value.label; + form.refCode = selectData.value.data.refCode; + form.description = selectData.value.data.description; + dialogFormVisible.value = true; +}; + +const delBtn = () => { + if (selectData.value.data.childrenCmsItemCount > 0) { + ElMessage({ + message: "棰戦亾涓嬭繕鏈夊叾浠栬祫婧愶紝璇峰厛鍒犻櫎璧勬簮鍚庨噸璇曪紒", + type: "warning", + }); + return false; + } + if (selectData.value.data.childrenChannelCount > 0) { + ElMessage({ + message: "棰戦亾涓嬭繕鏈夊瓙棰戦亾锛岃鍏堝垹闄ゅ瓙棰戦亾鍚庨噸璇曪紒", + type: "warning", + }); + return false; + } + ElMessageBox.confirm("纭畾瑕佸垹闄ら�変腑鐨勬暟鎹�?", "鍒犻櫎棰戦亾", { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + console.log(selectData.value, "selectData.value"); + let accessPath = ""; + let accessItemId = 0; + if (!selectData.value.parent) { + accessPath = props.storeInfo.repositoryData.rootChannel.id + ""; + accessItemId = props.storeInfo.repositoryData.rootChannel.id; + } else { + accessPath = selectData.value.parent.data.idPath; + accessItemId = selectData.value.parent.data.id; + } + MG.dps5 + .DelCmsItemByList({ + accessPath, + accessStoreId: selectData.value.data.storeId, + accessRepositoryId: selectData.value.data.repositoryId, + accessItemId, + itemIds: [selectData.value.data.id], + }) + .then((res) => { + ElMessage({ + message: "鍒犻櫎鎴愬姛", + type: "success", + }); + treeKey.value += 1; + }); + }) + .catch(() => {}); +}; + +const systemClick = (data: TreeNode) => { + curSelectNode.value = data; + router.push({ + path: "/systemManage" + data.path, + }); + console.log(curSelectNode.value, "curSelectNode"); +}; </script> <style lang="less" scoped> -.tree-menu { +.tree-menu-box { height: 100%; background-color: #fff; - + .flex { + height: 100%; + } +} +.tree-menu { + width: 260px; + height: 100%; + border-right: 1px solid #e9eef3; :deep(.el-tree) { padding: 10px; } - + .custom-tree-node { display: flex; align-items: center; gap: 8px; } + + .topMenu { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + border-bottom: 1px solid #ebeef5; + .topMenu-title { + font-size: 16px; + font-weight: bold; + } + .btnGroup { + display: flex; + gap: 12px; + cursor: pointer; + + .icon1, + .icon2, + .icon3 { + font-size: 18px; + color: #606266; + &:hover { + color: #409eff; + } + } + } + } } -</style> \ No newline at end of file +</style> -- Gitblit v1.9.1