| | |
| | | :data="list" |
| | | @node-click="handleNodeClick" |
| | | :expand-on-click-node="false" |
| | | @node-expand="handleNodeExpand" |
| | | @node-collapse="handleNodeCollapse" |
| | | :key="treeKey" |
| | | :default-expanded-keys="expandedKeys" |
| | | :filter-node-method="filterNode" |
| | | :props="{ children: 'children', label: 'label' }" |
| | |
| | | > |
| | | 编辑 |
| | | </el-button> |
| | | <el-button type="primary" link @click="openProDia('add', data)" :disabled="node.level >= 3"> |
| | | <el-button type="primary" link @click="openProDia('add', data)"> |
| | | 添加产品 |
| | | </el-button> |
| | | <el-button |
| | |
| | | <el-input |
| | | v-model="form.productName" |
| | | placeholder="请输入产品名称" |
| | | maxlength="20" |
| | | show-word-limit |
| | | clearable |
| | | @keydown.enter.prevent |
| | | /> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from "vue"; |
| | | import { nextTick, ref } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | | addOrEditProduct, |
| | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tree = ref(null); |
| | | const containerRef = ref(null); |
| | | const treeKey = ref(0); |
| | | const expandedKeySet = new Set(); |
| | | const EXPANDED_STORAGE_KEY = "basicData_product_tree_expanded_keys_v2"; |
| | | |
| | | const loadExpandedKeys = () => { |
| | | if (typeof window === "undefined") { |
| | | return []; |
| | | } |
| | | try { |
| | | const saved = localStorage.getItem(EXPANDED_STORAGE_KEY); |
| | | return saved ? JSON.parse(saved) : []; |
| | | } catch (error) { |
| | | console.error(error); |
| | | return []; |
| | | } |
| | | }; |
| | | |
| | | const saveExpandedKeys = () => { |
| | | if (typeof window === "undefined") { |
| | | return; |
| | | } |
| | | localStorage.setItem( |
| | | EXPANDED_STORAGE_KEY, |
| | | JSON.stringify(Array.from(expandedKeySet)) |
| | | ); |
| | | }; |
| | | |
| | | loadExpandedKeys().forEach((key) => expandedKeySet.add(key)); |
| | | |
| | | const syncExpandedKeysFromTree = () => { |
| | | const keys = []; |
| | | const walk = (nodes) => { |
| | | (nodes || []).forEach((item) => { |
| | | if (item.expanded && item.data?.id !== undefined) { |
| | | keys.push(item.data.id); |
| | | } |
| | | if (item.childNodes && item.childNodes.length) { |
| | | walk(item.childNodes); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | walk(tree.value?.root?.childNodes); |
| | | expandedKeySet.clear(); |
| | | keys.forEach((key) => expandedKeySet.add(key)); |
| | | expandedKeys.value = keys; |
| | | saveExpandedKeys(); |
| | | }; |
| | | |
| | | const normalizeExpandedKeys = (treeData) => { |
| | | const parentMap = new Map(); |
| | | const walk = (nodes, parentId = null) => { |
| | | (nodes || []).forEach((item) => { |
| | | parentMap.set(item.id, parentId); |
| | | if (item.children && item.children.length) { |
| | | walk(item.children, item.id); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | walk(treeData); |
| | | |
| | | const normalizedKeys = Array.from(expandedKeySet).filter((key) => { |
| | | if (!parentMap.has(key)) { |
| | | return false; |
| | | } |
| | | let currentId = key; |
| | | while (parentMap.has(currentId)) { |
| | | const parentId = parentMap.get(currentId); |
| | | if (!parentId) { |
| | | return true; |
| | | } |
| | | if (!expandedKeySet.has(parentId)) { |
| | | return false; |
| | | } |
| | | currentId = parentId; |
| | | } |
| | | return true; |
| | | }); |
| | | |
| | | if (normalizedKeys.length !== expandedKeySet.size) { |
| | | expandedKeySet.clear(); |
| | | normalizedKeys.forEach((key) => expandedKeySet.add(key)); |
| | | saveExpandedKeys(); |
| | | } |
| | | }; |
| | | |
| | | const productDia = ref(false); |
| | | const modelDia = ref(false); |
| | |
| | | treeLoad.value = true; |
| | | productTreeList() |
| | | .then((res) => { |
| | | list.value = res; |
| | | list.value.forEach((a) => { |
| | | expandedKeys.value.push(a.label); |
| | | list.value = res || []; |
| | | normalizeExpandedKeys(list.value); |
| | | expandedKeys.value = Array.from(expandedKeySet); |
| | | treeKey.value += 1; |
| | | nextTick(() => { |
| | | tree.value?.setDefaultExpandedKeys?.(expandedKeys.value); |
| | | }); |
| | | treeLoad.value = false; |
| | | }) |
| | | .catch((err) => { |
| | | console.error(err); |
| | | }) |
| | | .finally(() => { |
| | | treeLoad.value = false; |
| | | }); |
| | | }; |
| | | const handleNodeExpand = (data) => { |
| | | nextTick(syncExpandedKeysFromTree); |
| | | }; |
| | | const handleNodeCollapse = (data, node) => { |
| | | node?.eachNode?.((item) => { |
| | | item.collapse(); |
| | | }); |
| | | nextTick(syncExpandedKeysFromTree); |
| | | }; |
| | | // 过滤产品树 |
| | | const searchFilter = () => { |
| | | proxy.$refs.tree.filter(search.value); |