align(菜单管理): 同级拖拽排序接线(手柄列+类型/父级分组+reorder带menu_type)、列表拉全量类型、类型文案后台/软件、弹窗补菜单类型下拉、父菜单候选按类型过滤(对齐 admin.js loadColumns/bindColumnDragSort/persistColumnOrder)
This commit is contained in:
@@ -18,11 +18,17 @@ export interface MenuManageNode {
|
||||
children?: MenuManageNode[]
|
||||
}
|
||||
|
||||
/** 菜单类型展示文案(对齐 admin 菜单类型语义)。 */
|
||||
/** 菜单类型展示文案(对齐 admin.js:6824:admin → 后台,其余一律 → 软件)。 */
|
||||
export function menuTypeLabel(type: string | null | undefined): string {
|
||||
return (type || '').toLowerCase() === 'app' ? '应用菜单' : '后台菜单'
|
||||
return (type || '').toLowerCase() === 'admin' ? '后台' : '软件'
|
||||
}
|
||||
|
||||
/** 菜单类型下拉选项(对齐 admin.html:5931-5934 后台/软件)。 */
|
||||
export const MENU_TYPE_OPTIONS: Array<{ value: 'admin' | 'app'; label: string }> = [
|
||||
{ value: 'admin', label: '后台' },
|
||||
{ value: 'app', label: '软件' },
|
||||
]
|
||||
|
||||
export interface MenuManageForm {
|
||||
name: string
|
||||
columnKey: string
|
||||
@@ -198,6 +204,55 @@ export function siblingOrderAfterMove(group: number[], targetId: number, dir: nu
|
||||
return next
|
||||
}
|
||||
|
||||
/** 拖拽分组键:同"菜单类型 + 父级"才算同级(对齐 admin.js columnSiblingGroupKey)。 */
|
||||
export function menuSiblingGroupKey(node: MenuManageNode): string {
|
||||
return `${node.menuType || 'app'}|${node.parentId ?? ''}`
|
||||
}
|
||||
|
||||
/** 拖放排序:把 draggedId 插到 targetId 前/后,返回新的同级 id 顺序;任一 id 缺失或同 id 则原序。 */
|
||||
export function siblingOrderAfterDrop(
|
||||
group: number[],
|
||||
draggedId: number,
|
||||
targetId: number,
|
||||
placeAfter: boolean,
|
||||
): number[] {
|
||||
if (!Array.isArray(group) || group.length === 0) return []
|
||||
if (draggedId === targetId) return [...group]
|
||||
const next = [...group]
|
||||
const from = next.indexOf(draggedId)
|
||||
if (from < 0) return next
|
||||
const target = next.indexOf(targetId)
|
||||
if (target < 0) return next
|
||||
next.splice(from, 1)
|
||||
const insertAt = next.indexOf(targetId) + (placeAfter ? 1 : 0)
|
||||
next.splice(insertAt, 0, draggedId)
|
||||
return next
|
||||
}
|
||||
|
||||
/** 父菜单候选:仅同菜单类型的节点(对齐 admin 的类型联动父级下拉)。 */
|
||||
export function menuParentCandidates(nodes: MenuManageNode[], menuType: string): MenuManageNode[] {
|
||||
const type = (menuType || '').trim()
|
||||
return flattenMenuNodes(nodes).filter((node) => (node.menuType || '') === type)
|
||||
}
|
||||
|
||||
/** 同级重排请求体(对齐 admin.js persistColumnOrder:{ menu_type, ordered_ids })。 */
|
||||
export function toMenuReorderRequest(
|
||||
menuType: string,
|
||||
orderedIds: number[],
|
||||
): { menu_type: string; ordered_ids: number[] } {
|
||||
return { menu_type: text(menuType) || 'app', ordered_ids: dedupeOrderIds(orderedIds) }
|
||||
}
|
||||
|
||||
function dedupeOrderIds(ids: unknown[]): number[] {
|
||||
if (!Array.isArray(ids)) return []
|
||||
const set = new Set<number>()
|
||||
for (const v of ids) {
|
||||
const n = numberOrNull(v)
|
||||
if (n !== null && n > 0) set.add(n)
|
||||
}
|
||||
return [...set]
|
||||
}
|
||||
|
||||
/** 新建/编辑表单空值工厂:默认菜单类型为 admin、排序 0、根父节点。 */
|
||||
export function emptyMenuManageForm(): MenuManageForm {
|
||||
return { name: '', columnKey: '', parentId: null, menuType: ADMIN_MENU_TYPE, routePath: '', sortOrder: 0 }
|
||||
|
||||
Reference in New Issue
Block a user