@quiteer/naive-extra 0.0.1
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/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/components/breadcrumb/index.d.ts +0 -0
- package/dist/components/breadcrumb/index.vue.d.ts +3 -0
- package/dist/components/breadcrumb/props.d.ts +0 -0
- package/dist/components/button/action/index.d.ts +3 -0
- package/dist/components/button/action/index.vue.d.ts +118 -0
- package/dist/components/button/action/props.d.ts +63 -0
- package/dist/components/button/action/utils.d.ts +8 -0
- package/dist/components/button/base/index.d.ts +3 -0
- package/dist/components/button/base/index.vue.d.ts +36 -0
- package/dist/components/button/base/props.d.ts +27 -0
- package/dist/components/button/index.d.ts +4 -0
- package/dist/components/button/types.d.ts +2 -0
- package/dist/components/form/helper.d.ts +11 -0
- package/dist/components/form/index.d.ts +3 -0
- package/dist/components/form/index.vue.d.ts +642 -0
- package/dist/components/form/props.d.ts +34 -0
- package/dist/components/icon/IconPicker.vue.d.ts +13 -0
- package/dist/components/icon/iconify.d.ts +25 -0
- package/dist/components/icon/index.d.ts +3 -0
- package/dist/components/icon/index.vue.d.ts +12 -0
- package/dist/components/layout/const.d.ts +22 -0
- package/dist/components/layout/context.d.ts +77 -0
- package/dist/components/layout/index.d.ts +5 -0
- package/dist/components/layout/index.vue.d.ts +80 -0
- package/dist/components/layout/layout-parts/AppBreadcrumb.vue.d.ts +3 -0
- package/dist/components/layout/layout-parts/AppFooter.vue.d.ts +18 -0
- package/dist/components/layout/layout-parts/AppHeader.vue.d.ts +18 -0
- package/dist/components/layout/layout-parts/AppLeftLogoInfo.vue.d.ts +3 -0
- package/dist/components/layout/layout-parts/AppMain.vue.d.ts +18 -0
- package/dist/components/layout/layout-parts/AppSidebar.vue.d.ts +4067 -0
- package/dist/components/layout/layout-parts/LayoutTransition.vue.d.ts +58 -0
- package/dist/components/layout/mode.d.ts +0 -0
- package/dist/components/layout/props.d.ts +35 -0
- package/dist/components/layout/types.d.ts +59 -0
- package/dist/components/layout/utils.d.ts +97 -0
- package/dist/components/provider/index.d.ts +3 -0
- package/dist/components/provider/index.vue.d.ts +19 -0
- package/dist/components/provider/props.d.ts +33 -0
- package/dist/components/search-bar/index.d.ts +3 -0
- package/dist/components/search-bar/index.vue.d.ts +1288 -0
- package/dist/components/search-bar/props.d.ts +15 -0
- package/dist/components/table/TableSetting.vue.d.ts +15 -0
- package/dist/components/table/index.d.ts +4 -0
- package/dist/components/table/index.vue.d.ts +17246 -0
- package/dist/components/table/props.d.ts +26 -0
- package/dist/components/table/useColumn.d.ts +15 -0
- package/dist/components/upload/enum.d.ts +18 -0
- package/dist/components/upload/index.d.ts +4 -0
- package/dist/components/upload/index.vue.d.ts +17 -0
- package/dist/components/upload/props.d.ts +7 -0
- package/dist/const/defaults.d.ts +7 -0
- package/dist/const/index.d.ts +2 -0
- package/dist/const/types.d.ts +134 -0
- package/dist/context/color.d.ts +13 -0
- package/dist/context/common.d.ts +117 -0
- package/dist/context/index.d.ts +41 -0
- package/dist/context/layout.d.ts +52 -0
- package/dist/context/loading-bar.d.ts +14 -0
- package/dist/context/locale.d.ts +143 -0
- package/dist/context/menu.d.ts +212 -0
- package/dist/context/message.d.ts +14 -0
- package/dist/context/notification.d.ts +14 -0
- package/dist/context/table.d.ts +917 -0
- package/dist/context/theme.d.ts +20 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/useAdmin.d.ts +0 -0
- package/dist/hooks/useForm.d.ts +54 -0
- package/dist/hooks/useLayout.d.ts +116 -0
- package/dist/hooks/useProviderContext.d.ts +17 -0
- package/dist/hooks/useTable.d.ts +66 -0
- package/dist/hooks/useThemeOverrides.d.ts +8 -0
- package/dist/hooks/useUpload.d.ts +22 -0
- package/dist/index.css +36 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +6771 -0
- package/dist/share/compact.d.ts +16 -0
- package/dist/share/index.d.ts +2 -0
- package/dist/share/menu.d.ts +0 -0
- package/dist/share/route.d.ts +0 -0
- package/dist/share/slot.d.ts +6 -0
- package/dist/utils/form.d.ts +0 -0
- package/dist/utils/index.d.ts +0 -0
- package/dist/utils/transformRoutes.d.ts +67 -0
- package/dist/utils/tree.d.ts +6 -0
- package/package.json +53 -0
- package/src/auto-imports.d.ts +73 -0
- package/src/components/breadcrumb/index.ts +0 -0
- package/src/components/breadcrumb/index.vue +0 -0
- package/src/components/breadcrumb/props.ts +0 -0
- package/src/components/button/action/index.ts +4 -0
- package/src/components/button/action/index.vue +313 -0
- package/src/components/button/action/props.ts +78 -0
- package/src/components/button/action/utils.ts +122 -0
- package/src/components/button/base/index.ts +4 -0
- package/src/components/button/base/index.vue +156 -0
- package/src/components/button/base/props.ts +29 -0
- package/src/components/button/index.ts +4 -0
- package/src/components/button/types.ts +2 -0
- package/src/components/form/helper.ts +73 -0
- package/src/components/form/index.ts +5 -0
- package/src/components/form/index.vue +243 -0
- package/src/components/form/props.ts +75 -0
- package/src/components/icon/IconPicker.vue +255 -0
- package/src/components/icon/iconify.ts +80 -0
- package/src/components/icon/index.ts +7 -0
- package/src/components/icon/index.vue +23 -0
- package/src/components/layout/const.ts +102 -0
- package/src/components/layout/context.ts +189 -0
- package/src/components/layout/index.ts +8 -0
- package/src/components/layout/index.vue +64 -0
- package/src/components/layout/layout-parts/AppBreadcrumb.vue +108 -0
- package/src/components/layout/layout-parts/AppFooter.vue +26 -0
- package/src/components/layout/layout-parts/AppHeader.vue +112 -0
- package/src/components/layout/layout-parts/AppLeftLogoInfo.vue +30 -0
- package/src/components/layout/layout-parts/AppMain.vue +34 -0
- package/src/components/layout/layout-parts/AppSidebar.vue +174 -0
- package/src/components/layout/layout-parts/LayoutTransition.vue +366 -0
- package/src/components/layout/mode.ts +0 -0
- package/src/components/layout/props.ts +36 -0
- package/src/components/layout/types.ts +79 -0
- package/src/components/layout/utils.ts +201 -0
- package/src/components/provider/index.ts +5 -0
- package/src/components/provider/index.vue +69 -0
- package/src/components/provider/props.ts +45 -0
- package/src/components/search-bar/index.ts +5 -0
- package/src/components/search-bar/index.vue +282 -0
- package/src/components/search-bar/props.ts +26 -0
- package/src/components/table/TableSetting.vue +253 -0
- package/src/components/table/index.ts +14 -0
- package/src/components/table/index.vue +179 -0
- package/src/components/table/props.ts +29 -0
- package/src/components/table/useColumn.ts +104 -0
- package/src/components/upload/enum.ts +21 -0
- package/src/components/upload/index.ts +9 -0
- package/src/components/upload/index.vue +267 -0
- package/src/components/upload/props.ts +8 -0
- package/src/components.d.ts +154 -0
- package/src/const/defaults.ts +94 -0
- package/src/const/index.ts +2 -0
- package/src/const/types.ts +139 -0
- package/src/context/color.ts +53 -0
- package/src/context/common.ts +27 -0
- package/src/context/index.ts +141 -0
- package/src/context/layout.ts +34 -0
- package/src/context/loading-bar.ts +26 -0
- package/src/context/locale.ts +22 -0
- package/src/context/menu.ts +26 -0
- package/src/context/message.ts +30 -0
- package/src/context/notification.ts +29 -0
- package/src/context/table.ts +32 -0
- package/src/context/theme.ts +35 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useAdmin.ts +0 -0
- package/src/hooks/useForm.ts +272 -0
- package/src/hooks/useLayout.ts +300 -0
- package/src/hooks/useProviderContext.ts +47 -0
- package/src/hooks/useTable.ts +241 -0
- package/src/hooks/useThemeOverrides.ts +18 -0
- package/src/hooks/useUpload.ts +82 -0
- package/src/index.ts +59 -0
- package/src/share/compact.ts +35 -0
- package/src/share/index.ts +2 -0
- package/src/share/menu.ts +0 -0
- package/src/share/route.ts +0 -0
- package/src/share/slot.ts +29 -0
- package/src/utils/form.ts +0 -0
- package/src/utils/index.ts +0 -0
- package/src/utils/transformRoutes.ts +163 -0
- package/src/utils/tree.ts +31 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import type { DataTableColumn } from 'naive-ui'
|
|
2
|
+
import type { QuiTable } from '../components/table'
|
|
3
|
+
import { NImage } from 'naive-ui'
|
|
4
|
+
import { h, ref } from 'vue'
|
|
5
|
+
|
|
6
|
+
interface UseTableReturn<T> {
|
|
7
|
+
tableRef: ReturnType<typeof ref<InstanceType<typeof QuiTable>>>
|
|
8
|
+
refresh: (isReset?: boolean) => void
|
|
9
|
+
downloadCsv: (fileName?: string) => void
|
|
10
|
+
setActions: (columnOption: Partial<DataTableColumn<T>>) => void
|
|
11
|
+
setColumns: (columns: DataTableColumn<T>[]) => void
|
|
12
|
+
getColumns: () => DataTableColumn<T>[] | undefined
|
|
13
|
+
setSize: (size: 'small' | 'medium' | 'large') => void
|
|
14
|
+
setStriped: (striped: boolean) => void
|
|
15
|
+
getPagination: () => any
|
|
16
|
+
setPagination: (patch: Partial<{ page: number, pageSize: number }>) => void
|
|
17
|
+
getData: <TRow = any>() => TRow[] | undefined
|
|
18
|
+
setData: (rows: T[]) => void
|
|
19
|
+
setFetch: (fn: (pageInfo: { pageNum: number, pageSize: number }) => Promise<{ list: T[], total: number }>) => void
|
|
20
|
+
withSearch: (
|
|
21
|
+
getSearchParams: () => Record<string, any>,
|
|
22
|
+
remote: (args: { pageNum: number, pageSize: number } & Record<string, any>) => Promise<{ list: T[], total: number }>
|
|
23
|
+
) => void
|
|
24
|
+
createImageColumn: (key: keyof T & string, title?: string, width?: number) => DataTableColumn<T>
|
|
25
|
+
createIndexColumn: (title?: string, width?: number) => DataTableColumn<T>
|
|
26
|
+
createTextColumn: (key: keyof T & string, title: string, width?: number) => DataTableColumn<T>
|
|
27
|
+
createMoneyColumn: (key: keyof T & string, title?: string, precision?: number) => DataTableColumn<T>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 表格辅助函数集合
|
|
32
|
+
*
|
|
33
|
+
* 提供对 `QuiTable` 实例的常用操作封装,以及常用列的构造器。
|
|
34
|
+
* 适合在业务或示例中快速调用刷新、导出、追加操作列等能力。
|
|
35
|
+
*
|
|
36
|
+
* @returns 一组表格操作与便捷列构造器
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const { tableRef, refresh, downloadCsv, setActions } = useTable()
|
|
41
|
+
* refresh(true)
|
|
42
|
+
* downloadCsv('export')
|
|
43
|
+
* setActions({ title: '操作', render: (row) => h('div', {}, '查看') })
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* - 所有实例方法均基于 `QuiTable` 的 `defineExpose` 能力安全调用
|
|
48
|
+
* - 列构造器仅提供基础构造,仍可按需覆盖属性
|
|
49
|
+
*
|
|
50
|
+
* @security
|
|
51
|
+
* - 导出文件名由调用方决定,请避免包含敏感信息
|
|
52
|
+
*
|
|
53
|
+
* @performance
|
|
54
|
+
* - 方法本身为轻量封装,不引入额外复杂度
|
|
55
|
+
*/
|
|
56
|
+
export function useTable<T = Record<string, any>>(): UseTableReturn<T> {
|
|
57
|
+
const tableRef = ref<InstanceType<typeof QuiTable>>()
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 刷新表格数据
|
|
61
|
+
*
|
|
62
|
+
* @param isReset - 是否重置到第一页
|
|
63
|
+
*/
|
|
64
|
+
function refresh(isReset = false) {
|
|
65
|
+
tableRef.value?.updateTableData(isReset)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 导出 CSV
|
|
70
|
+
*
|
|
71
|
+
* @param fileName - 文件名(不含扩展名)
|
|
72
|
+
*/
|
|
73
|
+
function downloadCsv(fileName = 'data-table') {
|
|
74
|
+
tableRef.value?.downloadCsv(fileName)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 追加操作列
|
|
79
|
+
*
|
|
80
|
+
* @param columnOption - 操作列的部分配置
|
|
81
|
+
*/
|
|
82
|
+
function setActions(columnOption: Partial<DataTableColumn<T>>) {
|
|
83
|
+
tableRef.value?.setActions(columnOption as any)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 设置列集合
|
|
88
|
+
*/
|
|
89
|
+
function setColumns(columns: DataTableColumn<T>[]) {
|
|
90
|
+
tableRef.value?.setColumns(columns as any)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 获取当前列集合
|
|
95
|
+
*/
|
|
96
|
+
function getColumns(): DataTableColumn<T>[] | undefined {
|
|
97
|
+
return tableRef.value?.getColumns() as any
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 设置尺寸
|
|
102
|
+
*/
|
|
103
|
+
function setSize(size: 'small' | 'medium' | 'large') {
|
|
104
|
+
tableRef.value?.setSize(size as any)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 设置斑马纹
|
|
109
|
+
*/
|
|
110
|
+
function setStriped(striped: boolean) {
|
|
111
|
+
tableRef.value?.setStriped(striped)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 获取分页信息快照
|
|
116
|
+
*/
|
|
117
|
+
function getPagination() {
|
|
118
|
+
return tableRef.value?.getPagination()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 局部更新分页信息
|
|
123
|
+
*/
|
|
124
|
+
function setPagination(patch: Partial<{ page: number, pageSize: number }>) {
|
|
125
|
+
tableRef.value?.setPagination(patch as any)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 获取当前数据
|
|
130
|
+
*/
|
|
131
|
+
function getData<TRow = any>(): TRow[] | undefined {
|
|
132
|
+
return tableRef.value?.getData() as any
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* 覆盖当前数据行
|
|
137
|
+
*/
|
|
138
|
+
function setData(rows: T[]) {
|
|
139
|
+
tableRef.value?.setData(rows as any)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 替换远端 fetch 函数
|
|
144
|
+
*/
|
|
145
|
+
function setFetch(
|
|
146
|
+
fn: (pageInfo: { pageNum: number, pageSize: number }) => Promise<{ list: T[], total: number }>
|
|
147
|
+
) {
|
|
148
|
+
tableRef.value?.setFetch(fn as any)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 绑定外部搜索条件到远端 fetch
|
|
153
|
+
*
|
|
154
|
+
* @param getSearchParams - 返回搜索条件对象的函数
|
|
155
|
+
* @param remote - 实际请求函数,接收合并后的参数
|
|
156
|
+
*/
|
|
157
|
+
function withSearch(
|
|
158
|
+
getSearchParams: () => Record<string, any>,
|
|
159
|
+
remote: (args: { pageNum: number, pageSize: number } & Record<string, any>) => Promise<{ list: T[], total: number }>
|
|
160
|
+
) {
|
|
161
|
+
setFetch(async ({ pageNum, pageSize }) => {
|
|
162
|
+
const params = getSearchParams() || {}
|
|
163
|
+
return remote({ pageNum, pageSize, ...params })
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 构造图片列
|
|
169
|
+
*
|
|
170
|
+
* @param key - 数据字段
|
|
171
|
+
* @param title - 列标题
|
|
172
|
+
* @param width - 列宽
|
|
173
|
+
* @returns 图片列配置
|
|
174
|
+
*/
|
|
175
|
+
function createImageColumn(key: keyof T & string, title = '图片', width = 80): DataTableColumn<T> {
|
|
176
|
+
return {
|
|
177
|
+
title,
|
|
178
|
+
key,
|
|
179
|
+
width,
|
|
180
|
+
render(row) {
|
|
181
|
+
return h(NImage, { width, src: (row as any)[key] })
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 构造序号列
|
|
188
|
+
*/
|
|
189
|
+
function createIndexColumn(title = '序号', width = 80): DataTableColumn<T> {
|
|
190
|
+
return {
|
|
191
|
+
title,
|
|
192
|
+
key: '__index__' as any,
|
|
193
|
+
width,
|
|
194
|
+
render(_: any, index: number) {
|
|
195
|
+
return index + 1
|
|
196
|
+
}
|
|
197
|
+
} as any
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* 构造纯文本列
|
|
202
|
+
*/
|
|
203
|
+
function createTextColumn(key: keyof T & string, title: string, width?: number): DataTableColumn<T> {
|
|
204
|
+
return { title, key, width } as any
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 金额列
|
|
209
|
+
*/
|
|
210
|
+
function createMoneyColumn(key: keyof T & string, title = '金额', precision = 2): DataTableColumn<T> {
|
|
211
|
+
return {
|
|
212
|
+
title,
|
|
213
|
+
key,
|
|
214
|
+
render(row: T) {
|
|
215
|
+
const val = Number((row as any)[key] ?? 0)
|
|
216
|
+
return (val / 100).toFixed(precision)
|
|
217
|
+
}
|
|
218
|
+
} as any
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
tableRef,
|
|
223
|
+
refresh,
|
|
224
|
+
downloadCsv,
|
|
225
|
+
setActions,
|
|
226
|
+
setColumns,
|
|
227
|
+
getColumns,
|
|
228
|
+
setSize,
|
|
229
|
+
setStriped,
|
|
230
|
+
getPagination,
|
|
231
|
+
setPagination,
|
|
232
|
+
getData,
|
|
233
|
+
setData,
|
|
234
|
+
setFetch,
|
|
235
|
+
withSearch,
|
|
236
|
+
createImageColumn,
|
|
237
|
+
createIndexColumn,
|
|
238
|
+
createTextColumn,
|
|
239
|
+
createMoneyColumn
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
import { lightTheme } from 'naive-ui'
|
|
3
|
+
import { ref } from 'vue'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 获取 Naive UI 特定组件的主题覆盖配置
|
|
7
|
+
* 核心价值在于提供完整的 TypeScript 类型提示,方便用户在业务代码中访问或动态计算样式。
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
export function useThemeOverrides<K extends keyof typeof lightTheme>(
|
|
11
|
+
componentName: K
|
|
12
|
+
): Ref<(typeof lightTheme)[K]> {
|
|
13
|
+
const theme = lightTheme
|
|
14
|
+
|
|
15
|
+
const overrides = ref(theme[componentName]) as Ref<(typeof lightTheme)[K]>
|
|
16
|
+
|
|
17
|
+
return overrides
|
|
18
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { UploadProps } from 'naive-ui'
|
|
2
|
+
import type { Props as QuiUploadProps } from '../components/upload/props'
|
|
3
|
+
import { AcceptType } from '../components/upload/enum'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 上传组件属性辅助函数
|
|
7
|
+
*
|
|
8
|
+
* 提供一组便捷的方法来生成不同类型的上传组件属性配置(如图片、视频、音频)。
|
|
9
|
+
*
|
|
10
|
+
* @param config - 基础上传配置
|
|
11
|
+
* @returns 包含获取不同类型上传属性的方法对象
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const { getImageUploadProps } = useUploadProps({ max: 5 })
|
|
16
|
+
* const props = getImageUploadProps({ action: '/upload' })
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function useUploadProps(config: QuiUploadProps) {
|
|
20
|
+
const uploadComponentProps: QuiUploadProps = {
|
|
21
|
+
defaultUpload: true,
|
|
22
|
+
max: 1,
|
|
23
|
+
accept: undefined,
|
|
24
|
+
...config
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 获取通用上传属性
|
|
29
|
+
*
|
|
30
|
+
* @param option - 额外的上传配置
|
|
31
|
+
* @returns 合并后的上传属性
|
|
32
|
+
*/
|
|
33
|
+
const getUploadProps = (option?: UploadProps): UploadProps => {
|
|
34
|
+
return { ...uploadComponentProps, ...option }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 获取图片上传属性
|
|
39
|
+
*
|
|
40
|
+
* @param option - 额外的上传配置
|
|
41
|
+
* @returns 图片上传配置
|
|
42
|
+
*/
|
|
43
|
+
const getImageUploadProps = (option?: UploadProps): UploadProps => {
|
|
44
|
+
return {
|
|
45
|
+
...getUploadProps({ accept: AcceptType.Image }),
|
|
46
|
+
...option
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 获取视频上传属性
|
|
52
|
+
*
|
|
53
|
+
* @param option - 额外的上传配置
|
|
54
|
+
* @returns 视频上传配置
|
|
55
|
+
*/
|
|
56
|
+
const getVedioUploadProps = (option?: UploadProps): UploadProps => {
|
|
57
|
+
return {
|
|
58
|
+
...getUploadProps({ accept: AcceptType.Video }),
|
|
59
|
+
...option
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 获取音频上传属性
|
|
65
|
+
*
|
|
66
|
+
* @param option - 额外的上传配置
|
|
67
|
+
* @returns 音频上传配置
|
|
68
|
+
*/
|
|
69
|
+
const getAudioUploadProps = (option?: UploadProps): UploadProps => {
|
|
70
|
+
return {
|
|
71
|
+
...getUploadProps({ accept: AcceptType.Audio }),
|
|
72
|
+
...option
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
getUploadProps,
|
|
78
|
+
getImageUploadProps,
|
|
79
|
+
getVedioUploadProps,
|
|
80
|
+
getAudioUploadProps
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { DialogApi, LoadingBarApi, MessageApi, NotificationApi } from 'naive-ui'
|
|
2
|
+
|
|
3
|
+
import { QuiActionButton, QuiBaseButton } from './components/button'
|
|
4
|
+
import { QuiForm } from './components/form'
|
|
5
|
+
import { QuiIcon, QuiIconPicker } from './components/icon'
|
|
6
|
+
import { DEFAULT_LAYOUT_TYPE, QuiLayout } from './components/layout'
|
|
7
|
+
import { QuiProvider } from './components/provider'
|
|
8
|
+
import { QuiSearchBar } from './components/search-bar'
|
|
9
|
+
import { QuiTable } from './components/table'
|
|
10
|
+
|
|
11
|
+
import { AcceptType, QuiUpload } from './components/upload'
|
|
12
|
+
import 'virtual:uno.css'
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
QuiActionButton,
|
|
16
|
+
QuiBaseButton,
|
|
17
|
+
QuiForm,
|
|
18
|
+
QuiIcon,
|
|
19
|
+
QuiIconPicker,
|
|
20
|
+
QuiLayout,
|
|
21
|
+
QuiProvider,
|
|
22
|
+
QuiSearchBar,
|
|
23
|
+
QuiTable,
|
|
24
|
+
QuiUpload
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
AcceptType
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { DEFAULT_LAYOUT_TYPE }
|
|
32
|
+
|
|
33
|
+
export type { ActionItem, BaseButtonProps } from './components/button'
|
|
34
|
+
export type { CustomSwitchProps, FormProps, FormSchema } from './components/form'
|
|
35
|
+
export type { LayoutProps, LayoutType, RouteMeta } from './components/layout'
|
|
36
|
+
|
|
37
|
+
export type { ProviderProps } from './components/provider'
|
|
38
|
+
export type { SearchBarProps } from './components/search-bar'
|
|
39
|
+
export type {
|
|
40
|
+
TableColumn,
|
|
41
|
+
TableColumns,
|
|
42
|
+
TableExportType,
|
|
43
|
+
TableFetchFn,
|
|
44
|
+
TableProps,
|
|
45
|
+
TableSettings,
|
|
46
|
+
TableSize
|
|
47
|
+
} from './components/table'
|
|
48
|
+
export type { UploadProps } from './components/upload'
|
|
49
|
+
export * from './context'
|
|
50
|
+
export * from './hooks'
|
|
51
|
+
|
|
52
|
+
declare global {
|
|
53
|
+
interface Window {
|
|
54
|
+
$message?: MessageApi
|
|
55
|
+
$dialog?: DialogApi
|
|
56
|
+
$notification?: NotificationApi
|
|
57
|
+
$loadingBar?: LoadingBarApi
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 格式化像素值
|
|
3
|
+
*
|
|
4
|
+
* 将数字转换为带 px 单位的字符串,如果输入已带单位则保持不变。
|
|
5
|
+
*
|
|
6
|
+
* @param val - 数值或字符串
|
|
7
|
+
* @returns 格式化后的字符串或 undefined
|
|
8
|
+
*/
|
|
9
|
+
export function formatPx(val?: number | string): string | undefined {
|
|
10
|
+
if (val === undefined || val === null || val === '')
|
|
11
|
+
return undefined
|
|
12
|
+
if (typeof val === 'string' && (val.endsWith('px') || val.endsWith('%') || val.endsWith('vh') || val.endsWith('vw') || val.endsWith('rem') || val.endsWith('em'))) {
|
|
13
|
+
return val
|
|
14
|
+
}
|
|
15
|
+
return `${val}px`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 移除对象中值为 undefined 或 null 的属性 (浅压缩)
|
|
20
|
+
*
|
|
21
|
+
* @param obj - 目标对象
|
|
22
|
+
* @returns 清理后的新对象
|
|
23
|
+
*/
|
|
24
|
+
export function compact<T extends object>(obj: T): Partial<T> {
|
|
25
|
+
const result: any = {}
|
|
26
|
+
for (const key in obj) {
|
|
27
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
28
|
+
const value = obj[key]
|
|
29
|
+
if (value !== undefined && value !== null) {
|
|
30
|
+
result[key] = value
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result as Partial<T>
|
|
35
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Slot, VNode } from 'vue'
|
|
2
|
+
import { Comment, Fragment, Text } from 'vue'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 判断插槽是否有内容(忽略注释和空文本)
|
|
6
|
+
* @param slot - 插槽函数
|
|
7
|
+
*/
|
|
8
|
+
export function hasSlotContent(slot: Slot | undefined | null): boolean {
|
|
9
|
+
if (!slot)
|
|
10
|
+
return false
|
|
11
|
+
const nodes = slot()
|
|
12
|
+
return nodes.some(isVNodeNotEmpty)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isVNodeNotEmpty(vnode: VNode): boolean {
|
|
16
|
+
if (vnode.type === Comment)
|
|
17
|
+
return false
|
|
18
|
+
if (vnode.type === Text) {
|
|
19
|
+
return typeof vnode.children === 'string' && vnode.children.trim().length > 0
|
|
20
|
+
}
|
|
21
|
+
if (vnode.type === Fragment) {
|
|
22
|
+
if (!Array.isArray(vnode.children))
|
|
23
|
+
return false
|
|
24
|
+
if (vnode.children.length === 0)
|
|
25
|
+
return false
|
|
26
|
+
return vnode.children.some(child => isVNodeNotEmpty(child as VNode))
|
|
27
|
+
}
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { ComputedRef } from 'vue'
|
|
2
|
+
import type { RouteRecordRaw } from 'vue-router'
|
|
3
|
+
import type { RouteMeta } from '../components/layout/types'
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
|
|
6
|
+
export interface RouteNode {
|
|
7
|
+
path: string
|
|
8
|
+
name?: string
|
|
9
|
+
meta?: RouteMeta
|
|
10
|
+
children?: RouteNode[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function joinPath(parent: string, p: string) {
|
|
14
|
+
const full = p?.startsWith('/') ? p : (parent ? `${parent}/${p}` : `/${p}`)
|
|
15
|
+
const single = full.replace(/\/+/g, '/')
|
|
16
|
+
return single.length > 1 && single.endsWith('/') ? single.slice(0, -1) : single
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function sortRaw(list: RouteRecordRaw[]): RouteRecordRaw[] {
|
|
20
|
+
const getOrder = (r: RouteRecordRaw) => {
|
|
21
|
+
const m = r.meta as RouteMeta | undefined
|
|
22
|
+
const o = m?.order
|
|
23
|
+
const v = typeof o === 'number' ? o : Number(o)
|
|
24
|
+
return Number.isFinite(v) ? v : Number.POSITIVE_INFINITY
|
|
25
|
+
}
|
|
26
|
+
const getTitle = (r: RouteRecordRaw) => {
|
|
27
|
+
const m = r.meta as RouteMeta | undefined
|
|
28
|
+
return String(m?.title ?? r.path.split('/').filter(Boolean).pop() ?? '')
|
|
29
|
+
}
|
|
30
|
+
return [...list].sort((a, b) => {
|
|
31
|
+
const oa = getOrder(a)
|
|
32
|
+
const ob = getOrder(b)
|
|
33
|
+
if (oa !== ob)
|
|
34
|
+
return oa - ob
|
|
35
|
+
return getTitle(a).localeCompare(getTitle(b))
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 标准化路由并自动生成重定向
|
|
41
|
+
*
|
|
42
|
+
* 递归处理路由树,拼接父子路径,并为包含子路由但未定义重定向的父路由自动生成指向第一个子路由的重定向。
|
|
43
|
+
*
|
|
44
|
+
* @param raw - 原始路由配置数组
|
|
45
|
+
* @param parent - 父级路径,用于递归拼接完整路径
|
|
46
|
+
* @returns 标准化后的路由数组,包含完整路径和自动生成的 redirect
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* - 会自动拼接父级路径,确保 path 为绝对路径
|
|
50
|
+
* - 如果父路由没有 redirect 且有子路由,会自动将 redirect 设置为第一个子路由(优先 index 或空路径)
|
|
51
|
+
*/
|
|
52
|
+
export function normalizeAndRedirect(raw: RouteRecordRaw[], parent = ''): RouteRecordRaw[] {
|
|
53
|
+
const childrenSorted = sortRaw(raw)
|
|
54
|
+
return childrenSorted.map((r): RouteRecordRaw => {
|
|
55
|
+
const curPathAbs = joinPath(parent, r.path)
|
|
56
|
+
const kidsRaw = Array.isArray(r.children) ? (r.children as RouteRecordRaw[]) : []
|
|
57
|
+
const kids = kidsRaw.length ? normalizeAndRedirect(kidsRaw, curPathAbs) : undefined
|
|
58
|
+
let redirect = r.redirect as string | undefined
|
|
59
|
+
if (!redirect && kids && kids.length) {
|
|
60
|
+
const idx = kids.find(c => c.path === 'index' || c.path === '')
|
|
61
|
+
const target = idx ?? kids[0]
|
|
62
|
+
if (target) {
|
|
63
|
+
redirect = joinPath(curPathAbs, target.path)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
...r,
|
|
68
|
+
...(kids ? { children: kids } : {}),
|
|
69
|
+
...(redirect ? { redirect } : {})
|
|
70
|
+
} as RouteRecordRaw
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 将路由配置转换为简化的路由树结构
|
|
76
|
+
*
|
|
77
|
+
* 过滤掉 hideMenu 的路由,并提取用于菜单或导航展示的关键信息。
|
|
78
|
+
*
|
|
79
|
+
* @param raw - 原始路由配置数组
|
|
80
|
+
* @param parent - 父级路径
|
|
81
|
+
* @returns 简化后的路由节点树
|
|
82
|
+
*/
|
|
83
|
+
export function toRouteTree(raw: RouteRecordRaw[], parent = ''): RouteNode[] {
|
|
84
|
+
return raw
|
|
85
|
+
.filter(r => (r.meta as RouteMeta | undefined)?.hideMenu !== true)
|
|
86
|
+
.map<RouteNode>((r) => {
|
|
87
|
+
const meta = r.meta ? { ...(r.meta as RouteMeta) } : undefined
|
|
88
|
+
const abs = joinPath(parent, r.path)
|
|
89
|
+
const children = Array.isArray(r.children) ? toRouteTree(r.children as RouteRecordRaw[], abs) : []
|
|
90
|
+
return { path: abs, name: r.name as string | undefined, meta, children }
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 对路由树进行排序
|
|
96
|
+
*
|
|
97
|
+
* 根据 meta.order (数字) 升序排序,若 order 相同则按 title 或路径名进行字母顺序排序。
|
|
98
|
+
*
|
|
99
|
+
* @param tree - 路由节点树
|
|
100
|
+
* @returns 排序后的新路由树
|
|
101
|
+
*/
|
|
102
|
+
export function sortRouteTree(tree: RouteNode[]): RouteNode[] {
|
|
103
|
+
const sorted = [...tree].sort((a, b) => {
|
|
104
|
+
const oa = typeof a.meta?.order === 'number' ? (a.meta?.order as number) : Number(a.meta?.order)
|
|
105
|
+
const ob = typeof b.meta?.order === 'number' ? (b.meta?.order as number) : Number(b.meta?.order)
|
|
106
|
+
const av = Number.isFinite(oa) ? oa : Number.POSITIVE_INFINITY
|
|
107
|
+
const bv = Number.isFinite(ob) ? ob : Number.POSITIVE_INFINITY
|
|
108
|
+
if (av !== bv)
|
|
109
|
+
return av - bv
|
|
110
|
+
const at = String(a.meta?.title ?? a.path.split('/').filter(Boolean).pop() ?? '')
|
|
111
|
+
const bt = String(b.meta?.title ?? b.path.split('/').filter(Boolean).pop() ?? '')
|
|
112
|
+
return at.localeCompare(bt)
|
|
113
|
+
})
|
|
114
|
+
return sorted.map(n => ({
|
|
115
|
+
...n,
|
|
116
|
+
children: n.children ? sortRouteTree(n.children) : []
|
|
117
|
+
}))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 过滤路由树
|
|
122
|
+
*
|
|
123
|
+
* 移除在 excludePaths 列表中的路径及其子路径。
|
|
124
|
+
*
|
|
125
|
+
* @param tree - 路由节点树
|
|
126
|
+
* @param excludePaths - 需要排除的路径列表(支持 glob 风格匹配逻辑的简化版,即前缀匹配)
|
|
127
|
+
* @returns 过滤后的新路由树
|
|
128
|
+
*/
|
|
129
|
+
export function filterRouteTree(tree: RouteNode[], excludePaths: string[] = []): RouteNode[] {
|
|
130
|
+
const norm = (p: string) => {
|
|
131
|
+
const s = p.startsWith('/') ? p : `/${p}`
|
|
132
|
+
const single = s.replace(/\/+/g, '/')
|
|
133
|
+
return single.length > 1 && single.endsWith('/') ? single.slice(0, -1) : single
|
|
134
|
+
}
|
|
135
|
+
const excludes = excludePaths.map(norm)
|
|
136
|
+
const match = (p: string) => {
|
|
137
|
+
const np = norm(p)
|
|
138
|
+
return excludes.some(ex => np === ex || np.startsWith(`${ex}/`))
|
|
139
|
+
}
|
|
140
|
+
return tree
|
|
141
|
+
.filter(n => !match(n.path))
|
|
142
|
+
.map(n => ({
|
|
143
|
+
...n,
|
|
144
|
+
children: n.children ? filterRouteTree(n.children, excludePaths) : []
|
|
145
|
+
}))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 从原始路由配置生成可用的路由树(Composition API 钩子)
|
|
150
|
+
*
|
|
151
|
+
* 组合了标准化、转换树形结构、排序和过滤等步骤,返回一个计算属性。
|
|
152
|
+
*
|
|
153
|
+
* @param raw - 原始路由配置数组
|
|
154
|
+
* @param option - 配置选项
|
|
155
|
+
* @param option.excludePaths - 需要排除的路径列表
|
|
156
|
+
* @returns 包含响应式路由树的对象
|
|
157
|
+
*/
|
|
158
|
+
export function useRoutesTreeFromRaw(raw: RouteRecordRaw[], option?: { excludePaths?: string[] }): { routesTree: ComputedRef<RouteNode[]> } {
|
|
159
|
+
const normalized = normalizeAndRedirect(raw)
|
|
160
|
+
const baseTree = toRouteTree(normalized)
|
|
161
|
+
const routesTree = computed(() => sortRouteTree(filterRouteTree(baseTree, option?.excludePaths ?? [])))
|
|
162
|
+
return { routesTree }
|
|
163
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 递归遍历树结构,将节点的 children 字段为空数组时改为 null。
|
|
3
|
+
* @param arr 树节点数组
|
|
4
|
+
* @returns 处理后的新数组(不修改入参引用)
|
|
5
|
+
*/
|
|
6
|
+
export function convertEmptyChildrenToNull<T extends Record<string, any>>(arr: T[]): T[] {
|
|
7
|
+
if (!Array.isArray(arr))
|
|
8
|
+
return []
|
|
9
|
+
|
|
10
|
+
return arr.map((item) => {
|
|
11
|
+
if (!item || typeof item !== 'object')
|
|
12
|
+
return item
|
|
13
|
+
|
|
14
|
+
const children = (item as any).children
|
|
15
|
+
|
|
16
|
+
if (!Array.isArray(children))
|
|
17
|
+
return item
|
|
18
|
+
|
|
19
|
+
if (children.length === 0) {
|
|
20
|
+
return {
|
|
21
|
+
...item,
|
|
22
|
+
children: null
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
...item,
|
|
28
|
+
children: convertEmptyChildrenToNull(children as any[])
|
|
29
|
+
} as T
|
|
30
|
+
})
|
|
31
|
+
}
|