refactor(tree): 菜单与部门树构建抽为通用 toTree 工具
- 菜单页、权限分配页与部门页的递归转换收敛为节点映射回调 - 节点字段与叶子 children 形态由调用方决定,输出与原实现一致
This commit is contained in:
1 parent
5cb4b31173
commit
ac58ec49cb
4 files changed
+62
-50
No files matched your search
@@ -102,7 +102,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { toFormSchema } from "@/utils/form-schema";
|
||||
import { findOptionChain } from "@/utils/tree";
|
||||
import { findOptionChain, toTree } from "@/utils/tree";
|
||||
import { useToast } from "@wot-ui/ui";
|
||||
import type { CascaderOption } from "@wot-ui/ui/components/wd-cascader/types";
|
||||
import ActionSheet, { type ActionSheetCommand } from "@/subPages/work/components/ActionSheet.vue";
|
||||
@@ -148,20 +148,20 @@ interface DeptTreeOption extends TreeOption {
|
||||
|
||||
// 转换为树组件数据格式
|
||||
const treeData = computed<DeptTreeOption[]>(() =>
|
||||
deptList.value.map((dept) => transformDeptToTree(dept))
|
||||
toTree(
|
||||
deptList.value,
|
||||
(dept) => dept.children,
|
||||
(dept, children) => ({
|
||||
value: String(dept.id),
|
||||
label: dept.name ?? "",
|
||||
id: dept.id,
|
||||
name: dept.name,
|
||||
status: dept.status,
|
||||
children,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
function transformDeptToTree(dept: DeptItem): DeptTreeOption {
|
||||
return {
|
||||
value: String(dept.id),
|
||||
label: dept.name ?? "",
|
||||
id: dept.id,
|
||||
name: dept.name,
|
||||
status: dept.status,
|
||||
children: dept.children?.map((child) => transformDeptToTree(child)) || [],
|
||||
};
|
||||
}
|
||||
|
||||
// 上级部门选择器
|
||||
const showParentPicker = ref(false);
|
||||
const parentSelected = ref<string | number>("");
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { toFormSchema } from "@/utils/form-schema";
|
||||
import { findOptionChain } from "@/utils/tree";
|
||||
import { findOptionChain, toTree } from "@/utils/tree";
|
||||
import { useToast } from "@wot-ui/ui";
|
||||
import ActionSheet, { type ActionSheetCommand } from "@/subPages/work/components/ActionSheet.vue";
|
||||
import { useConfirmAction } from "@/composables/useConfirmAction";
|
||||
@@ -230,24 +230,23 @@ const MENU_TYPE_TEXT: Record<MenuType, string> = {
|
||||
|
||||
// 菜单列表转树节点:value/label 供树组件使用,业务字段随节点透传给操作菜单
|
||||
const treeData = computed<MenuTreeOption[]>(() =>
|
||||
menuList.value.map((menu: MenuItem) => transformMenuToTree(menu))
|
||||
toTree(
|
||||
menuList.value,
|
||||
(menu) => menu.children,
|
||||
(menu, children) => ({
|
||||
value: menu.id ?? "",
|
||||
label: menu.name ?? "",
|
||||
id: menu.id,
|
||||
name: menu.name,
|
||||
type: menu.type,
|
||||
icon: menu.icon,
|
||||
visible: menu.visible,
|
||||
perm: menu.perm,
|
||||
children,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// 递归转换:子节点沿用同一套字段,空 id 用空串占位以满足树组件契约
|
||||
function transformMenuToTree(menu: MenuItem): MenuTreeOption {
|
||||
return {
|
||||
value: menu.id ?? "",
|
||||
label: menu.name ?? "",
|
||||
id: menu.id,
|
||||
name: menu.name,
|
||||
type: menu.type,
|
||||
icon: menu.icon,
|
||||
visible: menu.visible,
|
||||
perm: menu.perm,
|
||||
children: menu.children?.map((child: MenuItem) => transformMenuToTree(child)) || [],
|
||||
};
|
||||
}
|
||||
|
||||
// 菜单类型对应的标签颜色,类型缺失时按主色展示
|
||||
function getMenuTypeTag(type?: MenuType) {
|
||||
return (type && MENU_TYPE_TAG[type]) || "primary";
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import MenuAPI, { type MenuItem, type MenuType } from "@/api/menu";
|
||||
import { toTree } from "@/utils/tree";
|
||||
import RoleAPI from "@/api/role";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import TreeView from "@/subPages/work/components/TreeView.vue";
|
||||
@@ -104,27 +105,21 @@ interface PermissionTreeOption extends TreeOption {
|
||||
children?: PermissionTreeOption[];
|
||||
}
|
||||
|
||||
// 转换菜单为树结构
|
||||
const menuTree = computed<PermissionTreeOption[]>(() => {
|
||||
if (!menuList.value.length) return [];
|
||||
return transformMenuToTree(menuList.value);
|
||||
});
|
||||
|
||||
// 转换菜单为树组件格式
|
||||
function transformMenuToTree(menus: MenuItem[]): PermissionTreeOption[] {
|
||||
return menus.map((menu) => {
|
||||
const id = String(menu.id);
|
||||
const name = menu.name ?? "";
|
||||
return {
|
||||
value: id,
|
||||
label: name,
|
||||
id,
|
||||
name,
|
||||
// 转换菜单为树组件格式,叶子节点不携带 children 字段
|
||||
const menuTree = computed<PermissionTreeOption[]>(() =>
|
||||
toTree(
|
||||
menuList.value,
|
||||
(menu) => menu.children,
|
||||
(menu, children) => ({
|
||||
value: String(menu.id),
|
||||
label: menu.name ?? "",
|
||||
id: String(menu.id),
|
||||
name: menu.name ?? "",
|
||||
type: menu.type,
|
||||
children: menu.children ? transformMenuToTree(menu.children) : undefined,
|
||||
};
|
||||
});
|
||||
}
|
||||
children: menu.children ? children : undefined,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// 处理选中变化
|
||||
function handleCheck(keys: string[]) {
|
||||
|
||||
@@ -24,3 +24,21 @@ export function findOptionChain(
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归把带 children 的列表转为树节点
|
||||
*
|
||||
* 源列表的层级由 children 字段表达,节点字段与叶子形态由调用方决定
|
||||
*
|
||||
* @param items 源列表
|
||||
* @param getChildren 取节点的子列表,无子级时返回 undefined
|
||||
* @param node 单节点映射,children 为已构建的子节点数组,叶子节点为空数组
|
||||
* @returns 树节点列表
|
||||
*/
|
||||
export function toTree<TSource, TNode>(
|
||||
items: TSource[],
|
||||
getChildren: (item: TSource) => TSource[] | undefined,
|
||||
node: (item: TSource, children: TNode[]) => TNode
|
||||
): TNode[] {
|
||||
return items.map((item) => node(item, toTree(getChildren(item) ?? [], getChildren, node)));
|
||||
}
|
||||
Reference in new issue
Block a user