c-admin-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +232 -0
- package/dist/c-admin-kit.css +1 -0
- package/dist/c-admin-kit.js +2482 -0
- package/dist/c-admin-kit.umd.cjs +10 -0
- package/dist/components/AsyncButton/index.vue.d.ts +48 -0
- package/dist/components/CollapsibleContainer/index.vue.d.ts +73 -0
- package/dist/components/CustomDrawer/index.vue.d.ts +149 -0
- package/dist/components/ImagePreview/index.vue.d.ts +34 -0
- package/dist/components/SearchBox/index.vue.d.ts +122 -0
- package/dist/components/SelectWithAll/index.vue.d.ts +169 -0
- package/dist/components/SelectWithPage/index.vue.d.ts +78 -0
- package/dist/components/SimpleTable/index.vue.d.ts +337 -0
- package/dist/components/SimpleTable/useTableColumnConfig.d.ts +5 -0
- package/dist/components/diff/index.vue.d.ts +33 -0
- package/dist/components/index.d.ts +12 -0
- package/dist/composables/index.d.ts +6 -0
- package/dist/composables/useConfirmAction.d.ts +5 -0
- package/dist/composables/useConfirmSubmit.d.ts +5 -0
- package/dist/composables/useDialog.d.ts +5 -0
- package/dist/composables/useDownload.d.ts +5 -0
- package/dist/composables/useForm.d.ts +5 -0
- package/dist/composables/useListPage.d.ts +5 -0
- package/dist/index.d.ts +9 -0
- package/dist/types.d.ts +282 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/scroll-to.d.ts +7 -0
- package/dist/utils/searchFieldFactory.d.ts +34 -0
- package/dist/utils/treeManager.d.ts +64 -0
- package/dist/utils/validate.d.ts +30 -0
- package/package.json +86 -0
- package/src/components/AsyncButton/index.vue +58 -0
- package/src/components/CollapsibleContainer/index.vue +240 -0
- package/src/components/CustomDrawer/index.vue +167 -0
- package/src/components/ImagePreview/index.vue +88 -0
- package/src/components/SearchBox/index.vue +582 -0
- package/src/components/SelectWithAll/index.vue +281 -0
- package/src/components/SelectWithPage/index.vue +204 -0
- package/src/components/SimpleTable/index.vue +781 -0
- package/src/components/SimpleTable/useTableColumnConfig.ts +139 -0
- package/src/components/diff/index.vue +265 -0
- package/src/components/index.ts +35 -0
- package/src/composables/index.ts +6 -0
- package/src/composables/useConfirmAction.ts +62 -0
- package/src/composables/useConfirmSubmit.ts +68 -0
- package/src/composables/useDialog.ts +48 -0
- package/src/composables/useDownload.ts +83 -0
- package/src/composables/useForm.ts +114 -0
- package/src/composables/useListPage.ts +243 -0
- package/src/env.d.ts +7 -0
- package/src/index.ts +44 -0
- package/src/types.ts +344 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/scroll-to.ts +60 -0
- package/src/utils/searchFieldFactory.ts +302 -0
- package/src/utils/treeManager.ts +218 -0
- package/src/utils/validate.ts +64 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 通用树结构处理工具
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 递归从树中查找目标节点
|
|
7
|
+
* @param tree 树数组
|
|
8
|
+
* @param predicate 匹配函数
|
|
9
|
+
* @param childrenKey 子节点字段名,默认 'children'
|
|
10
|
+
* @returns 找到的节点对象
|
|
11
|
+
*/
|
|
12
|
+
export function findTreeNode<T extends Record<string, any>>(
|
|
13
|
+
tree: T[] = [],
|
|
14
|
+
predicate: (node: T) => boolean,
|
|
15
|
+
childrenKey: string = 'children'
|
|
16
|
+
): T | null {
|
|
17
|
+
for (const node of tree) {
|
|
18
|
+
if (predicate(node)) return node
|
|
19
|
+
const children = node[childrenKey] as T[] | undefined
|
|
20
|
+
if (children && children.length > 0) {
|
|
21
|
+
const found = findTreeNode(children, predicate, childrenKey)
|
|
22
|
+
if (found) return found
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 获取从根节点到目标节点的完整祖先路径 (仅值列表,如 [1, 10, 102])
|
|
30
|
+
* @param tree 树结构
|
|
31
|
+
* @param targetValue 目标节点标识
|
|
32
|
+
* @param keyField 匹配键名,如 'id'
|
|
33
|
+
* @param childrenKey 子节点字段名
|
|
34
|
+
* @returns 包含从根到目标节点的所有路径标识
|
|
35
|
+
*/
|
|
36
|
+
export function findNodePath<T extends Record<string, any>>(
|
|
37
|
+
tree: T[] = [],
|
|
38
|
+
targetValue: any,
|
|
39
|
+
keyField: string = 'id',
|
|
40
|
+
childrenKey: string = 'children'
|
|
41
|
+
): any[] {
|
|
42
|
+
const findPath = (nodes: T[], target: any, path: any[] = []): any[] => {
|
|
43
|
+
for (const node of nodes) {
|
|
44
|
+
const currentPath = [...path, node[keyField]]
|
|
45
|
+
if (node[keyField] === target) {
|
|
46
|
+
return currentPath
|
|
47
|
+
}
|
|
48
|
+
const children = node[childrenKey] as T[] | undefined
|
|
49
|
+
if (children && children.length > 0) {
|
|
50
|
+
const found = findPath(children, target, currentPath)
|
|
51
|
+
if (found.length > 0) return found
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return []
|
|
55
|
+
}
|
|
56
|
+
return findPath(tree, targetValue)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 获取从根节点到目标节点的完整祖先节点对象列表 (包含目标节点自身)
|
|
61
|
+
* @param tree 树结构
|
|
62
|
+
* @param predicate 匹配条件或目标节点键值
|
|
63
|
+
* @param childrenKey 子节点字段名
|
|
64
|
+
* @returns 祖先节点对象数组,根节点在前
|
|
65
|
+
*/
|
|
66
|
+
export function findParentNodes<T extends Record<string, any>>(
|
|
67
|
+
tree: T[] = [],
|
|
68
|
+
predicate: ((node: T) => boolean) | any,
|
|
69
|
+
childrenKey: string = 'children',
|
|
70
|
+
keyField: string = 'id'
|
|
71
|
+
): T[] {
|
|
72
|
+
const matchFn = typeof predicate === 'function' ? predicate : (node: T) => node[keyField] === predicate
|
|
73
|
+
|
|
74
|
+
const find = (nodes: T[], path: T[] = []): T[] => {
|
|
75
|
+
for (const node of nodes) {
|
|
76
|
+
const currentPath = [...path, node]
|
|
77
|
+
if (matchFn(node)) {
|
|
78
|
+
return currentPath
|
|
79
|
+
}
|
|
80
|
+
const children = node[childrenKey] as T[] | undefined
|
|
81
|
+
if (children && children.length > 0) {
|
|
82
|
+
const res = find(children, currentPath)
|
|
83
|
+
if (res.length > 0) return res
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return []
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return find(tree)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 树结构扁平化
|
|
94
|
+
* @param tree 树数组
|
|
95
|
+
* @param childrenKey 子节点字段名
|
|
96
|
+
* @returns 扁平化后的数组
|
|
97
|
+
*/
|
|
98
|
+
export function flattenTree<T extends Record<string, any>>(
|
|
99
|
+
tree: T[] = [],
|
|
100
|
+
childrenKey: string = 'children'
|
|
101
|
+
): T[] {
|
|
102
|
+
const result: T[] = []
|
|
103
|
+
const traverse = (nodes: T[]) => {
|
|
104
|
+
nodes.forEach(node => {
|
|
105
|
+
result.push(node)
|
|
106
|
+
const children = node[childrenKey] as T[] | undefined
|
|
107
|
+
if (children && children.length > 0) {
|
|
108
|
+
traverse(children)
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
traverse(tree)
|
|
113
|
+
return result
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** 树转列表别名 */
|
|
117
|
+
export const treeToList = flattenTree
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 扁平列表转树结构 (时间复杂度 O(n) 的高效 Map 算法)
|
|
121
|
+
* @param list 扁平列表
|
|
122
|
+
* @param options 配置项 { id: 'id', pid: 'parentId', children: 'children', rootPid: [0, null, undefined, ''] }
|
|
123
|
+
* @returns 构造完成的树数组
|
|
124
|
+
*/
|
|
125
|
+
export function listToTree<T extends Record<string, any>>(
|
|
126
|
+
list: T[] = [],
|
|
127
|
+
options: {
|
|
128
|
+
id?: string
|
|
129
|
+
pid?: string
|
|
130
|
+
children?: string
|
|
131
|
+
rootPid?: any[]
|
|
132
|
+
} = {}
|
|
133
|
+
): T[] {
|
|
134
|
+
const {
|
|
135
|
+
id = 'id',
|
|
136
|
+
pid = 'parentId',
|
|
137
|
+
children = 'children',
|
|
138
|
+
rootPid = [0, '0', null, undefined, ''],
|
|
139
|
+
} = options
|
|
140
|
+
|
|
141
|
+
const nodeMap = new Map<any, T>()
|
|
142
|
+
const tree: T[] = []
|
|
143
|
+
|
|
144
|
+
// 深拷贝并建立 Map 映射
|
|
145
|
+
list.forEach((item) => {
|
|
146
|
+
nodeMap.set(item[id], { ...item, [children]: [] })
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// 组织父子关系
|
|
150
|
+
list.forEach((item) => {
|
|
151
|
+
const node = nodeMap.get(item[id])!
|
|
152
|
+
const parentId = item[pid]
|
|
153
|
+
|
|
154
|
+
if (rootPid.includes(parentId) || !nodeMap.has(parentId)) {
|
|
155
|
+
tree.push(node)
|
|
156
|
+
} else {
|
|
157
|
+
const parent = nodeMap.get(parentId)
|
|
158
|
+
if (parent) {
|
|
159
|
+
;(parent as any)[children].push(node)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
return tree
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 过滤树结构,保留满足条件的节点及其父链路
|
|
169
|
+
* @param tree 树数组
|
|
170
|
+
* @param predicate 过滤条件
|
|
171
|
+
* @param childrenKey 子节点字段名
|
|
172
|
+
* @returns 过滤后的新树结构
|
|
173
|
+
*/
|
|
174
|
+
export function filterTree<T extends Record<string, any>>(
|
|
175
|
+
tree: T[] = [],
|
|
176
|
+
predicate: (node: T) => boolean,
|
|
177
|
+
childrenKey: string = 'children'
|
|
178
|
+
): T[] {
|
|
179
|
+
const filterNodes = (nodes: T[]): T[] => {
|
|
180
|
+
return nodes
|
|
181
|
+
.map(node => {
|
|
182
|
+
const clone = { ...node }
|
|
183
|
+
const children = clone[childrenKey] as T[] | undefined
|
|
184
|
+
if (children && children.length > 0) {
|
|
185
|
+
const filtered = filterNodes(children)
|
|
186
|
+
;(clone as any)[childrenKey] = filtered.length > 0 ? filtered : undefined
|
|
187
|
+
}
|
|
188
|
+
const filteredChildren = (clone as any)[childrenKey] as T[] | undefined
|
|
189
|
+
if (predicate(clone) || (filteredChildren && filteredChildren.length > 0)) {
|
|
190
|
+
return clone
|
|
191
|
+
}
|
|
192
|
+
return null
|
|
193
|
+
})
|
|
194
|
+
.filter(Boolean) as T[]
|
|
195
|
+
}
|
|
196
|
+
return filterNodes(tree)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 树结构映射/转换 (类似于数组的 map)
|
|
201
|
+
* @param tree 树数组
|
|
202
|
+
* @param mapper 节点转换器
|
|
203
|
+
* @param childrenKey 子节点字段名
|
|
204
|
+
*/
|
|
205
|
+
export function mapTree<T extends Record<string, any>, R extends Record<string, any>>(
|
|
206
|
+
tree: T[] = [],
|
|
207
|
+
mapper: (node: T) => R,
|
|
208
|
+
childrenKey: string = 'children'
|
|
209
|
+
): R[] {
|
|
210
|
+
return tree.map((node) => {
|
|
211
|
+
const mapped = mapper(node)
|
|
212
|
+
const children = node[childrenKey] as T[] | undefined
|
|
213
|
+
if (children && children.length > 0) {
|
|
214
|
+
;(mapped as any)[childrenKey] = mapTree(children, mapper, childrenKey)
|
|
215
|
+
}
|
|
216
|
+
return mapped
|
|
217
|
+
})
|
|
218
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路径匹配器
|
|
3
|
+
*/
|
|
4
|
+
export function isPathMatch(pattern: string, path: string): boolean {
|
|
5
|
+
const regexPattern = pattern.replace(/\//g, '\\/').replace(/\*\*/g, '.*').replace(/\*/g, '[^\\/]*')
|
|
6
|
+
const regex = new RegExp(`^${regexPattern}$`)
|
|
7
|
+
return regex.test(path)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 判断value字符串是否为空
|
|
12
|
+
*/
|
|
13
|
+
export function isEmpty(value: unknown): boolean {
|
|
14
|
+
if (value == null || value === "" || value === undefined || value === "undefined") {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 判断url是否是http或https
|
|
22
|
+
*/
|
|
23
|
+
export function isHttp(url: string): boolean {
|
|
24
|
+
if (!url || typeof url !== 'string') return false
|
|
25
|
+
return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 判断path是否为外链
|
|
30
|
+
*/
|
|
31
|
+
export function isExternal(path: string): boolean {
|
|
32
|
+
return /^(https?:|mailto:|tel:)/.test(path)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 验证合法 URL
|
|
37
|
+
*/
|
|
38
|
+
export function validURL(url: string): boolean {
|
|
39
|
+
const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
|
|
40
|
+
return reg.test(url)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 验证邮箱
|
|
45
|
+
*/
|
|
46
|
+
export function validEmail(email: string): boolean {
|
|
47
|
+
const reg = /^(([^<>()[\]\\.,;:\s@"]+(\.[[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
|
48
|
+
return reg.test(email)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 验证手机号
|
|
53
|
+
*/
|
|
54
|
+
export function validPhone(phone: string): boolean {
|
|
55
|
+
return /^1[3-9]\d{9}$/.test(phone)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function isString(str: unknown): str is string {
|
|
59
|
+
return typeof str === 'string' || str instanceof String
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function isArray(arg: unknown): arg is any[] {
|
|
63
|
+
return Array.isArray(arg)
|
|
64
|
+
}
|