zhou zhou
昨天 5d31cb5f1fb32a478d5b751ebfe97d47db890778
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
export function createMenuSearchState() {
  return {
    name: '',
    route: ''
  }
}
 
export function normalizeMenuNumber(value, fallback = 0) {
  if (value === '' || value === null || value === undefined) {
    return fallback
  }
  const normalized = Number(value)
  return Number.isNaN(normalized) ? fallback : normalized
}
 
export function normalizeMenuTitleKey(row = {}) {
  const titleKey = row.meta?.title || row.name || ''
  return titleKey && !String(titleKey).includes('.') ? `menu.${titleKey}` : titleKey
}
 
export function defaultMenuTitleFormatter(title = '') {
  if (!title) {
    return ''
  }
  return String(title).split('.').pop() || String(title)
}
 
export function getMenuDisplayTitle(row = {}, titleFormatter = defaultMenuTitleFormatter) {
  return titleFormatter(normalizeMenuTitleKey(row))
}
 
export function getMenuDisplayIcon(row = {}) {
  return row.meta?.icon || row.icon || ''
}
 
export function hasNestedMenus(row = {}) {
  return Array.isArray(row.children) && row.children.some((child) => !child.meta?.isAuthButton)
}
 
export function getMenuTypeTag(row = {}) {
  if (row.meta?.isAuthButton || Number(row.type) === 1) return 'danger'
  if (hasNestedMenus(row)) return 'info'
  return 'primary'
}
 
export function getMenuTypeText(row = {}) {
  if (row.meta?.isAuthButton || Number(row.type) === 1) return '按钮'
  if (hasNestedMenus(row)) return '目录'
  return '菜单'
}
 
export function getMenuStatusMeta(status) {
  return normalizeMenuNumber(status, 1) === 1
    ? { text: '启用', type: 'success' }
    : { text: '禁用', type: 'danger' }
}
 
export function normalizeMenuTreeOptions(nodes = [], titleFormatter = defaultMenuTitleFormatter) {
  if (!Array.isArray(nodes)) {
    return []
  }
 
  return nodes.map((node) => ({
    label: getMenuDisplayTitle(node, titleFormatter),
    value: normalizeMenuNumber(node.id, 0),
    children: normalizeMenuTreeOptions(node.children, titleFormatter)
  }))
}
 
export function buildMenuTreeOptions(tree = [], titleFormatter = defaultMenuTitleFormatter) {
  return [
    {
      label: '顶级菜单',
      value: 0,
      children: normalizeMenuTreeOptions(tree, titleFormatter)
    }
  ]
}
 
export function buildMenuSubmitPayload(formData = {}) {
  return {
    ...(formData.id ? { id: normalizeMenuNumber(formData.id, 0) } : {}),
    parentId: normalizeMenuNumber(formData.parentId, 0),
    name: String(formData.name || '').trim(),
    route: String(formData.route || '').trim(),
    component: String(formData.component || '').trim(),
    authority: String(formData.authority || '').trim(),
    icon: String(formData.icon || '').trim(),
    sort: normalizeMenuNumber(formData.sort, 0),
    status: normalizeMenuNumber(formData.status, 1),
    memo: String(formData.memo || '').trim(),
    type: formData.menuType === 'button' ? 1 : 0
  }
}
 
export function cloneMenuTree(source) {
  if (source === null || typeof source !== 'object') return source
  if (source instanceof Date) return new Date(source)
  if (Array.isArray(source)) return source.map((item) => cloneMenuTree(item))
  const cloned = {}
  for (const key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      cloned[key] = cloneMenuTree(source[key])
    }
  }
  return cloned
}
 
export function expandMenuAuthChildren(items = []) {
  return items.map((item) => {
    const clonedItem = cloneMenuTree(item)
    if (clonedItem.children?.length) {
      clonedItem.children = expandMenuAuthChildren(clonedItem.children)
    }
    if (item.meta?.authList?.length) {
      const authChildren = item.meta.authList.map((auth) => ({
        ...cloneMenuTree(auth),
        route: auth.route || '',
        component: auth.component || '',
        meta: {
          title: auth.title,
          authMark: auth.authMark,
          isAuthButton: true,
          parentPath: item.path,
          icon: auth.icon,
          sort: auth.sort,
          isEnable: normalizeMenuNumber(auth.status, 1) === 1
        }
      }))
      clonedItem.children = clonedItem.children?.length
        ? [...clonedItem.children, ...authChildren]
        : authChildren
    }
    return clonedItem
  })
}
 
export function filterMenuTree(items = [], filters = {}, titleFormatter = defaultMenuTitleFormatter) {
  const results = []
  const searchName = String(filters.name || '').toLowerCase().trim()
  const searchRoute = String(filters.route || '').toLowerCase().trim()
 
  for (const item of items) {
    const menuTitle = getMenuDisplayTitle(item, titleFormatter).toLowerCase()
    const menuRoute = String(item.route || item.path || item.authority || '').toLowerCase()
    const nameMatch = !searchName || menuTitle.includes(searchName)
    const routeMatch = !searchRoute || menuRoute.includes(searchRoute)
 
    if (item.children?.length) {
      const matchedChildren = filterMenuTree(item.children, filters, titleFormatter)
      if (matchedChildren.length > 0) {
        const clonedItem = cloneMenuTree(item)
        clonedItem.children = matchedChildren
        results.push(clonedItem)
        continue
      }
    }
 
    if (nameMatch && routeMatch) {
      results.push(cloneMenuTree(item))
    }
  }
  return results
}