- 新增共享级联工具 utils/treeCascade.ts:勾选子->祖先全部勾选;勾选父->子孙全部勾选/取消;取消子->父/祖不受影响(zTree 侧 chkboxType 置空,由代码级联) - GroupAuth.vue:接入代码级联,模块明细按 diff 提交(追加/删除),取消时同步清理子组继承标记 - AppModuleCheckTree.vue:角色授权接入同一套级联逻辑 - 组/角色授权树与应用节点默认闭合,点击文字等价勾选框(MyTree onClick 同步触发 onCheck) - PermissionView.vue「已授权应用」应用一级默认不展开模块
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 树勾选级联工具
|
||||
*
|
||||
* 规则(与 zTree chkboxType {Y:"ps", N:"s"} 语义一致,由代码实现,zTree 侧保持 {Y:"",N:""}):
|
||||
* 1. 勾选子节点 -> 其所有父/祖先节点全部勾选
|
||||
* 2. 勾选父节点 -> 其所有子孙节点全部勾选
|
||||
* 3. 取消父节点 -> 其所有子孙节点全部取消
|
||||
* 4. 取消子节点 -> 父/祖先保持原状(不受影响)
|
||||
* 取消任意节点时,同时清除其 inheritFlag(子组继承标记),并向下传播清除,避免残留。
|
||||
*/
|
||||
|
||||
export type ModuleVo = {
|
||||
id?: number;
|
||||
name?: string;
|
||||
checked?: boolean;
|
||||
inheritFlag?: boolean;
|
||||
children?: ModuleVo[];
|
||||
};
|
||||
|
||||
export function walkModules(nodes: ModuleVo[] | undefined, fn: (n: ModuleVo) => void): void {
|
||||
(nodes || []).forEach((n) => {
|
||||
fn(n);
|
||||
walkModules(n.children, fn);
|
||||
});
|
||||
}
|
||||
|
||||
function findModuleWithPath(
|
||||
nodes: ModuleVo[] | undefined,
|
||||
moduleId: number,
|
||||
ancestors: ModuleVo[] = []
|
||||
): { node: ModuleVo; ancestors: ModuleVo[] } | null {
|
||||
for (const n of nodes || []) {
|
||||
if (Number(n.id) === moduleId) return { node: n, ancestors };
|
||||
const hit = findModuleWithPath(n.children, moduleId, [...ancestors, n]);
|
||||
if (hit) return hit;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地数据(AppItem.modules 嵌套结构)级联。
|
||||
* 勾选:自身 + 祖先链 + 子孙全部勾选;取消:自身 + 子孙全部取消(祖先不动)。
|
||||
*/
|
||||
export function applyModuleCascade(app: { modules?: ModuleVo[] } | null | undefined, moduleId: number, checked: boolean): void {
|
||||
if (!app?.modules) return;
|
||||
const hit = findModuleWithPath(app.modules, moduleId);
|
||||
if (!hit) return;
|
||||
const { node, ancestors } = hit;
|
||||
node.checked = checked;
|
||||
if (checked) {
|
||||
ancestors.forEach((a) => {
|
||||
a.checked = true;
|
||||
});
|
||||
walkModules(node.children, (c) => {
|
||||
c.checked = true;
|
||||
});
|
||||
} else {
|
||||
walkModules([node], (c) => {
|
||||
c.checked = false;
|
||||
c.inheritFlag = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 应用整级勾选/取消:全部模块同步(取消时清除 inheritFlag) */
|
||||
export function setAppModulesChecked(app: { modules?: ModuleVo[] } | null | undefined, checked: boolean): void {
|
||||
walkModules(app?.modules, (n) => {
|
||||
n.checked = checked;
|
||||
if (!checked) n.inheritFlag = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* zTree 节点级联(仅同步视觉状态,checkTypeFlag / callbackFlag 均传 false,不触发 onCheck、不重复走 chkboxType)。
|
||||
* 勾选:自身 + 祖先链 + 子孙;取消:自身 + 子孙(祖先不动)。
|
||||
*/
|
||||
export function checkNodeWithCascade(treeObj: any, node: any, checked: boolean): void {
|
||||
if (!treeObj || !node) return;
|
||||
const set = (n: any, v: boolean) => {
|
||||
n.checked = v;
|
||||
if (!v && n.inheritFlag !== undefined) n.inheritFlag = false;
|
||||
treeObj.checkNode(n, v, false, false);
|
||||
};
|
||||
set(node, checked);
|
||||
if (checked) {
|
||||
let parent: any = node.getParentNode ? node.getParentNode() : null;
|
||||
while (parent) {
|
||||
set(parent, true);
|
||||
parent = parent.getParentNode ? parent.getParentNode() : null;
|
||||
}
|
||||
}
|
||||
walkZtreeChildren(node, (c) => set(c, checked));
|
||||
}
|
||||
|
||||
function walkZtreeChildren(node: any, fn: (n: any) => void): void {
|
||||
(node.children || []).forEach((c: any) => {
|
||||
fn(c);
|
||||
walkZtreeChildren(c, fn);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user