From 5da536668e047dbaefbb79731ab2cacfdf70dc56 Mon Sep 17 00:00:00 2001 From: zhang_12370 <z2864490065@outlook.com> Date: 星期二, 22 七月 2025 17:36:38 +0800 Subject: [PATCH] 1、提交配煤计算器 解除煤种限制 2、增加销售出库的导出功能 3、库存管理正式库的导出功能 4、文档管理优化 5、优化设备管理模块 --- src/views/archiveManagement/index.vue | 1024 ++++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 654 insertions(+), 370 deletions(-) diff --git a/src/views/archiveManagement/index.vue b/src/views/archiveManagement/index.vue index 7bcbed9..8db8de6 100644 --- a/src/views/archiveManagement/index.vue +++ b/src/views/archiveManagement/index.vue @@ -5,23 +5,22 @@ <div class="tree-header"> <h3>鏂囨。绠$悊</h3> <el-button icon="Plus" size="small" type="primary" @click="append('')" - >鏂板 - </el-button - > + >鏂板 + </el-button> </div> <!-- 鎼滅储妗� --> <div class="search-box"> <el-input - v-model="filterText" - clearable - placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�" - size="small" - @input="handleFilter" + v-model="filterText" + clearable + placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�" + size="small" + @input="handleFilter" > <template #prefix> <el-icon> - <Search/> + <Search /> </el-icon> </template> </el-input> @@ -29,62 +28,73 @@ <div class="tree-container"> <el-tree - ref="treeRef" - :data="treeData" - :default-expand-all="false" - :expand-on-click-node="false" - :filter-node-method="filterNode" - :props="props" - class="custom-tree" - node-key="id" - @node-click="handleNodeClick" + ref="treeRef" + :data="treeData" + :default-expand-all="false" + :expand-on-click-node="false" + :filter-node-method="filterNode" + :props="props" + :lazy="false" + :load="undefined" + :render-after-expand="true" + :auto-expand-parent="true" + :indent="20" + class="custom-tree" + node-key="id" + @node-click="handleNodeClick" + @node-expand="handleNodeExpand" > <template #default="{ node, data }"> - <div class="tree-node-content" @dblclick="headerDbClick(node,data)"> + <div + class="tree-node-content" + :data-temp-id="data._tempId" + :data-node-id="data.id" + @dblclick="headerDbClick(node, data)" + > <div class="node-icon"> <el-icon - v-if="!node.isLeaf" - :class="{ expanded: node.expanded }" + v-if="!node.isLeaf" + :class="{ expanded: node.expanded }" > - <Folder/> + <Folder /> </el-icon> <el-icon v-else> - <Document/> + <Document /> </el-icon> </div> <div class="node-label"> <span v-if="!data.isEdit" class="label-text">{{ - node.label - }}</span> + node.label + }}</span> <el-input - v-else - :ref="(el) => setInputRef(el, data)" - v-model="newName" - autofocus - class="tree-input" - placeholder="璇疯緭鍏ヨ妭鐐瑰悕绉�" - size="small" - @blur="(event) => handleInputBlur(event, data, node)" - @keyup.enter=" - (event) => handleInputBlur(event, data, node) - " + v-else + :ref="(el) => setInputRef(data.id || data._tempId, el)" + v-model="newName" + autofocus + class="tree-input" + placeholder="璇疯緭鍏ヨ妭鐐瑰悕绉�" + size="small" + @blur="(event) => handleInputBlur(event, data, node)" + @keyup.enter="(event) => handleInputBlur(event, data, node)" + @keyup.esc="() => cancelEdit(data, node)" /> </div> <div v-show="!data.isEdit" class="node-actions"> <el-button - icon="Plus" - link - size="small" - title="鏂板瀛愯妭鐐�" - @click.stop="append(data)" + icon="Plus" + link + size="small" + :title="getNodeDepth(data) >= 7 ? '宸茶揪鍒版渶澶у祵濂楀眰绾э紙7灞傦級' : '鏂板瀛愯妭鐐�'" + :disabled="getNodeDepth(data) >= 7" + @click.stop="append(data)" ></el-button> <el-button - icon="Delete" - link - size="small" - title="鍒犻櫎" - @click.stop="remove(node, data)" + icon="Delete" + link + size="small" + title="鍒犻櫎" + @click.stop="remove(node, data)" ></el-button> </div> </div> @@ -95,168 +105,236 @@ </div> <div class="right"> <el-row :gutter="24"> - <el-col :offset="20" :span="2" - > - <el-button :icon="Delete" type="danger" @click="delHandler">鍒犻櫎</el-button> - </el-col - > - <el-col :span="2" - > - <el-button - :disabled="!tableSwitch" - :icon="Plus" - type="primary" - @click="add" - >鏂板 - </el-button + <el-col :span="10"> + <div> + <el-input + style="float: left; width: 50%" + v-model="searchText" + placeholder="璇疯緭鍏ュ叧閿瓧鏌ヨ鏂囦欢" + clearable + @input="handleSearch" + @clear="handleSearch" + > + <template #prefix> + <el-icon> + <Search /> + </el-icon> + </template> + <template #suffix> + <el-button @click="handleSearch" link style="border: none"> + <span>鎼滅储</span> + </el-button> + </template> + </el-input> + </div> + </el-col> + <el-col :offset="8" :span="3"> + <el-button :icon="Delete" type="danger" @click="delHandler" + >鍒犻櫎</el-button > - </el-col - > + </el-col> + <el-col :span="3"> + <el-button + :disabled="!tableSwitch" + :icon="Plus" + type="primary" + @click="add" + >鏂板 + </el-button> + </el-col> </el-row> <ETable - :border="true" - :columns="columns" - :loading="loading" - :maxHeight="1200" - :show-selection="true" - :table-data="tableData" - @edit="handleEdit" - @selection-change="handleSelectionChange" + :border="true" + :columns="columns" + :loading="loading" + :maxHeight="1200" + :show-selection="true" + :table-data="tableData" + @edit="handleEdit" + @selection-change="handleSelectionChange" + style="height: calc(65vh);" > </ETable> <Pagination - :layout="'total, prev, pager, next, jumper'" - :limit="queryParams.pageSize" - :page="queryParams.current" - :show-total="true" - :total="total" - @pagination="handlePageChange" + :layout="'total, prev, pager, next, jumper'" + :limit="queryParams.pageSize" + :page="queryParams.current" + :show-total="true" + :total="total" + @pagination="handlePageChange" ></Pagination> </div> <archiveDialog - ref="archiveDialogs" - v-model:centerDialogVisible="dialogVisible" - :row="row" - @centerDialogVisible="centerDialogVisible" - @submitForm="submitForm" - + ref="archiveDialogs" + v-model:centerDialogVisible="dialogVisible" + :row="row" + @centerDialogVisible="centerDialogVisible" + @submitForm="submitForm" > </archiveDialog> </el-card> </template> <script setup> -import {nextTick, onMounted, reactive, ref} from "vue"; +import { computed, nextTick, onMounted, reactive, ref } from "vue"; import ETable from "@/components/Table/ETable.vue"; -import {ElButton, ElIcon, ElInput, ElMessage, ElMessageBox} from "element-plus"; +import { + ElButton, + ElIcon, + ElInput, + ElMessage, + ElMessageBox, +} from "element-plus"; import archiveDialog from "./mould/archiveDialog.vue"; import Pagination from "@/components/Pagination/index.vue"; -import {Delete, Document, Folder, Plus, Search,} from "@element-plus/icons-vue"; -import {addOrEditTree, delArchive, delTree, getArchiveList, getTree,} from "@/api/archiveManagement"; +import { + Delete, + Document, + Folder, + Plus, + Search, +} from "@element-plus/icons-vue"; +import { + addOrEditTree, + delArchive, + delTree, + getArchiveList, + getTree, +} from "@/api/archiveManagement"; -const dialogVisible = ref(false); // 鎺у埗褰掓。瀵硅瘽妗嗘樉绀� +// ===== 鍝嶅簲寮忕姸鎬佺鐞� ===== +const searchText = ref(""); +const dialogVisible = ref(false); const loading = ref(false); const tableData = ref([]); const treeData = ref([]); const newName = ref(""); -const inputRefs = ref(new Map()); // 瀛樺偍杈撳叆妗嗗紩鐢� -const filterText = ref(""); // 鎼滅储鍏抽敭瀛� -const treeRef = ref(); // 鏍戠粍浠跺紩鐢� -const total = ref(0); // 鎬昏褰曟暟 +const inputRefs = ref(new Map()); +const filterText = ref(""); +const treeRef = ref(); +const total = ref(0); +const row = ref({}); +const selectedRows = reactive([]); +const rowClickData = ref({}); +const tableSwitch = ref(false); +const archiveDialogs = ref(null); + +// ===== 閰嶇疆甯搁噺 ===== const columns = [ - {prop: "name", label: "鍚嶇О", minWidth: 180}, - {prop: "type", label: "绫诲瀷", minWidth: 120}, - {prop: "status", label: "鐘舵��", minWidth: 100}, + { prop: "name", label: "鍚嶇О", minWidth: 180 }, + { prop: "type", label: "绫诲瀷", minWidth: 120 }, + { prop: "status", label: "鐘舵��", minWidth: 100 }, ]; -const selectedRows = reactive([]); // 瀛樺偍閫変腑琛屾暟鎹� -const handleSelectionChange = (selection) => { - selectedRows.splice(0, selectedRows.length, ...selection); -}; + const queryParams = reactive({ searchAll: "", current: 1, - pageSize: 10, // 鍥哄畾姣忛〉10鏉� - treeId: null, // 褰撳墠鏍戣妭鐐笽D + pageSize: 10, + treeId: null, }); -// 鎼滅储杩囨护鍔熻兘 + +const props = { + label: "name", + children: "children", + isLeaf: "leaf", +}; + +// ===== 璁$畻灞炴�� ===== +// 璁$畻鎬昏妭鐐规暟 +const totalNodeCount = computed(() => { + const countNodes = (nodes) => { + let count = 0; + for (const node of nodes || []) { + count += 1; + if (node.children) { + count += countNodes(node.children); + } + } + return count; + }; + return countNodes(treeData.value); +}); + +// 妫�鏌ユ槸鍚︿负澶ч噺鑺傜偣锛堣秴杩�1000涓妭鐐规椂鎻愮ず鎬ц兘浼樺寲锛� +const isLargeTree = computed(() => totalNodeCount.value > 1000); + +// 鑾峰彇鑺傜偣娣卞害鐨勫嚱鏁� +const getNodeDepth = (nodeData) => { + if (!nodeData || !nodeData.id) return 0; + + let depth = 1; + const node = treeRef.value?.getNode(nodeData.id); + let parentNode = node?.parent; + + while (parentNode && parentNode.data && parentNode.data.id) { + depth++; + parentNode = parentNode.parent; + } + + return depth; +}; + +// ===== 宸ュ叿鍑芥暟 ===== +const handleError = (error, defaultMsg = "鎿嶄綔澶辫触锛岃绋嶅悗閲嶈瘯") => { + console.error(error); + ElMessage.error(defaultMsg); +}; + +const showSuccess = (msg = "鎿嶄綔鎴愬姛") => { + ElMessage.success(msg); +}; + +// 鎼滅储鏌ヨ鍑芥暟 +const handleSearch = () => { + queryParams.searchAll = searchText.value; + queryParams.current = 1; // 閲嶇疆鍒扮涓�椤� + getArchiveListData(); +}; + +const showConfirm = (message, title = "纭鎿嶄綔") => { + return ElMessageBox.confirm(message, title, { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning", + }); +}; + +// ===== 鍩虹鍔熻兘鍑芥暟 ===== +const handleSelectionChange = (selection) => { + selectedRows.splice(0, selectedRows.length, ...selection); +}; + const handleFilter = () => { treeRef.value?.filter(filterText.value); }; -const row = ref({}); // 褰撳墠閫変腑琛屾暟鎹� + const filterNode = (value, data) => { if (!value) return true; return data.name?.toLowerCase().includes(value.toLowerCase()); -}; -const submitForm = async (res) => { - try { - if (res && res.code === 200) { - ElMessage.success("鎿嶄綔鎴愬姛"); - dialogVisible.value = false; - // 鍒锋柊鍒楄〃鏁版嵁 - await getArchiveListData(); - } else { - ElMessage.error("鎿嶄綔澶辫触: " + (res?.message || res?.msg || "鏈煡閿欒")); - } - } catch (error) { - console.error("鎻愪氦琛ㄥ崟閿欒:", error); - ElMessage.error("鎿嶄綔澶辫触锛岃绋嶅悗閲嶈瘯"); - } }; const centerDialogVisible = (val) => { dialogVisible.value = val; }; -const tableSwitch = ref(false); -// 澶勭悊鑺傜偣鐐瑰嚮 -const handleNodeClick = (data) => { - rowClickData.value = data; // 瀛樺偍褰撳墠鐐瑰嚮鐨勮妭鐐规暟鎹� - tableSwitch.value = true; - // 鍒囨崲鑺傜偣鏃堕噸缃埌绗竴椤� - queryParams.current = 1; - queryParams.treeId = data.id; - getArchiveListData(); -}; -const rowClickData = ref({}); // 瀛樺偍褰撳墠鐐瑰嚮鐨勮妭鐐规暟鎹� -const archiveDialogs = ref(null); // 琛ㄦ牸缁勪欢寮曠敤 -// 鏂板褰掓。 -const add = () => { +// ===== 鏁版嵁鑾峰彇鍑芥暟 ===== +const getList = async () => { try { - row.value = {}; // 娓呯┖琛屾暟鎹紝纭繚鏄柊澧炴ā寮� - newName.value = ""; // 娓呯┖杈撳叆妗� - dialogVisible.value = true; - - // 纭繚缁勪欢寮曠敤瀛樺湪鍚庡啀璋冪敤鏂规硶 - nextTick(() => { - if (archiveDialogs.value && typeof archiveDialogs.value.initForm === 'function') { - archiveDialogs.value.initForm(rowClickData.value); // 閲嶇疆琛ㄥ崟 - } - }); + const res = await getTree(); + treeData.value = + res.code === 200 ? res.data?.records || res.data || [] : []; } catch (error) { - console.error("鏂板褰掓。閿欒:", error); - ElMessage.error("鎵撳紑鏂板鐣岄潰澶辫触"); - } -}; -// 澶勭悊鍒嗛〉鍙樺寲 -const handlePageChange = (pagination) => { - try { - const { page, limit } = pagination; - queryParams.current = page; - if (limit) { - queryParams.pageSize = limit; - } - getArchiveListData(); - } catch (error) { - console.error("鍒嗛〉澶勭悊閿欒:", error); - ElMessage.error("鍒嗛〉鎿嶄綔澶辫触"); + handleError(error, "鑾峰彇鏍戠粨鏋勬暟鎹け璐�"); + treeData.value = []; } }; const getArchiveListData = async () => { try { loading.value = true; - let res = await getArchiveList({ + const res = await getArchiveList({ treeId: queryParams.treeId, current: queryParams.current, size: queryParams.pageSize, + searchAll: queryParams.searchAll, }); if (res.code !== 200) { @@ -265,23 +343,94 @@ total.value = 0; return; } + tableData.value = res.data?.records || res.data || []; total.value = res.data?.total || 0; - // 纭繚鍒嗛〉鍙傛暟姝g‘鏇存柊 + if (res.data?.current) { queryParams.current = res.data.current; } - // pageSize 鍥哄畾涓�20锛屼笉浠庡悗绔幏鍙� - } catch (error) { - ElMessage.error("鑾峰彇鏁版嵁澶辫触"); + handleError(error, "鑾峰彇褰掓。鏁版嵁澶辫触"); tableData.value = []; total.value = 0; } finally { loading.value = false; } }; -// 鍒犻櫎閫変腑鐨勫綊妗h褰� + +// ===== 琛ㄥ崟鎻愪氦澶勭悊 ===== +const submitForm = async (res) => { + try { + if (res?.code === 200) { + showSuccess(); + dialogVisible.value = false; + await getArchiveListData(); + } else { + ElMessage.error("鎿嶄綔澶辫触: " + (res?.message || res?.msg || "鏈煡閿欒")); + } + } catch (error) { + handleError(error, "鎻愪氦琛ㄥ崟澶辫触"); + } +}; +// ===== 鑺傜偣鎿嶄綔鍑芥暟 ===== +const handleNodeClick = (data) => { + rowClickData.value = data; + tableSwitch.value = true; + queryParams.current = 1; + queryParams.treeId = data.id; + getArchiveListData(); +}; + +// 鑺傜偣灞曞紑浜嬩欢澶勭悊 +const handleNodeExpand = (data, node, instance) => { + // 灞曞紑鍚庣◢寰欢杩燂紝纭繚瀛愯妭鐐规覆鏌撳畬鎴� + setTimeout(() => { + // 濡傛灉鏈夋柊娣诲姞鐨勭紪杈戠姸鎬佽妭鐐癸紝鑱氱劍鍒板畠 + if (data.children && data.children.length > 0) { + const editingChild = data.children.find(child => child.isEdit && child._tempId); + if (editingChild) { + focusInput(editingChild._tempId, 200); + } + } + }, 100); +}; + +const handlePageChange = (pagination) => { + try { + const { page, limit } = pagination; + queryParams.current = page; + if (limit) queryParams.pageSize = limit; + getArchiveListData(); + } catch (error) { + handleError(error, "鍒嗛〉鎿嶄綔澶辫触"); + } +}; + +// ===== 寮圭獥鎿嶄綔鍑芥暟 ===== +const openDialog = (isEdit = false, rowData = {}) => { + try { + row.value = isEdit ? { ...rowData } : {}; + newName.value = ""; + dialogVisible.value = true; + + nextTick(() => { + if (archiveDialogs.value) { + const method = isEdit ? "editForm" : "initForm"; + if (typeof archiveDialogs.value[method] === "function") { + archiveDialogs.value[method](isEdit ? rowData : rowClickData.value); + } + } + }); + } catch (error) { + handleError(error, `鎵撳紑${isEdit ? "缂栬緫" : "鏂板"}鐣岄潰澶辫触`); + } +}; + +const add = () => openDialog(false); +const handleEdit = (rows) => openDialog(true, rows); + +// ===== 鍒犻櫎鎿嶄綔鍑芥暟 ===== const delHandler = async () => { if (selectedRows.length === 0) { ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁"); @@ -289,280 +438,393 @@ } try { - await ElMessageBox.confirm( + await showConfirm( `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.length} 鏉¤褰曞悧锛焋, - '鍒犻櫎纭', - { - confirmButtonText: '纭畾', - cancelButtonText: '鍙栨秷', - type: 'warning', - } + "鍒犻櫎纭" ); const ids = selectedRows.map((row) => row.id); const { code, msg } = await delArchive(ids); - + if (code !== 200) { ElMessage.error("鍒犻櫎澶辫触: " + msg); return; } - ElMessage.success("鍒犻櫎鎴愬姛"); - // 鍒犻櫎鎴愬姛鍚庨噸鏂拌幏鍙栨暟鎹� + showSuccess("鍒犻櫎鎴愬姛"); await getArchiveListData(); - // 娓呯┖閫変腑鐘舵�� selectedRows.splice(0, selectedRows.length); - } catch (error) { - if (error !== 'cancel') { - console.error("鍒犻櫎褰掓。澶辫触:", error); - ElMessage.error("鍒犻櫎鎿嶄綔澶辫触锛岃绋嶅悗閲嶈瘯"); + if (error !== "cancel") { + handleError(error, "鍒犻櫎鎿嶄綔澶辫触"); } } }; -// 鍙屽嚮缂栬緫鑺傜偣 + +const remove = async (node, data) => { + if (!data?.id) { + ElMessage.warning("鏃犳硶鍒犻櫎姝よ妭鐐�"); + return; + } + + try { + await showConfirm(`纭畾瑕佸垹闄よ妭鐐� "${data.name}" 鍚楋紵`, "鍒犻櫎纭"); + + const { code, msg } = await delTree([data.id]); + + if (code !== 200) { + ElMessage.error("鍒犻櫎澶辫触: " + msg); + return; + } + + showSuccess("鍒犻櫎鎴愬姛"); + await getList(); + } catch (error) { + if (error !== "cancel") { + handleError(error, "鍒犻櫎鑺傜偣澶辫触"); + } + } +}; +// ===== 鏍戣妭鐐圭紪杈戝嚱鏁� ===== +const setInputRef = (key, el) => { + if (el && key) { + inputRefs.value.set(key, el); + } +}; + const headerDbClick = (node, data) => { - data.isEdit = true; - newName.value = data.name; - nextTick(() => { - const inputEl = inputRefs.value.get(data.id || data); - if (inputEl) { - inputEl.focus(); - inputEl.select(); - } - }); -}; - -// 璁剧疆杈撳叆妗嗗紩鐢ㄧ殑鏂规硶 -const setInputRef = (el, data) => { - if (el) { - inputRefs.value.set(data.id || data, el); - if (data.isEdit) { - nextTick(() => { - // el.focus(); - // el.select(); - }); - } + try { + data.isEdit = true; + newName.value = data.name; + + nextTick(() => { + const key = data._tempId || data.id; + if (key) { + focusInput(key, 50); + } + }); + } catch (error) { + console.error('杩涘叆缂栬緫妯″紡澶辫触:', error); + ElMessage.error('杩涘叆缂栬緫妯″紡澶辫触'); } }; -// 澶勭悊杈撳叆妗嗗け鐒� +// 鍙栨秷缂栬緫鍔熻兘 +const cancelEdit = (data, node) => { + try { + data.isEdit = false; + + // 濡傛灉鏄柊鍒涘缓鐨勪复鏃惰妭鐐癸紝鍒犻櫎瀹� + if (data._tempId && !data.id) { + if (node.parent) { + const parent = node.parent.data; + const index = parent.children?.indexOf(data); + if (index > -1) { + parent.children.splice(index, 1); + } + } else { + // 鏍硅妭鐐� + const index = treeData.value.indexOf(data); + if (index > -1) { + treeData.value.splice(index, 1); + } + } + + // 娓呯悊杈撳叆妗嗗紩鐢� + const key = data._tempId; + if (inputRefs.value.has(key)) { + inputRefs.value.delete(key); + } + } + + // 閲嶇疆鍚嶇О + newName.value = ""; + } catch (error) { + console.error('鍙栨秷缂栬緫澶辫触:', error); + } +}; + +const expandParentNodes = (node) => { + if (node?.parent?.data) { + node.parent.expanded = true; + expandParentNodes(node.parent); + } +}; + const handleInputBlur = async (event, comeTreeData, node) => { try { - if (!comeTreeData.isEdit) return; // 濡傛灉涓嶆槸缂栬緫鐘舵�侊紝鐩存帴杩斿洖 - - if (event.relatedTarget && event.relatedTarget.tagName === "BUTTON") { + if (!comeTreeData.isEdit || event.relatedTarget?.tagName === "BUTTON") return; - } - + comeTreeData.isEdit = false; const newValue = newName.value.trim(); - - if (comeTreeData.name === newValue) { - return; - } - - if (newValue === "") { - newName.value = comeTreeData.name || "鏂拌妭鐐�"; + + // 濡傛灉鍚嶇О涓虹┖锛屽鐞嗙┖鍚嶇О鎯呭喌 + if (!newValue) { + // 濡傛灉鏄柊鍒涘缓鐨勪复鏃惰妭鐐癸紝鍒犻櫎瀹� + if (comeTreeData._tempId && !comeTreeData.id) { + cancelEdit(comeTreeData, node); + } else { + // 宸插瓨鍦ㄧ殑鑺傜偣锛屾仮澶嶅師鍚嶇О + newName.value = comeTreeData.name || "鏂拌妭鐐�"; + } ElMessage.warning("鑺傜偣鍚嶇О涓嶈兘涓虹┖"); return; } - - // 鑾峰彇鐖惰妭鐐圭殑id - 閫氳繃 node 鍙傛暟鏇村噯纭湴鑾峰彇 - let parentId = null; - if (node && node.parent && node.parent.data) { - parentId = node.parent.data.id; + + // 濡傛灉鍚嶇О娌℃湁鏀瑰彉锛岀洿鎺ヨ繑鍥� + if (comeTreeData.name === newValue) { + return; } - + + const parentId = node?.parent?.data?.id || null; + const result = await addOrEditTree({ name: newValue, - parentId: parentId || null, // 濡傛灉娌℃湁鐖惰妭鐐癸紝鍒欎负 null + parentId, id: comeTreeData.id || null, }); - if (result.code === 200) { + + if (result.code === 200) { comeTreeData.name = newValue; if (!comeTreeData.id && result.data) { comeTreeData.id = result.data.id || result.data; + // 娓呯悊涓存椂ID + if (comeTreeData._tempId) { + const tempKey = comeTreeData._tempId; + delete comeTreeData._tempId; + + // 鏇存柊寮曠敤鏄犲皠 + if (inputRefs.value.has(tempKey)) { + const inputEl = inputRefs.value.get(tempKey); + inputRefs.value.delete(tempKey); + if (comeTreeData.id && inputEl) { + inputRefs.value.set(comeTreeData.id, inputEl); + } + } + } } - ElMessage.success("淇濆瓨鎴愬姛"); - - // 鍒锋柊鏍戞暟鎹苟灞曞紑褰撳墠鑺傜偣 + showSuccess("淇濆瓨鎴愬姛"); + const currentNodeId = comeTreeData.id; await getList(); - - // 绛夊緟DOM鏇存柊鍚庡睍寮�鑺傜偣 + nextTick(() => { if (currentNodeId && treeRef.value) { const targetNode = treeRef.value.getNode(currentNodeId); if (targetNode) { // 灞曞紑褰撳墠鑺傜偣 targetNode.expanded = true; - // 濡傛灉鏈夌埗鑺傜偣锛屼篃灞曞紑鐖惰妭鐐硅矾寰� + + // 灞曞紑鎵�鏈夌埗鑺傜偣 expandParentNodes(targetNode); + + // 婊氬姩鍒拌妭鐐逛綅缃� + setTimeout(() => { + const nodeElement = document.querySelector(`[data-node-id="${currentNodeId}"]`); + if (nodeElement) { + nodeElement.scrollIntoView({ + behavior: 'smooth', + block: 'center' + }); + } + }, 300); } } }); } else { - comeTreeData.name = comeTreeData.name || "鏂拌妭鐐�"; + // 淇濆瓨澶辫触锛屾仮澶嶅師鍚嶇О鎴栧垹闄や复鏃惰妭鐐� + if (comeTreeData._tempId && !comeTreeData.id) { + cancelEdit(comeTreeData, node); + } else { + comeTreeData.name = comeTreeData.name || "鏂拌妭鐐�"; + } ElMessage.error("淇濆瓨澶辫触: " + (result.msg || "鏈煡閿欒")); } - } catch (error) { - console.error("淇濆瓨鑺傜偣澶辫触:", error); - comeTreeData.name = comeTreeData.name || "鏂拌妭鐐�"; - ElMessage.error("淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯"); + handleError(error, "淇濆瓨鑺傜偣澶辫触"); + // 鍑洪敊鏃跺鐞嗕复鏃惰妭鐐� + if (comeTreeData._tempId && !comeTreeData.id) { + cancelEdit(comeTreeData, node); + } else { + comeTreeData.name = comeTreeData.name || "鏂拌妭鐐�"; + } } }; -onMounted(async () => { - await getList(); +// ===== 鑺傜偣鏂板鍑芥暟 ===== +const createNewNode = (name, isEdit = true) => ({ + name, + isEdit, + _tempId: Date.now() + Math.random(), // 娣诲姞涓存椂ID }); -const props = { - label: "name", - children: "children", // 鏀逛负 children 浠ュ尮閰嶆爣鍑嗙粨鏋� - isLeaf: "leaf", -}; -// 灞曞紑鐖惰妭鐐硅矾寰� -const expandParentNodes = (node) => { - if (node && node.parent && node.parent.data) { - // 閫掑綊灞曞紑鎵�鏈夌埗鑺傜偣 - node.parent.expanded = true; - expandParentNodes(node.parent); - } -}; - -// 鍒犻櫎鏍戣妭鐐� -const remove = async (node, data) => { - if (!data || !data.id) { - ElMessage.warning("鏃犳硶鍒犻櫎姝よ妭鐐�"); - return; - } - - try { - await ElMessageBox.confirm( - `纭畾瑕佸垹闄よ妭鐐� "${data.name}" 鍚楋紵`, - '鍒犻櫎纭', - { - confirmButtonText: '纭畾', - cancelButtonText: '鍙栨秷', - type: 'warning', +const focusInput = (nodeKey, delay = 100) => { + setTimeout(() => { + const inputEl = inputRefs.value.get(nodeKey); + if (inputEl) { + try { + // 鍏堟粴鍔ㄥ埌鍙鍖哄煙 + inputEl.$el?.scrollIntoView?.({ + behavior: "smooth", + block: "center", + }); + + // 鑱氱劍骞堕�変腑鎵�鏈夋枃鏈紝纭繚鍙互鐩存帴缂栬緫 + setTimeout(() => { + inputEl.focus(); + inputEl.select(); + + // 纭繚鍏夋爣鍦ㄨ緭鍏ユ鏈熬锛堝鏋渟elect澶辫触鐨勮瘽锛� + const inputElement = inputEl.ref || inputEl.input || inputEl.$el?.querySelector('input'); + if (inputElement) { + inputElement.setSelectionRange(0, inputElement.value.length); + + // 纭繚杈撳叆妗嗗湪瑙嗗彛涓ぎ + setTimeout(() => { + inputElement.scrollIntoView({ + behavior: 'smooth', + block: 'center' + }); + }, 100); + } + }, 100); + } catch (error) { + console.warn('鑱氱劍杈撳叆妗嗗け璐�:', error); + // 澶囩敤鏂规锛氱洿鎺ヨ仛鐒� + try { + inputEl.focus(); + // 灏濊瘯閫変腑鏂囨湰 + setTimeout(() => { + const inputElement = inputEl.ref || inputEl.input || inputEl.$el?.querySelector('input'); + if (inputElement) { + inputElement.select(); + } + }, 200); + } catch (e) { + console.warn('澶囩敤鑱氱劍鏂规涔熷け璐�:', e); + } } - ); - - const { code, msg } = await delTree([data.id]); - - if (code !== 200) { - ElMessage.error("鍒犻櫎澶辫触: " + msg); - return; + } else { + console.warn('鏈壘鍒拌緭鍏ユ鍏冪礌锛宬ey:', nodeKey); } - - ElMessage.success("鍒犻櫎鎴愬姛"); - await getList(); - - } catch (error) { - if (error !== 'cancel') { - console.error("鍒犻櫎鑺傜偣澶辫触:", error); - ElMessage.error("鍒犻櫎澶辫触锛岃绋嶅悗閲嶈瘯"); - } - } + }, delay); }; const append = async (data) => { - if (data === "") { - // 鏂板鏍硅妭鐐� - const newNode = { - name: "鏂拌妭鐐�", - isEdit: true, - }; - treeData.value.push(newNode); - newName.value = "鏂拌妭鐐�"; - - nextTick(() => { - const inputEl = inputRefs.value.get(newNode.id || newNode); - if (inputEl) { - inputEl.focus(); - inputEl.select(); - } - }); - } else { - const hasChildren = data.children; - const nodeKey = data.id || data; - const node = treeRef.value?.getNode(nodeKey); - const isExpanded = node?.expanded; // 濡傛灉鏈夊瓙绾т笖鏈睍寮�锛屽厛灞曞紑鑺傜偣 - if (hasChildren && !isExpanded) { - if ( - treeRef.value && - treeRef.value.store && - treeRef.value.store.nodesMap[nodeKey] - ) { - treeRef.value.store.nodesMap[nodeKey].expanded = true; - } - } - const newNode = { - name: "鏂板瓙鑺傜偣", - isEdit: true, - }; - - if (!data.children) { - data.children = []; - } - data.children.push(newNode); - newName.value = "鏂板瓙鑺傜偣"; - - // 鏍规嵁鏄惁闇�瑕佸睍寮�鏉ュ喅瀹氬欢杩熸椂闂� - const delay = hasChildren && !isExpanded ? 200 : 50; - - // 绛夊緟DOM鏇存柊瀹屾垚鍚庡啀鑱氱劍 - nextTick(() => { - setTimeout(() => { - const inputEl = inputRefs.value.get(newNode.id || newNode); - if (inputEl) { - inputEl.focus(); - inputEl.select(); - - // 婊氬姩鍒版柊澧炵殑鑺傜偣浣嶇疆 - inputEl.$el?.scrollIntoView?.({ - behavior: "smooth", - block: "nearest", - }); + try { + // 妫�鏌ュ祵濂楀眰绾ч檺鍒� + const getNodeDepth = (nodeData, currentDepth = 1) => { + if (!nodeData || data === "") return 0; // 鏍硅妭鐐逛笉绠楀眰绾� + + let depth = currentDepth; + let current = nodeData; + + // 閫氳繃鏍戠粍浠惰幏鍙栫埗鑺傜偣鏉ヨ绠楁繁搴� + if (current.id) { + const node = treeRef.value?.getNode(current.id); + let parentNode = node?.parent; + + while (parentNode && parentNode.data && parentNode.data.id) { + depth++; + parentNode = parentNode.parent; } - }, delay); - }); - } -}; - -// 缂栬緫褰掓。 -const handleEdit = (rows) => { - try { - row.value = { ...rows }; // 浣跨敤娣辨嫹璐濋伩鍏嶅紩鐢ㄩ棶棰� - dialogVisible.value = true; - - // 纭繚缁勪欢寮曠敤瀛樺湪鍚庡啀璋冪敤鏂规硶 - nextTick(() => { - if (archiveDialogs.value && typeof archiveDialogs.value.editForm === 'function') { - archiveDialogs.value.editForm(rows); // 璋冪敤缂栬緫鏂规硶 } - }); - } catch (error) { - console.error("缂栬緫褰掓。閿欒:", error); - ElMessage.error("鎵撳紑缂栬緫鐣岄潰澶辫触"); - } -}; + + return depth; + }; -// 绉婚櫎鎳掑姞杞斤紝鐩存帴鑾峰彇鏁版嵁 -const getList = async () => { - try { - let res = await getTree(); - if (res.code === 200) { - treeData.value = res.data?.records || res.data || []; + const currentDepth = getNodeDepth(data); + + // 闄愬埗鏈�澶�7灞傚祵濂� + if (currentDepth >= 7) { + ElMessage.warning('鏈�澶氬彧鑳藉祵濂�7灞傝妭鐐癸紝褰撳墠宸茶揪鍒版渶澶у眰绾ч檺鍒�'); + return; + } + + // 鍦ㄥぇ閲忚妭鐐规椂鎻愮ず鎬ц兘娉ㄦ剰浜嬮」 + if (isLargeTree.value && totalNodeCount.value > 2000) { + const confirmed = await ElMessageBox.confirm( + `褰撳墠鏍戠粨鏋勫寘鍚� ${totalNodeCount.value} 涓妭鐐癸紝鑺傜偣杈冨鍙兘褰卞搷鎬ц兘銆傚缓璁�冭檻鍒嗗眰绠$悊銆傛槸鍚︾户缁坊鍔狅紵`, + '鎬ц兘鎻愮ず', + { + confirmButtonText: '缁х画娣诲姞', + cancelButtonText: '鍙栨秷', + type: 'warning', + } + ).catch(() => false); + + if (!confirmed) return; + } + + if (data === "") { + // 鏂板鏍硅妭鐐� + const newNode = createNewNode("鏂拌妭鐐�"); + treeData.value.push(newNode); + newName.value = "鏂拌妭鐐�"; + + await nextTick(); + focusInput(newNode._tempId, 200); } else { - treeData.value = []; + const hasChildren = data.children && data.children.length > 0; + const nodeKey = data.id || data; + const node = treeRef.value?.getNode(nodeKey); + + // 鍒涘缓鏂板瓙鑺傜偣 + const newNode = createNewNode("鏂板瓙鑺傜偣"); + + if (!data.children) { + data.children = []; + } + data.children.push(newNode); + newName.value = "鏂板瓙鑺傜偣"; + + // 寮哄埗鏇存柊鏍戠粨鏋� + await nextTick(); + + // 纭繚鐖惰妭鐐瑰睍寮�浠ユ樉绀烘柊鑺傜偣 + if (node) { + node.expanded = true; + + // 濡傛灉鏄涓�娆℃坊鍔犲瓙鑺傜偣锛岀瓑寰呭睍寮�鍔ㄧ敾骞剁‘淇濆彲瑙� + if (!hasChildren) { + await new Promise(resolve => setTimeout(resolve, 300)); + + // 灞曞紑鍚庢粴鍔ㄥ埌鏂拌妭鐐逛綅缃� + setTimeout(() => { + const newNodeElement = document.querySelector(`[data-temp-id="${newNode._tempId}"]`); + if (newNodeElement) { + newNodeElement.scrollIntoView({ + behavior: 'smooth', + block: 'center' + }); + } + }, 100); + } + + // 灞曞紑鎵�鏈夌埗鑺傜偣纭繚瀹屽叏鍙 + let parentNode = node.parent; + while (parentNode && parentNode.data && parentNode.data.id) { + parentNode.expanded = true; + parentNode = parentNode.parent; + } + } + + // 鑱氱劍鍒版柊鍒涘缓鐨勮緭鍏ユ + const delay = hasChildren ? 150 : 500; // 濡傛灉涔嬪墠娌℃湁瀛愯妭鐐癸紝寤惰繜鏇撮暱鏃堕棿绛夊睍寮� + focusInput(newNode._tempId, delay); } } catch (error) { - treeData.value = []; + console.error('鏂板鑺傜偣澶辫触:', error); + ElMessage.error('鏂板鑺傜偣澶辫触锛岃閲嶈瘯'); } }; + +// ===== 鐢熷懡鍛ㄦ湡 ===== +onMounted(()=>{ + getList(); + getArchiveListData(); +}); </script> <style lang="scss" scoped> .custom-tree-node { @@ -619,18 +881,27 @@ border-radius: 8px; background: #fff; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + max-height: calc(100vh - 240px); // 闄愬埗鏈�澶ч珮搴︼紝鍚敤婊氬姩 .custom-tree { padding: 8px; background: transparent; + // 浣跨敤GPU鍔犻�熸彁鍗囨粴鍔ㄦ�ц兘 + transform: translateZ(0); + will-change: scroll-position; :deep(.el-tree-node) { + // 鍑忓皯涓嶅繀瑕佺殑閲嶇粯 + contain: layout style; + .el-tree-node__content { height: 36px; padding: 0 8px; border-radius: 6px; margin: 2px 0; transition: all 0.2s ease; + // 浼樺寲娓叉煋鎬ц兘 + will-change: background-color; &:hover { background-color: #f0f9ff; @@ -710,13 +981,19 @@ color: #909399; min-height: auto; - &:hover { + &:hover:not(:disabled) { color: #1890ff; background-color: #f0f9ff; } - &.el-button--text:hover { + &.el-button--text:hover:not(:disabled) { background-color: #f0f9ff; + } + + &:disabled { + color: #c0c4cc; + cursor: not-allowed; + background-color: transparent; } } } @@ -732,11 +1009,13 @@ :deep(.el-input__wrapper) { border-radius: 4px; - border: 1px solid #d9d9d9; + border: 1px solid #40a9ff; transition: all 0.2s ease; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1); &:hover { - border-color: #40a9ff; + border-color: #1890ff; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.15); } &.is-focus { @@ -749,10 +1028,15 @@ padding: 4px 8px; font-size: 14px; color: #303133; + background-color: #fff; &::placeholder { color: #bfbfbf; } + + &:focus { + background-color: #f8fcff; + } } } -- Gitblit v1.9.3