@xmszm/core 0.0.1 → 0.0.2

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.
@@ -1,9 +1,10 @@
1
- import { hasPermission } from '@/utils/permission'
1
+ import { checkPermission } from '../../utils/config'
2
2
  import { NButton, NImage, NSpace, NSpin } from 'naive-ui'
3
3
  import { ref } from 'vue'
4
4
  import DataColumnCollet from './DataColumnCollet.jsx'
5
5
  import OprButton from './useDataColumnButton.jsx'
6
6
  import Pop from './useDataColumnPop.jsx'
7
+ import { createDialogOptions } from '../../utils/dialog'
7
8
 
8
9
  export const rowIndexKey = (row, index) => (row ? JSON.stringify(row) : index)
9
10
 
@@ -39,7 +40,7 @@ export function createActionColumnJsx(
39
40
  actions = defaultOption
40
41
  actions.forEach((itm, idx) => {
41
42
  if (itm.permission) {
42
- if (hasPermission(itm.permission)) {
43
+ if (checkPermission(itm.permission)) {
43
44
  if (!collectParams || idx < collect.max)
44
45
  width += itm?.label?.length * 12 + 36
45
46
 
@@ -77,101 +78,132 @@ export function createActionColumnJsx(
77
78
 
78
79
  return filterAction.length
79
80
  ? {
80
- title: '操作',
81
- key: 'opr',
82
- fixed: 'right',
83
- align: 'left',
84
- width,
85
- ...oprParams,
86
- render(row, index) {
87
- const vNodes = collect
88
- ? (
89
- <DataColumnCollet
90
- data={row}
91
- index={index}
92
- max={collect.max}
93
- options={filterAction}
94
- />
95
- )
96
- : (
97
- filterAction
98
- .map(
99
- (
100
- {
101
- isRender = () => true,
102
- onClick = null,
103
- mode = null,
104
- disabled = false,
105
- type = 'primary',
106
- ...action
107
- },
108
- i,
109
- ) => {
110
- return isRender?.(row)
81
+ title: '操作',
82
+ key: 'opr',
83
+ fixed: 'right',
84
+ align: 'left',
85
+ width,
86
+ ...oprParams,
87
+ render(row, index) {
88
+ const vNodes = collect
89
+ ? (
90
+ <DataColumnCollet
91
+ data={row}
92
+ index={index}
93
+ max={collect.max}
94
+ options={filterAction}
95
+ />
96
+ )
97
+ : (
98
+ filterAction
99
+ .map(
100
+ (
101
+ {
102
+ isRender = () => true,
103
+ onClick = null,
104
+ mode = null,
105
+ disabled = false,
106
+ type = 'primary',
107
+ ...action
108
+ },
109
+ i,
110
+ ) => {
111
+ return isRender?.(row)
112
+ ? (
113
+ mode === 'pop'
111
114
  ? (
112
- mode === 'pop'
113
- ? (
114
- <Pop
115
- onClick={onClick}
116
- row={row}
117
- index={index}
118
- action={action}
119
- key={rowIndexKey(row, index) + i}
120
- >
121
- <NButton
122
- text
123
- disabled={disabled && disabled(row)}
124
- type={disabled && disabled(row) ? 'default' : type}
125
- {...action}
126
- >
127
- {typeof action?.label === 'function'
128
- ? action?.label(row)
129
- : action?.label}
130
- </NButton>
131
- </Pop>
132
- )
133
- : (
134
- <OprButton
135
- row={row}
136
- action={{
137
- ...action,
138
- disabled,
139
- onClick,
140
- type,
141
- }}
142
- index={index}
143
- key={rowIndexKey(row, index) + i}
144
- />
145
- )
146
- )
147
- : undefined
148
- },
149
- )
150
- .filter(v => v)
151
- )
152
- return oprParams?.isRender
153
- ? (
154
- oprParams?.render(row)
155
- )
156
- : (
157
- <NSpace
158
- align="center"
159
- wrap-item={false}
160
- size={18}
161
- key={rowIndexKey(row, index)}
162
- >
163
- {vNodes}
164
- </NSpace>
115
+ <Pop
116
+ onClick={onClick}
117
+ row={row}
118
+ index={index}
119
+ action={action}
120
+ key={rowIndexKey(row, index) + i}
121
+ >
122
+ <NButton
123
+ text
124
+ disabled={disabled && disabled(row)}
125
+ type={disabled && disabled(row) ? 'default' : type}
126
+ {...action}
127
+ >
128
+ {typeof action?.label === 'function'
129
+ ? action?.label(row)
130
+ : action?.label}
131
+ </NButton>
132
+ </Pop>
133
+ )
134
+ : (
135
+ <OprButton
136
+ row={row}
137
+ action={{
138
+ ...action,
139
+ disabled,
140
+ onClick,
141
+ type,
142
+ }}
143
+ index={index}
144
+ key={rowIndexKey(row, index) + i}
145
+ />
146
+ )
147
+ )
148
+ : undefined
149
+ },
165
150
  )
166
- },
167
- }
151
+ .filter(v => v)
152
+ )
153
+ return oprParams?.isRender
154
+ ? (
155
+ oprParams?.render(row)
156
+ )
157
+ : (
158
+ <NSpace
159
+ align="center"
160
+ wrap-item={false}
161
+ size={18}
162
+ key={rowIndexKey(row, index)}
163
+ >
164
+ {vNodes}
165
+ </NSpace>
166
+ )
167
+ },
168
+ }
168
169
  : undefined
169
170
  }
170
171
 
172
+ /**
173
+ * 创建二维码弹窗
174
+ * @param {Object} row - 行数据
175
+ * @param {Function} fn - 获取二维码的函数
176
+ * @returns {Promise<boolean>}
177
+ *
178
+ * @example
179
+ * import { useQRCode } from '@xmszm/core'
180
+ *
181
+ * export default defineComponent({
182
+ * setup() {
183
+ * const showQR = useQRCode()
184
+ *
185
+ * const handleShowQR = (row) => {
186
+ * showQR(row, async () => {
187
+ * return await getQRCode(row.id)
188
+ * })
189
+ * }
190
+ *
191
+ * return { handleShowQR }
192
+ * }
193
+ * })
194
+ */
171
195
  export async function createQRCode(row, fn = null) {
196
+ const dialogInstance = getDialogInstance()
197
+
198
+ if (!dialogInstance) {
199
+ throw new Error('无法获取 dialog 实例。请使用 useQRCode hook 或在组件中通过 setupConfig 注册 dialog 实例。')
200
+ }
201
+
172
202
  const code = ref(null)
173
203
  const loading = ref(false)
174
- $dialog.info({
204
+
205
+ const dialogOptions = createDialogOptions({
206
+ type: 'info',
175
207
  showIcon: false,
176
208
  style: {
177
209
  width: '350px',
@@ -186,7 +218,10 @@ export async function createQRCode(row, fn = null) {
186
218
  <div className="qr-title">{loading.value ? '' : row.name}</div>
187
219
  </div>
188
220
  ),
189
- })
221
+ }, dialogInstance)
222
+
223
+ dialogInstance.info(dialogOptions)
224
+
190
225
  if (fn) {
191
226
  loading.value = true
192
227
  code.value = await fn()
@@ -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
+
@@ -0,0 +1,178 @@
1
+ /**
2
+ * 全局配置系统
3
+ * 用于统一管理库的外部依赖配置
4
+ */
5
+
6
+ /**
7
+ * 配置对象
8
+ */
9
+ const config = {
10
+ // API 基础地址
11
+ baseURL: '',
12
+
13
+ // 权限检查函数
14
+ hasPermission: null,
15
+
16
+ // 上传方法
17
+ uploadMethod: null,
18
+
19
+ // Dialog 配置
20
+ dialog: {
21
+ // Dialog 实例(可通过 setupConfig 注册,或内部自动获取)
22
+ instance: null,
23
+ // 是否继承外部定义的主题色(默认 true)
24
+ inheritTheme: true,
25
+ // 主题色覆盖(当 inheritTheme 为 false 时使用)
26
+ themeOverrides: null,
27
+ },
28
+ }
29
+
30
+ /**
31
+ * 初始化配置
32
+ * @param {Object} options - 配置选项
33
+ * @param {string} [options.baseURL] - API 基础地址
34
+ * @param {Function} [options.hasPermission] - 权限检查函数 (permission: string) => boolean
35
+ * @param {Function} [options.uploadMethod] - 上传方法 (config: AxiosRequestConfig) => Promise
36
+ * @param {Object} [options.dialog] - Dialog 配置
37
+ * @param {boolean} [options.dialog.inheritTheme] - 是否继承外部定义的主题色(默认 true)
38
+ * @param {Object} [options.dialog.themeOverrides] - 主题色覆盖(当 inheritTheme 为 false 时使用)
39
+ * @example
40
+ * import { setupConfig } from '@xmszm/core'
41
+ *
42
+ * setupConfig({
43
+ * baseURL: 'https://api.example.com',
44
+ * hasPermission: (permission) => {
45
+ * const permissions = getPermissions() // 你的权限获取逻辑
46
+ * return permissions.includes(permission)
47
+ * },
48
+ * uploadMethod: (config) => axios.request(config),
49
+ * dialog: {
50
+ * inheritTheme: false, // 不继承外部主题色
51
+ * themeOverrides: {
52
+ * // 自定义主题色
53
+ * }
54
+ * }
55
+ * })
56
+ */
57
+ export function setupConfig(options = {}) {
58
+ if (options.baseURL !== undefined) {
59
+ config.baseURL = options.baseURL
60
+ }
61
+
62
+ if (options.hasPermission !== undefined) {
63
+ if (typeof options.hasPermission !== 'function') {
64
+ throw new TypeError('hasPermission 必须是一个函数')
65
+ }
66
+ config.hasPermission = options.hasPermission
67
+ }
68
+
69
+ if (options.uploadMethod !== undefined) {
70
+ if (typeof options.uploadMethod !== 'function') {
71
+ throw new TypeError('uploadMethod 必须是一个函数')
72
+ }
73
+ config.uploadMethod = options.uploadMethod
74
+ }
75
+
76
+ if (options.dialog !== undefined) {
77
+ if (typeof options.dialog !== 'object') {
78
+ throw new TypeError('dialog 必须是一个对象')
79
+ }
80
+ if (options.dialog.instance !== undefined) {
81
+ config.dialog.instance = options.dialog.instance
82
+ }
83
+ if (options.dialog.inheritTheme !== undefined) {
84
+ config.dialog.inheritTheme = options.dialog.inheritTheme
85
+ }
86
+ if (options.dialog.themeOverrides !== undefined) {
87
+ config.dialog.themeOverrides = options.dialog.themeOverrides
88
+ }
89
+ }
90
+
91
+ return config
92
+ }
93
+
94
+ /**
95
+ * 获取配置
96
+ * @returns {Object} 配置对象
97
+ */
98
+ export function getConfig() {
99
+ return { ...config }
100
+ }
101
+
102
+ /**
103
+ * 获取 BASE_URL
104
+ * @returns {string}
105
+ */
106
+ export function getBaseURL() {
107
+ return config.baseURL
108
+ }
109
+
110
+ /**
111
+ * 获取权限检查函数
112
+ * @returns {Function|null}
113
+ */
114
+ export function getHasPermission() {
115
+ return config.hasPermission
116
+ }
117
+
118
+ /**
119
+ * 获取上传方法
120
+ * @returns {Function|null}
121
+ */
122
+ export function getUploadMethod() {
123
+ return config.uploadMethod
124
+ }
125
+
126
+ /**
127
+ * 获取 Dialog 配置
128
+ * @returns {Object}
129
+ */
130
+ export function getDialogConfig() {
131
+ return { ...config.dialog }
132
+ }
133
+
134
+ /**
135
+ * 注册 Dialog 实例(可选,如果不注册则内部自动获取)
136
+ * @param {Object} dialogInstance - dialog 实例(从 useDialog 获取)
137
+ */
138
+ export function registerDialogInstance(dialogInstance) {
139
+ config.dialog.instance = dialogInstance
140
+ }
141
+
142
+ /**
143
+ * 获取 Dialog 实例
144
+ * @returns {Object|null}
145
+ */
146
+ export function getDialogInstance() {
147
+ return config.dialog.instance
148
+ }
149
+
150
+ /**
151
+ * 检查权限(带默认值)
152
+ * @param {string} permission - 权限标识
153
+ * @returns {boolean}
154
+ */
155
+ export function checkPermission(permission) {
156
+ if (config.hasPermission) {
157
+ return config.hasPermission(permission)
158
+ }
159
+ // 默认返回 true,避免未配置时阻塞功能
160
+ console.warn('hasPermission 未配置,默认返回 true。请使用 setupConfig 配置权限检查函数。')
161
+ return true
162
+ }
163
+
164
+ // 兼容旧版 API(向后兼容)
165
+ // 注意:registryUpload 在 upload.js 中导出,这里不重复导出
166
+
167
+ export default {
168
+ setupConfig,
169
+ getConfig,
170
+ getBaseURL,
171
+ getHasPermission,
172
+ getUploadMethod,
173
+ checkPermission,
174
+ getDialogConfig,
175
+ registerDialogInstance,
176
+ getDialogInstance,
177
+ }
178
+
@@ -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 = {}, dialogInstance = 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, options = {}) {
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
+
@@ -7,20 +7,15 @@
7
7
  * @typedef {Promise<import('axios').AxiosResponse<UploadData>>} UploadDataPromise
8
8
  */
9
9
 
10
- import { BASE_URL } from '@/utils/request'
10
+ import { getBaseURL, getUploadMethod, setupConfig } from './config'
11
11
 
12
12
  /**
13
- * 实际的上传实现函数
14
- * @type {null | ((AxiosRequestConfig) => UploadDataPromise)}
15
- */
16
- let uploadMethod = null
17
-
18
- /**
19
- * 注册上传方法
13
+ * 注册上传方法(兼容旧版 API)
20
14
  * @param {function(AxiosRequestConfig): UploadDataPromise} fn - 实际的上传实现函数
15
+ * @deprecated 请使用 setupConfig({ uploadMethod: fn }) 代替
21
16
  */
22
17
  export function registryUpload(fn) {
23
- uploadMethod = fn
18
+ setupConfig({ uploadMethod: fn })
24
19
  }
25
20
 
26
21
  /**
@@ -29,17 +24,29 @@ export function registryUpload(fn) {
29
24
  * @returns {UploadDataPromise} 上传结果Promise
30
25
  */
31
26
  export function customUpload(...args) {
27
+ const uploadMethod = getUploadMethod()
32
28
  if (typeof uploadMethod !== 'function') {
33
- throw new TypeError('请先通过 registryUpload(fn) 注册上传实现')
29
+ throw new TypeError('请先通过 setupConfig({ uploadMethod: fn }) 或 registryUpload(fn) 注册上传实现')
34
30
  }
35
31
  return uploadMethod(...args)
36
32
  }
37
33
 
34
+ /**
35
+ * 获取文件 URL
36
+ * @param {string} url - 文件路径
37
+ * @param {number|null} ossSize - OSS 样式尺寸
38
+ * @returns {string} 完整的文件 URL
39
+ */
38
40
  export function getFileUrl(url, ossSize = null) {
39
41
  if (url && !url?.startsWith('http')) {
42
+ const baseURL = getBaseURL()
43
+ if (!baseURL) {
44
+ console.warn('BASE_URL 未配置,返回原始 URL。请使用 setupConfig({ baseURL: "..." }) 配置。')
45
+ return url
46
+ }
40
47
  return !ossSize
41
- ? `${BASE_URL}${url}`
42
- : `${BASE_URL}${url}?x-oss-process=style/w${ossSize}`
48
+ ? `${baseURL}${url}`
49
+ : `${baseURL}${url}?x-oss-process=style/w${ossSize}`
43
50
  }
44
51
  return url
45
52
  }