From de6ab3fcf299c0a5da2712d52284b771af9beb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=9E=E5=AE=9D=E5=B1=B1?= <1253070437@qq.com> Date: Tue, 9 Dec 2025 21:38:19 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=89=8D=E7=AB=AF=E3=80=91=E5=AD=97?= =?UTF-8?q?=E5=85=B8=E7=95=8C=E9=9D=A2=E6=A0=B7=E5=BC=8F=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=EF=BC=8C=E5=B7=A6=E4=BE=A7=E6=94=AF=E6=8C=81=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/dev/dict/category/index.vue | 370 +++++++++++++----- snowy-admin-web/src/views/dev/dict/index.vue | 21 +- 2 files changed, 266 insertions(+), 125 deletions(-) diff --git a/snowy-admin-web/src/views/dev/dict/category/index.vue b/snowy-admin-web/src/views/dev/dict/category/index.vue index acf76d2f..33fe7001 100644 --- a/snowy-admin-web/src/views/dev/dict/category/index.vue +++ b/snowy-admin-web/src/views/dev/dict/category/index.vue @@ -1,97 +1,120 @@ @@ -100,50 +123,63 @@ import dictApi from '@/api/dev/dictApi' import Form from './form.vue' import tool from '@/utils/tool' + import XnResizablePanel from '@/components/XnResizablePanel/index.vue' + const props = defineProps({ type: { type: String, default: 'FRM' } }) - const columns = [ + + const columns = ref([ { title: '字典名称', - dataIndex: 'dictLabel' + dataIndex: 'dictLabel', + width: 200 }, { title: '字典值', - dataIndex: 'dictValue' + dataIndex: 'dictValue', + ellipsis: true }, { title: '排序', - dataIndex: 'sortCode' + dataIndex: 'sortCode', + width: 100, + align: 'center' }, { title: '操作', dataIndex: 'action', align: 'center', - fixed: 'right' + fixed: 'right', + width: 150 } - ] - const categoryType = computed(() => { - return props.type - }) + ]) + + const categoryType = ref('FRM') + const treeSearchKey = ref('') + const autoExpandParent = ref(true) + // 定义tableDOM const tableRef = ref(null) const formRef = ref() + const cardLoading = ref(true) const searchFormRef = ref() const searchFormState = ref({}) // 默认展开的节点 let defaultExpandedKeys = ref([]) const treeData = ref([]) + // 备份完整树数据用于搜索 + const treeDataOrigin = ref([]) + // 替换treeNode 中 title,key,children const treeFieldNames = { children: 'children', title: 'dictLabel', key: 'id' } const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false } // 表格查询 返回 Promise 对象 const loadData = (parameter) => { - loadTreeData() parameter.category = categoryType.value return dictApi.dictPage(Object.assign(parameter, searchFormState.value)).then((data) => { if (data.records) { @@ -168,39 +204,103 @@ return data }) } + // 重置 const reset = () => { searchFormRef.value.resetFields() tableRef.value.refresh(true) } + + // 切换类型 + const typeChange = () => { + cardLoading.value = true + treeSearchKey.value = '' + loadTreeData() + // 切换类型时清空选中状态并刷新列表 + searchFormState.value.parentId = undefined + const index = columns.value.findIndex((f) => f.title === '层级') + if (index !== -1) { + columns.value.splice(index, 1) + } + tableRef.value.refresh(true) + } + // 加载左侧的树 const loadTreeData = () => { const param = { category: categoryType.value } - dictApi.dictTree(param).then((data) => { - if (data) { - treeData.value = data - } - }) + dictApi + .dictTree(param) + .then((res) => { + if (res) { + treeData.value = res + treeDataOrigin.value = res + } else { + treeData.value = [] + treeDataOrigin.value = [] + } + }) + .finally(() => { + cardLoading.value = false + }) } + // 初始化加载树 + loadTreeData() + + // 树搜索 + const onTreeSearch = () => { + if (!treeSearchKey.value) { + treeData.value = treeDataOrigin.value + return + } + // 简单的前端搜索过滤,如果数据量大应该走后端 + // 这里暂不实现复杂的前端递归过滤,AntDV的Tree通常配合后端搜索或扁平化数据处理 + // 既然是字典树,数据量通常不大,我们只高亮匹配项,或者让用户通过视觉查找 + // 这里为了体验,我们保持树结构不变,仅高亮,且展开所有 + autoExpandParent.value = true + // 递归获取所有包含key的节点的父级key,用于展开 + const expanded = [] + const getParentKeys = (data, key) => { + data.forEach((item) => { + if (item.children) { + if (JSON.stringify(item.children).indexOf(key) > -1) { + expanded.push(item.id) + } + getParentKeys(item.children, key) + } + }) + } + getParentKeys(treeDataOrigin.value, treeSearchKey.value) + defaultExpandedKeys.value = [...new Set(expanded)] + } + // 监听搜索词变化 + watch(treeSearchKey, () => { + onTreeSearch() + }) + // 点击树查询 const treeSelect = (selectedKeys) => { if (selectedKeys && selectedKeys.length > 0) { searchFormState.value.parentId = selectedKeys.toString() - if (!columns.find((f) => f.title === '层级')) { - columns.splice(2, 0, { + if (!columns.value.find((f) => f.title === '层级')) { + columns.value.splice(2, 0, { title: '层级', dataIndex: 'level', - width: 100 + width: 100, + align: 'center' }) } } else { delete searchFormState.value.parentId - columns.splice(2, 1) + const index = columns.value.findIndex((f) => f.title === '层级') + if (index !== -1) { + columns.value.splice(index, 1) + } } tableRef.value.refresh(true) } + // 删除 const remove = (record) => { let params = [ @@ -211,13 +311,17 @@ dictApi.dictDelete(params).then(() => { tableRef.value.refresh() refreshStoreDict() + loadTreeData() // 删除后刷新树 }) } + // 表单界面回调 const formSuccessful = () => { tableRef.value.refresh() refreshStoreDict() + loadTreeData() // 新增/编辑后刷新树 } + // 刷新store中的字典 const refreshStoreDict = () => { dictApi.dictTree().then((res) => { @@ -227,11 +331,67 @@ diff --git a/snowy-admin-web/src/views/dev/dict/index.vue b/snowy-admin-web/src/views/dev/dict/index.vue index 1e7ab465..7b7ccac0 100644 --- a/snowy-admin-web/src/views/dev/dict/index.vue +++ b/snowy-admin-web/src/views/dev/dict/index.vue @@ -1,26 +1,7 @@ -