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.
Files changed (56) hide show
  1. package/README.md +232 -0
  2. package/dist/c-admin-kit.css +1 -0
  3. package/dist/c-admin-kit.js +2482 -0
  4. package/dist/c-admin-kit.umd.cjs +10 -0
  5. package/dist/components/AsyncButton/index.vue.d.ts +48 -0
  6. package/dist/components/CollapsibleContainer/index.vue.d.ts +73 -0
  7. package/dist/components/CustomDrawer/index.vue.d.ts +149 -0
  8. package/dist/components/ImagePreview/index.vue.d.ts +34 -0
  9. package/dist/components/SearchBox/index.vue.d.ts +122 -0
  10. package/dist/components/SelectWithAll/index.vue.d.ts +169 -0
  11. package/dist/components/SelectWithPage/index.vue.d.ts +78 -0
  12. package/dist/components/SimpleTable/index.vue.d.ts +337 -0
  13. package/dist/components/SimpleTable/useTableColumnConfig.d.ts +5 -0
  14. package/dist/components/diff/index.vue.d.ts +33 -0
  15. package/dist/components/index.d.ts +12 -0
  16. package/dist/composables/index.d.ts +6 -0
  17. package/dist/composables/useConfirmAction.d.ts +5 -0
  18. package/dist/composables/useConfirmSubmit.d.ts +5 -0
  19. package/dist/composables/useDialog.d.ts +5 -0
  20. package/dist/composables/useDownload.d.ts +5 -0
  21. package/dist/composables/useForm.d.ts +5 -0
  22. package/dist/composables/useListPage.d.ts +5 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/types.d.ts +282 -0
  25. package/dist/utils/index.d.ts +4 -0
  26. package/dist/utils/scroll-to.d.ts +7 -0
  27. package/dist/utils/searchFieldFactory.d.ts +34 -0
  28. package/dist/utils/treeManager.d.ts +64 -0
  29. package/dist/utils/validate.d.ts +30 -0
  30. package/package.json +86 -0
  31. package/src/components/AsyncButton/index.vue +58 -0
  32. package/src/components/CollapsibleContainer/index.vue +240 -0
  33. package/src/components/CustomDrawer/index.vue +167 -0
  34. package/src/components/ImagePreview/index.vue +88 -0
  35. package/src/components/SearchBox/index.vue +582 -0
  36. package/src/components/SelectWithAll/index.vue +281 -0
  37. package/src/components/SelectWithPage/index.vue +204 -0
  38. package/src/components/SimpleTable/index.vue +781 -0
  39. package/src/components/SimpleTable/useTableColumnConfig.ts +139 -0
  40. package/src/components/diff/index.vue +265 -0
  41. package/src/components/index.ts +35 -0
  42. package/src/composables/index.ts +6 -0
  43. package/src/composables/useConfirmAction.ts +62 -0
  44. package/src/composables/useConfirmSubmit.ts +68 -0
  45. package/src/composables/useDialog.ts +48 -0
  46. package/src/composables/useDownload.ts +83 -0
  47. package/src/composables/useForm.ts +114 -0
  48. package/src/composables/useListPage.ts +243 -0
  49. package/src/env.d.ts +7 -0
  50. package/src/index.ts +44 -0
  51. package/src/types.ts +344 -0
  52. package/src/utils/index.ts +4 -0
  53. package/src/utils/scroll-to.ts +60 -0
  54. package/src/utils/searchFieldFactory.ts +302 -0
  55. package/src/utils/treeManager.ts +218 -0
  56. 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
+ }