20260915170028

This commit is contained in:
oneao committed 2026-09-15 17:00:29 +08:00
1 parent d26afb5fec
commit 1f56cc3efb
89 files changed
+1135 -397

No files matched your search

@@ -21,12 +21,18 @@ import { FolderTree, Save, RefreshCw } from '@lucide/vue'
import { Button, Splitter, SplitterPanel, Modal, Message, Spin } from '@/components/ui'
import { loadDataApi, saveObjectApi } from '@/services/api'
import {
buildTree,
sortTree,
findTreeNode,
addRowUpdate,
applyTreePosition,
buildSortedTree,
decorateTreeNodes,
expandAncestors,
findNodePosition,
findTreeNode,
insertTreeNode,
rebuildTreePositions,
removeTreeNode,
renumberSiblings,
sortTree,
} from '@/utils/tree'
import { cloneData, diffRow, diffRows } from '@/utils/dataChanges'
import { createTempId } from '@/utils/common'
@@ -36,14 +42,10 @@ import MenuTreePanel from './MenuTreePanel.vue'
import MenuBasicPanel from './MenuBasicPanel.vue'
import ModulePickerModal from './ModulePickerModal.vue'
import {
addRowUpdate,
applyMenuPosition,
MENU_NON_LEAF_TYPES,
MENU_TYPE_ICON_MAP,
buildMenuI18nKey,
findNodePosition,
markDirectoryNonLeaf,
menuRowOf,
rebuildTreePositions,
renumberSiblings,
} from './utils'
import { useI18nStore } from '@/stores/i18n'
@@ -158,7 +160,11 @@ async function loadMenuTree() {
menuTreeLoading.value = true
try {
const res = await loadDataApi('s_menu', '1 = 1', 'b_xh ASC, b_id ASC')
menuTreeData.value = markDirectoryNonLeaf(sortTree(buildTree(res.data || [])))
menuTreeData.value = decorateTreeNodes(buildSortedTree(res.data || []), {
typeField: 'b_menu_type',
nonLeafValues: MENU_NON_LEAF_TYPES,
iconMap: MENU_TYPE_ICON_MAP,
})
unsavedMenuIds.clear()
} catch (e) {
Message.error('加载菜单树失败:' + (e?.message || e))
@@ -221,7 +227,7 @@ async function onMenuDrop({ dragKey, dropKey, dropPosition }) {
}
// 只有目录能承载子菜单:页面/外链是末端节点,放入会形成「页面挂子菜单」的非法层级。
// 必须在移除被拖节点之前拦截,否则中途 return 会让节点凭空消失。
if (dropPosition === 'inside' && dropNode.b_menu_type !== 'directory') {
if (dropPosition === 'inside' && !MENU_NON_LEAF_TYPES.includes(dropNode.b_menu_type)) {
Message.warning('只能将菜单放入目录下')
return
}
@@ -330,7 +336,7 @@ async function addMenu(parentId, menuTypeValue = 'page') {
}
// b_depth / b_path 是 b_parent_id 的派生字段(b_path 非空且无默认值,缺失会新增失败)。
// 此处先按父级填一次占位值;保存前会用最终菜单编码重算(临时 id 不落库)。
applyMenuPosition(newMenu, parentNode)
applyTreePosition(newMenu, parentNode)
insertTreeNode(menuTreeData.value, newMenu, { sort: sortTree })
const ancestors = expandAncestors(menuTreeData.value, newId)
if (ancestors.length) {
@@ -611,10 +617,10 @@ async function beforeSave() {
// 否则会把 /-1/ 这类临时路径写进库。父级不在树中(数据异常)时无法派生,保持原值不动。
const parentId = menuData.b_parent_id ? String(menuData.b_parent_id) : null
if (!parentId) {
applyMenuPosition(menuData, null)
applyTreePosition(menuData, null)
} else {
const parentNode = findTreeNode(menuTreeData.value, parentId)
if (parentNode) applyMenuPosition(menuData, parentNode)
if (parentNode) applyTreePosition(menuData, parentNode)
}
// 受管 i18n 键:菜单统一 menu. 前缀
menuData.b_i18n = buildMenuI18nKey(menuCode)
@@ -828,7 +834,7 @@ async function loadModuleOptions() {
const res = await loadDataApi('s_module', 'b_canuse = 1', 'b_path ASC, b_xh ASC, b_id ASC')
const rows = res.data || []
moduleRows.value = rows
moduleTree.value = sortTree(buildTree(rows.map((row) => ({ ...row }))))
moduleTree.value = buildSortedTree(rows)
moduleOptionsLoaded = true
} catch (e) {
// Silently fail; modules will be empty