@xmszm/core 0.0.1 → 0.0.3
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 +187 -0
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +1431 -1170
- package/dist/plugin/vite/initRouteMeta.cjs +1 -0
- package/dist/plugin/vite/initRouteMeta.mjs +13 -0
- package/dist/style.css +1 -1
- package/docs/.vitepress/config.mjs +91 -0
- package/docs/components/config-options.md +125 -0
- package/docs/components/dataform.md +176 -23
- package/docs/components/datatable.md +58 -39
- package/docs/components/dialog.md +158 -19
- package/docs/components/options.md +44 -15
- package/docs/components/query.md +68 -14
- package/docs/components/utils.md +124 -16
- package/docs/guide/changelog.md +81 -0
- package/docs/guide/config.md +415 -0
- package/docs/guide/demo.md +2 -2
- package/docs/guide/local-development.md +109 -0
- package/docs/guide/quickstart.md +40 -11
- package/docs/index.md +3 -3
- package/docs/usage.md +30 -6
- package/examples/README.md +46 -0
- package/examples/index.html +14 -0
- package/examples/package.json +25 -0
- package/examples/pnpm-lock.yaml +1569 -0
- package/examples/pnpm-workspace.yaml +3 -0
- package/examples/src/AdminSystem.vue +870 -0
- package/examples/src/App.vue +330 -0
- package/examples/src/Introduction.vue +307 -0
- package/examples/src/main.js +22 -0
- package/examples/src/utils/permission.js +16 -0
- package/examples/src/utils/request.js +10 -0
- package/examples/vite.config.js +41 -0
- package/package.json +13 -4
- package/src/dialog/commonDialog.tsx +285 -0
- package/src/dialog/useCommonDialog.ts +41 -0
- package/src/dialog/utils/{dialog.js → dialog.ts} +2 -0
- package/src/directives/auto-register.ts +57 -0
- package/src/directives/permission.ts +67 -0
- package/src/enum/sort.tsx +45 -0
- package/src/form/DataForm.vue +34 -52
- package/src/index.ts +58 -0
- package/src/list/{useList.jsx → useList.tsx} +49 -14
- package/src/options/{Options.jsx → Options.tsx} +86 -72
- package/src/options/defaultOptions.tsx +656 -0
- package/src/plugin/index.ts +20 -0
- package/src/query/CommonQuery.vue +65 -90
- package/src/table/DataTable.vue +82 -95
- package/src/table/opr/{DataColumnCollet.jsx → DataColumnCollet.tsx} +18 -8
- package/src/table/opr/useDataColumn.tsx +226 -0
- package/src/table/opr/{useDataColumnButton.jsx → useDataColumnButton.tsx} +13 -6
- package/src/table/opr/{useDataColumnPop.jsx → useDataColumnPop.tsx} +13 -5
- package/src/table/opr/useQRCode.ts +40 -0
- package/src/utils/{array.js → array.ts} +4 -6
- package/src/utils/config.ts +192 -0
- package/src/utils/dialog.ts +110 -0
- package/src/utils/{object.js → object.ts} +1 -0
- package/src/utils/upload.ts +53 -0
- package/types/auto-imports.d.ts +78 -0
- package/types/components.d.ts +402 -0
- package/types/index.d.ts +145 -7
- package/types/plugin/vite/initRouteMeta.d.ts +23 -0
- package/types/src.d.ts +55 -0
- package/types/vue-shim.d.ts +9 -0
- package/examples/demo.vue +0 -224
- package/src/dialog/commonDialog.jsx +0 -230
- package/src/enum/sort.jsx +0 -31
- package/src/index.js +0 -46
- package/src/options/defaultOptions.jsx +0 -580
- package/src/table/opr/useDataColumn.jsx +0 -196
- package/src/utils/upload.js +0 -46
- /package/src/enum/{options.js → options.ts} +0 -0
- /package/src/plugin/vite/{initRouteMeta.js → initRouteMeta.ts} +0 -0
- /package/src/store/utils/{index.js → index.ts} +0 -0
- /package/src/table/utils/{ellipsis.js → ellipsis.ts} +0 -0
- /package/src/utils/{auth.js → auth.ts} +0 -0
- /package/src/utils/{time.js → time.ts} +0 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { checkPermission } from '../../utils/config'
|
|
2
|
+
import { NButton, NImage, NSpace, NSpin } from 'naive-ui'
|
|
3
|
+
import { ref, type VNode } from 'vue'
|
|
4
|
+
import type { ActionOption, TableColumn } from '../../../types/components'
|
|
5
|
+
import DataColumnCollet from './DataColumnCollet'
|
|
6
|
+
import OprButton from './useDataColumnButton'
|
|
7
|
+
import Pop from './useDataColumnPop'
|
|
8
|
+
import { createDialogOptions } from '../../utils/dialog'
|
|
9
|
+
import { getDialogInstance } from '../../utils/dialog'
|
|
10
|
+
|
|
11
|
+
export const rowIndexKey = (row: any, index: number): string =>
|
|
12
|
+
row ? JSON.stringify(row) : String(index)
|
|
13
|
+
|
|
14
|
+
interface CollectParams {
|
|
15
|
+
max: number
|
|
16
|
+
width: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createActionColumnJsx(
|
|
20
|
+
defaultOption: ActionOption[],
|
|
21
|
+
oprParams: Record<string, any> | null = null,
|
|
22
|
+
collectParams?: boolean | CollectParams,
|
|
23
|
+
): TableColumn | undefined {
|
|
24
|
+
// 粗滤计算操作栏占用宽度
|
|
25
|
+
const defaultCollectParams: CollectParams = {
|
|
26
|
+
max: 4,
|
|
27
|
+
width: 80,
|
|
28
|
+
}
|
|
29
|
+
let collect: CollectParams | false = false
|
|
30
|
+
if (typeof collectParams === 'boolean')
|
|
31
|
+
collect = defaultCollectParams
|
|
32
|
+
else if (typeof collectParams === 'object')
|
|
33
|
+
collect = { ...defaultCollectParams, ...collectParams }
|
|
34
|
+
|
|
35
|
+
console.log('collect', collect)
|
|
36
|
+
console.log(Array.isArray(defaultOption))
|
|
37
|
+
if (!Array.isArray(defaultOption)) {
|
|
38
|
+
throw new TypeError('需要配置数组')
|
|
39
|
+
}
|
|
40
|
+
console.log('ddd')
|
|
41
|
+
let actions: ActionOption[] = []
|
|
42
|
+
let width = 0
|
|
43
|
+
const filterAction: ActionOption[] = []
|
|
44
|
+
const isLoading = false
|
|
45
|
+
|
|
46
|
+
if (Array.isArray(defaultOption)) {
|
|
47
|
+
actions = defaultOption
|
|
48
|
+
actions.forEach((itm, idx) => {
|
|
49
|
+
if (itm.permission) {
|
|
50
|
+
if (checkPermission(itm.permission)) {
|
|
51
|
+
if (!collectParams || (typeof collect === 'object' && idx < collect.max))
|
|
52
|
+
width += (typeof itm?.label === 'string' ? itm?.label?.length : 10) * 12 + 36
|
|
53
|
+
|
|
54
|
+
filterAction.push(itm)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
if (!collectParams || (typeof collect === 'object' && idx < collect.max))
|
|
59
|
+
width += (typeof itm?.label === 'string' ? itm?.label?.length : 10) * 12 + 36
|
|
60
|
+
filterAction.push(itm)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
width = Math.max(80, width)
|
|
66
|
+
width += isLoading ? 20 : 0
|
|
67
|
+
|
|
68
|
+
if (collect)
|
|
69
|
+
width += 2
|
|
70
|
+
|
|
71
|
+
return filterAction.length
|
|
72
|
+
? {
|
|
73
|
+
title: '操作',
|
|
74
|
+
key: 'opr',
|
|
75
|
+
fixed: 'right',
|
|
76
|
+
align: 'left',
|
|
77
|
+
width,
|
|
78
|
+
...oprParams,
|
|
79
|
+
render(row: any, index: number): VNode {
|
|
80
|
+
const vNodes = collect
|
|
81
|
+
? (
|
|
82
|
+
<DataColumnCollet
|
|
83
|
+
data={row}
|
|
84
|
+
index={index}
|
|
85
|
+
max={collect.max}
|
|
86
|
+
options={filterAction}
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
: (
|
|
90
|
+
filterAction
|
|
91
|
+
.map(
|
|
92
|
+
(
|
|
93
|
+
{
|
|
94
|
+
isRender = () => true,
|
|
95
|
+
onClick = null,
|
|
96
|
+
mode = null,
|
|
97
|
+
disabled = false,
|
|
98
|
+
type = 'primary',
|
|
99
|
+
...action
|
|
100
|
+
},
|
|
101
|
+
i,
|
|
102
|
+
) => {
|
|
103
|
+
return (typeof isRender === 'function' ? isRender(row) : isRender)
|
|
104
|
+
? (
|
|
105
|
+
mode === 'pop'
|
|
106
|
+
? (
|
|
107
|
+
<Pop
|
|
108
|
+
onClick={onClick}
|
|
109
|
+
row={row}
|
|
110
|
+
index={index}
|
|
111
|
+
action={action}
|
|
112
|
+
key={rowIndexKey(row, index) + i}
|
|
113
|
+
>
|
|
114
|
+
<NButton
|
|
115
|
+
text
|
|
116
|
+
disabled={typeof disabled === 'function' ? disabled(row) : disabled}
|
|
117
|
+
type={typeof disabled === 'function' && disabled(row) ? 'default' : type}
|
|
118
|
+
{...action}
|
|
119
|
+
>
|
|
120
|
+
{typeof action?.label === 'function'
|
|
121
|
+
? action?.label(row)
|
|
122
|
+
: action?.label}
|
|
123
|
+
</NButton>
|
|
124
|
+
</Pop>
|
|
125
|
+
)
|
|
126
|
+
: (
|
|
127
|
+
<OprButton
|
|
128
|
+
row={row}
|
|
129
|
+
action={{
|
|
130
|
+
...action,
|
|
131
|
+
disabled,
|
|
132
|
+
onClick,
|
|
133
|
+
type,
|
|
134
|
+
}}
|
|
135
|
+
index={index}
|
|
136
|
+
key={rowIndexKey(row, index) + i}
|
|
137
|
+
/>
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
: undefined
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
.filter((v): v is VNode => v !== undefined)
|
|
144
|
+
)
|
|
145
|
+
return (oprParams as any)?.isRender
|
|
146
|
+
? (
|
|
147
|
+
(oprParams as any)?.render(row)
|
|
148
|
+
)
|
|
149
|
+
: (
|
|
150
|
+
<NSpace
|
|
151
|
+
align="center"
|
|
152
|
+
wrap-item={false}
|
|
153
|
+
size={18}
|
|
154
|
+
key={rowIndexKey(row, index)}
|
|
155
|
+
>
|
|
156
|
+
{vNodes}
|
|
157
|
+
</NSpace>
|
|
158
|
+
)
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
: undefined
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 创建二维码弹窗
|
|
166
|
+
* @param row - 行数据
|
|
167
|
+
* @param fn - 获取二维码的函数
|
|
168
|
+
* @returns Promise<boolean>
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* import { useQRCode } from '@xmszm/core'
|
|
172
|
+
*
|
|
173
|
+
* export default defineComponent({
|
|
174
|
+
* setup() {
|
|
175
|
+
* const showQR = useQRCode()
|
|
176
|
+
*
|
|
177
|
+
* const handleShowQR = (row) => {
|
|
178
|
+
* showQR(row, async () => {
|
|
179
|
+
* return await getQRCode(row.id)
|
|
180
|
+
* })
|
|
181
|
+
* }
|
|
182
|
+
*
|
|
183
|
+
* return { handleShowQR }
|
|
184
|
+
* }
|
|
185
|
+
* })
|
|
186
|
+
*/
|
|
187
|
+
export async function createQRCode(
|
|
188
|
+
row: any,
|
|
189
|
+
fn: (() => Promise<string> | string) | null = null,
|
|
190
|
+
): Promise<boolean> {
|
|
191
|
+
const dialogInstance = getDialogInstance()
|
|
192
|
+
|
|
193
|
+
if (!dialogInstance) {
|
|
194
|
+
throw new Error('无法获取 dialog 实例。请使用 useQRCode hook 或在组件中通过 setupConfig 注册 dialog 实例。')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const code = ref<string | null>(null)
|
|
198
|
+
const loading = ref(false)
|
|
199
|
+
|
|
200
|
+
const dialogOptions = createDialogOptions({
|
|
201
|
+
type: 'info',
|
|
202
|
+
showIcon: false,
|
|
203
|
+
style: {
|
|
204
|
+
width: '350px',
|
|
205
|
+
height: '350px',
|
|
206
|
+
},
|
|
207
|
+
content: () => (
|
|
208
|
+
<div class="qr-box">
|
|
209
|
+
{loading.value ? <NSpin class="qr-spin" show /> : ''}
|
|
210
|
+
<div class="qr-img">
|
|
211
|
+
<NImage src={code.value} style={{ width: '100%' }} />
|
|
212
|
+
</div>
|
|
213
|
+
<div class="qr-title">{loading.value ? '' : row.name}</div>
|
|
214
|
+
</div>
|
|
215
|
+
),
|
|
216
|
+
}, dialogInstance)
|
|
217
|
+
|
|
218
|
+
dialogInstance.info(dialogOptions)
|
|
219
|
+
|
|
220
|
+
if (fn) {
|
|
221
|
+
loading.value = true
|
|
222
|
+
code.value = await fn()
|
|
223
|
+
loading.value = false
|
|
224
|
+
}
|
|
225
|
+
return true
|
|
226
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { NButton } from 'naive-ui'
|
|
2
|
-
import { defineComponent, ref } from 'vue'
|
|
2
|
+
import { defineComponent, ref, type VNode } from 'vue'
|
|
3
|
+
import type { ActionOption } from '../../../types/components'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
action: ActionOption | null
|
|
7
|
+
row: any
|
|
8
|
+
index: number
|
|
9
|
+
}
|
|
3
10
|
|
|
4
11
|
export default defineComponent(
|
|
5
|
-
({ action, row,index }) => {
|
|
12
|
+
({ action, row, index }: Props) => {
|
|
6
13
|
const {
|
|
7
14
|
onClick,
|
|
8
15
|
disabled,
|
|
@@ -10,7 +17,7 @@ export default defineComponent(
|
|
|
10
17
|
loading = false,
|
|
11
18
|
label = null,
|
|
12
19
|
...other
|
|
13
|
-
} = action
|
|
20
|
+
} = action || {}
|
|
14
21
|
const oprBtnLoading = ref(false)
|
|
15
22
|
return () => (
|
|
16
23
|
<NButton
|
|
@@ -21,16 +28,16 @@ export default defineComponent(
|
|
|
21
28
|
if (loading) {
|
|
22
29
|
oprBtnLoading.value = true
|
|
23
30
|
}
|
|
24
|
-
await onClick(row
|
|
31
|
+
await onClick(row)
|
|
25
32
|
}
|
|
26
33
|
finally {
|
|
27
34
|
setTimeout(() => (oprBtnLoading.value = false), 500)
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
37
|
}}
|
|
31
|
-
disabled={disabled
|
|
38
|
+
disabled={typeof disabled === 'function' ? disabled(row) : disabled}
|
|
32
39
|
loading={oprBtnLoading.value}
|
|
33
|
-
type={disabled && disabled(row) ? 'default' : type}
|
|
40
|
+
type={typeof disabled === 'function' && disabled(row) ? 'default' : type}
|
|
34
41
|
{...other}
|
|
35
42
|
>
|
|
36
43
|
{typeof label === 'function' ? label?.(row) : label}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { NPopconfirm } from 'naive-ui'
|
|
2
|
-
import { defineComponent, ref } from 'vue'
|
|
2
|
+
import { defineComponent, ref, type VNode } from 'vue'
|
|
3
|
+
import type { ActionOption } from '../../../types/components'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
onClick: ((row: any, index: number) => void | Promise<void>) | null
|
|
7
|
+
row: any
|
|
8
|
+
index: number
|
|
9
|
+
action: ActionOption | null
|
|
10
|
+
}
|
|
3
11
|
|
|
4
12
|
export default defineComponent(
|
|
5
|
-
({ onClick, row, index,action }, { slots }) => {
|
|
13
|
+
({ onClick, row, index, action }: Props, { slots }) => {
|
|
6
14
|
const popLoading = ref(false)
|
|
7
15
|
return () => (
|
|
8
16
|
<NPopconfirm
|
|
@@ -14,7 +22,7 @@ export default defineComponent(
|
|
|
14
22
|
try {
|
|
15
23
|
if (onClick) {
|
|
16
24
|
popLoading.value = true
|
|
17
|
-
await onClick(row,index)
|
|
25
|
+
await onClick(row, index)
|
|
18
26
|
popLoading.value = false
|
|
19
27
|
return true
|
|
20
28
|
}
|
|
@@ -29,7 +37,7 @@ export default defineComponent(
|
|
|
29
37
|
{{
|
|
30
38
|
trigger: slots.default,
|
|
31
39
|
default: () =>
|
|
32
|
-
action?.popProps?.content || action?.content || '确定删除该记录?',
|
|
40
|
+
action?.popProps?.content || (action as any)?.content || '确定删除该记录?',
|
|
33
41
|
}}
|
|
34
42
|
</NPopconfirm>
|
|
35
43
|
)
|
|
@@ -37,7 +45,7 @@ export default defineComponent(
|
|
|
37
45
|
{
|
|
38
46
|
props: {
|
|
39
47
|
onClick: {
|
|
40
|
-
type:
|
|
48
|
+
type: Function as any,
|
|
41
49
|
default: null,
|
|
42
50
|
},
|
|
43
51
|
row: {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useQRCode Hook
|
|
3
|
+
* 在组件中使用 createQRCode 的便捷方式
|
|
4
|
+
*/
|
|
5
|
+
import { useDialog } from 'naive-ui'
|
|
6
|
+
import { createQRCode } from './useDataColumn'
|
|
7
|
+
import { registerDialogInstance } from '../../utils/config'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 使用 QRCode 的 Hook
|
|
11
|
+
* @returns {Function} showQRCode 函数
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* import { useQRCode } from '@xmszm/core'
|
|
15
|
+
*
|
|
16
|
+
* export default defineComponent({
|
|
17
|
+
* setup() {
|
|
18
|
+
* const showQRCode = useQRCode()
|
|
19
|
+
*
|
|
20
|
+
* const handleShowQR = (row) => {
|
|
21
|
+
* showQRCode(row, async () => {
|
|
22
|
+
* return await getQRCode(row.id)
|
|
23
|
+
* })
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* return { handleShowQR }
|
|
27
|
+
* }
|
|
28
|
+
* })
|
|
29
|
+
*/
|
|
30
|
+
export function useQRCode() {
|
|
31
|
+
const dialog = useDialog()
|
|
32
|
+
|
|
33
|
+
// 注册 dialog 实例到全局配置
|
|
34
|
+
registerDialogInstance(dialog)
|
|
35
|
+
|
|
36
|
+
return (row, fn) => {
|
|
37
|
+
return createQRCode(row, fn)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
@@ -5,11 +5,9 @@ import {
|
|
|
5
5
|
} from '../enum/options'
|
|
6
6
|
|
|
7
7
|
export function ArrayToObject(
|
|
8
|
-
arr = [],
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
valueField: globalValueField,
|
|
12
|
-
},
|
|
8
|
+
arr: any[] = [],
|
|
9
|
+
labelField: string = globalLabelField,
|
|
10
|
+
valueField: string = globalValueField,
|
|
13
11
|
) {
|
|
14
12
|
return unref(arr).reduce((o, n) => {
|
|
15
13
|
o[n[valueField]] = {
|
|
@@ -21,6 +19,6 @@ export function ArrayToObject(
|
|
|
21
19
|
}, {})
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
export function toArray(v) {
|
|
22
|
+
export function toArray(v: any) {
|
|
25
23
|
return Array.isArray(v) ? v : [v]
|
|
26
24
|
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 全局配置系统
|
|
3
|
+
* 用于统一管理库的外部依赖配置
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 配置对象类型定义
|
|
8
|
+
*/
|
|
9
|
+
interface ConfigType {
|
|
10
|
+
baseURL: string
|
|
11
|
+
hasPermission: ((permission: string) => boolean) | null
|
|
12
|
+
uploadMethod: ((config: any) => Promise<any>) | null
|
|
13
|
+
dialog: {
|
|
14
|
+
instance: any
|
|
15
|
+
inheritTheme: boolean
|
|
16
|
+
themeOverrides: any
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 配置对象
|
|
22
|
+
*/
|
|
23
|
+
const config: ConfigType = {
|
|
24
|
+
// API 基础地址
|
|
25
|
+
baseURL: '',
|
|
26
|
+
|
|
27
|
+
// 权限检查函数
|
|
28
|
+
hasPermission: null,
|
|
29
|
+
|
|
30
|
+
// 上传方法
|
|
31
|
+
uploadMethod: null,
|
|
32
|
+
|
|
33
|
+
// Dialog 配置
|
|
34
|
+
dialog: {
|
|
35
|
+
// Dialog 实例(可通过 setupConfig 注册,或内部自动获取)
|
|
36
|
+
instance: null,
|
|
37
|
+
// 是否继承外部定义的主题色(默认 true)
|
|
38
|
+
inheritTheme: true,
|
|
39
|
+
// 主题色覆盖(当 inheritTheme 为 false 时使用)
|
|
40
|
+
themeOverrides: null,
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 初始化配置
|
|
46
|
+
* @param {Object} options - 配置选项
|
|
47
|
+
* @param {string} [options.baseURL] - API 基础地址
|
|
48
|
+
* @param {Function} [options.hasPermission] - 权限检查函数 (permission: string) => boolean
|
|
49
|
+
* @param {Function} [options.uploadMethod] - 上传方法 (config: AxiosRequestConfig) => Promise
|
|
50
|
+
* @param {Object} [options.dialog] - Dialog 配置
|
|
51
|
+
* @param {boolean} [options.dialog.inheritTheme] - 是否继承外部定义的主题色(默认 true)
|
|
52
|
+
* @param {Object} [options.dialog.themeOverrides] - 主题色覆盖(当 inheritTheme 为 false 时使用)
|
|
53
|
+
* @example
|
|
54
|
+
* import { setupConfig } from '@xmszm/core'
|
|
55
|
+
*
|
|
56
|
+
* setupConfig({
|
|
57
|
+
* baseURL: 'https://api.example.com',
|
|
58
|
+
* hasPermission: (permission) => {
|
|
59
|
+
* const permissions = getPermissions() // 你的权限获取逻辑
|
|
60
|
+
* return permissions.includes(permission)
|
|
61
|
+
* },
|
|
62
|
+
* uploadMethod: (config) => axios.request(config),
|
|
63
|
+
* dialog: {
|
|
64
|
+
* inheritTheme: false, // 不继承外部主题色
|
|
65
|
+
* themeOverrides: {
|
|
66
|
+
* // 自定义主题色
|
|
67
|
+
* }
|
|
68
|
+
* }
|
|
69
|
+
* })
|
|
70
|
+
*/
|
|
71
|
+
export function setupConfig(options: Partial<ConfigType> = {}) {
|
|
72
|
+
if (options.baseURL !== undefined) {
|
|
73
|
+
config.baseURL = options.baseURL
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (options.hasPermission !== undefined) {
|
|
77
|
+
if (typeof options.hasPermission !== 'function') {
|
|
78
|
+
throw new TypeError('hasPermission 必须是一个函数')
|
|
79
|
+
}
|
|
80
|
+
config.hasPermission = options.hasPermission
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (options.uploadMethod !== undefined) {
|
|
84
|
+
if (typeof options.uploadMethod !== 'function') {
|
|
85
|
+
throw new TypeError('uploadMethod 必须是一个函数')
|
|
86
|
+
}
|
|
87
|
+
config.uploadMethod = options.uploadMethod
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (options.dialog !== undefined) {
|
|
91
|
+
if (typeof options.dialog !== 'object') {
|
|
92
|
+
throw new TypeError('dialog 必须是一个对象')
|
|
93
|
+
}
|
|
94
|
+
if (options.dialog.instance !== undefined) {
|
|
95
|
+
config.dialog.instance = options.dialog.instance
|
|
96
|
+
}
|
|
97
|
+
if (options.dialog.inheritTheme !== undefined) {
|
|
98
|
+
config.dialog.inheritTheme = options.dialog.inheritTheme
|
|
99
|
+
}
|
|
100
|
+
if (options.dialog.themeOverrides !== undefined) {
|
|
101
|
+
config.dialog.themeOverrides = options.dialog.themeOverrides
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return config
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 获取配置
|
|
110
|
+
* @returns {Object} 配置对象
|
|
111
|
+
*/
|
|
112
|
+
export function getConfig() {
|
|
113
|
+
return { ...config }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 获取 BASE_URL
|
|
118
|
+
* @returns {string}
|
|
119
|
+
*/
|
|
120
|
+
export function getBaseURL() {
|
|
121
|
+
return config.baseURL
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 获取权限检查函数
|
|
126
|
+
* @returns {Function|null}
|
|
127
|
+
*/
|
|
128
|
+
export function getHasPermission() {
|
|
129
|
+
return config.hasPermission
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 获取上传方法
|
|
134
|
+
* @returns {Function|null}
|
|
135
|
+
*/
|
|
136
|
+
export function getUploadMethod() {
|
|
137
|
+
return config.uploadMethod
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 获取 Dialog 配置
|
|
142
|
+
* @returns {Object}
|
|
143
|
+
*/
|
|
144
|
+
export function getDialogConfig() {
|
|
145
|
+
return { ...config.dialog }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 注册 Dialog 实例(可选,如果不注册则内部自动获取)
|
|
150
|
+
* @param {Object} dialogInstance - dialog 实例(从 useDialog 获取)
|
|
151
|
+
*/
|
|
152
|
+
export function registerDialogInstance(dialogInstance) {
|
|
153
|
+
config.dialog.instance = dialogInstance
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 获取 Dialog 实例
|
|
158
|
+
* @returns {Object|null}
|
|
159
|
+
*/
|
|
160
|
+
export function getDialogInstance() {
|
|
161
|
+
return config.dialog.instance
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 检查权限(带默认值)
|
|
166
|
+
* @param {string} permission - 权限标识
|
|
167
|
+
* @returns {boolean}
|
|
168
|
+
*/
|
|
169
|
+
export function checkPermission(permission) {
|
|
170
|
+
if (config.hasPermission) {
|
|
171
|
+
return config.hasPermission(permission)
|
|
172
|
+
}
|
|
173
|
+
// 默认返回 true,避免未配置时阻塞功能
|
|
174
|
+
console.warn('hasPermission 未配置,默认返回 true。请使用 setupConfig 配置权限检查函数。')
|
|
175
|
+
return true
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 兼容旧版 API(向后兼容)
|
|
179
|
+
// 注意:registryUpload 在 upload.js 中导出,这里不重复导出
|
|
180
|
+
|
|
181
|
+
export default {
|
|
182
|
+
setupConfig,
|
|
183
|
+
getConfig,
|
|
184
|
+
getBaseURL,
|
|
185
|
+
getHasPermission,
|
|
186
|
+
getUploadMethod,
|
|
187
|
+
checkPermission,
|
|
188
|
+
getDialogConfig,
|
|
189
|
+
registerDialogInstance,
|
|
190
|
+
getDialogInstance,
|
|
191
|
+
}
|
|
192
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog 工具函数
|
|
3
|
+
* 使用 useDialog 替代全局 $dialog
|
|
4
|
+
*/
|
|
5
|
+
import { getCurrentInstance } from 'vue'
|
|
6
|
+
import { useDialog } from 'naive-ui'
|
|
7
|
+
import { getDialogConfig, getDialogInstance as getRegisteredDialogInstance } from './config'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 获取 dialog 实例
|
|
11
|
+
* 优先从配置中获取(如果已注册),否则从当前组件实例获取
|
|
12
|
+
* @returns {Object|null} dialog 实例
|
|
13
|
+
*/
|
|
14
|
+
export function getDialogInstance() {
|
|
15
|
+
// 1. 优先从配置中获取(如果外部已注册)
|
|
16
|
+
const registered = getRegisteredDialogInstance()
|
|
17
|
+
if (registered) {
|
|
18
|
+
return registered
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 2. 尝试从当前组件实例获取
|
|
22
|
+
try {
|
|
23
|
+
const instance = getCurrentInstance()
|
|
24
|
+
if (instance?.appContext?.app) {
|
|
25
|
+
// 在组件上下文中,尝试通过 app 实例获取 dialog
|
|
26
|
+
// 注意:useDialog 必须在 setup 中调用,这里我们无法直接调用
|
|
27
|
+
// 所以需要通过其他方式获取
|
|
28
|
+
// 实际上,如果不在组件上下文中,这里会返回 null
|
|
29
|
+
// 建议在组件中使用 useCommonDialog hook,或通过 setupConfig 注册
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
} catch (e) {
|
|
33
|
+
// 忽略错误
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 创建 dialog 配置,应用主题色继承设置
|
|
41
|
+
* @param {Object} options - dialog 选项
|
|
42
|
+
* @param {Object} dialogInstance - dialog 实例(从 useDialog 获取)
|
|
43
|
+
* @returns {Object} 处理后的 dialog 选项
|
|
44
|
+
*/
|
|
45
|
+
export function createDialogOptions(options: Record<string, any> = {}, dialogInstance: any = null) {
|
|
46
|
+
const dialogConfig = getDialogConfig()
|
|
47
|
+
|
|
48
|
+
// 如果配置了不继承主题色,则添加 themeOverrides
|
|
49
|
+
if (!dialogConfig.inheritTheme && dialogConfig.themeOverrides) {
|
|
50
|
+
return {
|
|
51
|
+
...options,
|
|
52
|
+
themeOverrides: {
|
|
53
|
+
...dialogConfig.themeOverrides,
|
|
54
|
+
...(options.themeOverrides || {}),
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return options
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 使用 dialog 的工具函数
|
|
64
|
+
* 在组件中使用:const dialog = useDialog(); createDialog(dialog, options)
|
|
65
|
+
* @param {Object} dialogInstance - dialog 实例(从 useDialog 获取)
|
|
66
|
+
* @param {Object} options - dialog 选项
|
|
67
|
+
* @returns {Object} dialog 返回的对象
|
|
68
|
+
*/
|
|
69
|
+
export function createDialog(dialogInstance: any, options: Record<string, any> = {}) {
|
|
70
|
+
if (!dialogInstance) {
|
|
71
|
+
throw new Error('dialogInstance 是必需的。请在组件中使用 useDialog() 获取实例,然后传递给此函数。')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const finalOptions = createDialogOptions(options, dialogInstance)
|
|
75
|
+
return dialogInstance.create(finalOptions)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Dialog 快捷方法
|
|
80
|
+
* @param {Object} dialogInstance - dialog 实例
|
|
81
|
+
*/
|
|
82
|
+
export function createDialogMethods(dialogInstance) {
|
|
83
|
+
if (!dialogInstance) {
|
|
84
|
+
throw new Error('dialogInstance 是必需的。请在组件中使用 useDialog() 获取实例。')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
info: (options) => {
|
|
89
|
+
const finalOptions = createDialogOptions({ type: 'info', ...options }, dialogInstance)
|
|
90
|
+
return dialogInstance.info(finalOptions)
|
|
91
|
+
},
|
|
92
|
+
success: (options) => {
|
|
93
|
+
const finalOptions = createDialogOptions({ type: 'success', ...options }, dialogInstance)
|
|
94
|
+
return dialogInstance.success(finalOptions)
|
|
95
|
+
},
|
|
96
|
+
warning: (options) => {
|
|
97
|
+
const finalOptions = createDialogOptions({ type: 'warning', ...options }, dialogInstance)
|
|
98
|
+
return dialogInstance.warning(finalOptions)
|
|
99
|
+
},
|
|
100
|
+
error: (options) => {
|
|
101
|
+
const finalOptions = createDialogOptions({ type: 'error', ...options }, dialogInstance)
|
|
102
|
+
return dialogInstance.error(finalOptions)
|
|
103
|
+
},
|
|
104
|
+
create: (options) => {
|
|
105
|
+
const finalOptions = createDialogOptions(options, dialogInstance)
|
|
106
|
+
return dialogInstance.create(finalOptions)
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|