@fmdeui/fmui 1.0.26 → 1.0.27

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 CHANGED
@@ -1,36 +1,60 @@
1
- ## fmdeui 组件库
1
+ # fmdeui 组件库
2
2
 
3
- ## "@vitejs/plugin-vue": "^5.2.4", 升级到6.0.4编译报错
4
- ## vite 6.3.5
3
+ ## 项目介绍
5
4
 
5
+ fmdeui 是一个基于 Vue 3 的前端组件库,提供了丰富的工具函数、状态管理、路由管理、国际化等功能,帮助开发者快速构建现代化的前端应用。
6
6
 
7
+ ## 安装
7
8
 
9
+ ```bash
10
+ # 使用 npm
11
+ npm install @fmdeui/fmui
8
12
 
13
+ # 使用 pnpm
14
+ pnpm add @fmdeui/fmui
9
15
 
10
- ## 自定义路由配置
16
+ # 使用 yarn
17
+ yarn add @fmdeui/fmui
18
+ ```
11
19
 
12
- import { router, initRouter, configureRoutes, setPathPrefix, setDynamicViewsModules } from '@fmdeui/router';
20
+ ## 快速开始
13
21
 
14
- // 配置路由
15
- configureRoutes({
16
- dynamicRoutes: [...],
17
- staticRoutes: [...],
18
- pathPrefix: '/@' // 可选
19
- });
22
+ ### 1. 基本使用
20
23
 
21
- // 设置动态视图模块映射
22
- const modules = import.meta.glob('./views/**/*.vue');
23
- setDynamicViewsModules(modules);
24
+ ```javascript
25
+ import { createApp } from 'vue';
26
+ import App from './App.vue';
27
+ import fmdeui from '@fmdeui/fmui';
28
+ import '@fmdeui/fmui/dist/style.css';
24
29
 
25
- // 初始化路由
26
- const routerInstance = initRouter();
27
- app.use(routerInstance);
30
+ const app = createApp(App);
31
+ app.use(fmdeui);
32
+ app.mount('#app');
33
+ ```
28
34
 
35
+ ### 2. 按需导入
29
36
 
30
- # 1. 覆盖方式(默认)
31
- import { configureRoutes, initRouter } from '@fmdeui/router';
37
+ ```javascript
38
+ import { createApp } from 'vue';
39
+ import App from './App.vue';
40
+ import { router, initRouter, useTagsViewRoutes, signalR } from '@fmdeui/fmui';
32
41
 
33
- // 不设置 merge 或设置为 false,使用覆盖方式
42
+ const app = createApp(App);
43
+ // 配置并初始化路由
44
+ // ...
45
+ app.mount('#app');
46
+ ```
47
+
48
+ ## 核心功能
49
+
50
+ ### 1. 路由管理
51
+
52
+ #### 配置路由
53
+
54
+ ```javascript
55
+ import { configureRoutes, initRouter, setDynamicViewsModules } from '@fmdeui/fmui';
56
+
57
+ // 配置路由
34
58
  configureRoutes({
35
59
  dynamicRoutes: [
36
60
  {
@@ -58,39 +82,378 @@ configureRoutes({
58
82
  ]
59
83
  });
60
84
 
61
- // 结果:完全替换原有的路由配置
85
+ // 设置动态视图模块映射
86
+ const modules = import.meta.glob('./views/**/*.vue');
87
+ setDynamicViewsModules(modules);
88
+
89
+ // 初始化路由
90
+ const routerInstance = initRouter();
91
+ app.use(routerInstance);
92
+ ```
62
93
 
63
- ## 2. 合并方式
64
- import { configureRoutes, initRouter } from '@fmdeui/router';
94
+ #### 路由配置选项
65
95
 
66
- // 设置 merge: true,使用合并方式
67
- configureRoutes({
68
- dynamicRoutes: [
69
- {
70
- path: '/custom',
71
- name: 'custom',
72
- component: () => import('./layout/index.vue'),
73
- children: [
74
- {
75
- path: 'page',
76
- name: 'customPage',
77
- component: () => import('./views/custom/page.vue'),
78
- meta: { title: '自定义页面' }
79
- }
80
- ]
96
+ | 选项 | 类型 | 说明 | 默认值 |
97
+ |------|------|------|--------|
98
+ | dynamicRoutes | Array | 动态路由配置 | [] |
99
+ | staticRoutes | Array | 静态路由配置 | [] |
100
+ | pathPrefix | String | 路由路径前缀 | '' |
101
+ | merge | Boolean | 是否与默认路由合并 | false |
102
+
103
+ ### 2. 状态管理
104
+
105
+ #### 标签页管理
106
+
107
+ ```javascript
108
+ import { useTagsViewRoutes } from '@fmdeui/fmui';
109
+
110
+ const { tagsViewRoutes, addTagsViewRoute, closeTagsViewRoute, closeAllTagsViewRoutes } = useTagsViewRoutes();
111
+
112
+ // 添加标签页
113
+ addTagsViewRoute({ path: '/home', name: 'home', meta: { title: '首页' } });
114
+
115
+ // 关闭标签页
116
+ closeTagsViewRoute('/home');
117
+
118
+ // 关闭所有标签页
119
+ closeAllTagsViewRoutes();
120
+ ```
121
+
122
+ #### 主题配置
123
+
124
+ ```javascript
125
+ import { useThemeConfig } from '@fmdeui/fmui';
126
+
127
+ const { themeConfig, setThemeConfig } = useThemeConfig();
128
+
129
+ // 修改主题配置
130
+ setThemeConfig({
131
+ theme: 'dark',
132
+ layout: 'vertical',
133
+ primary: '#409EFF'
134
+ });
135
+ ```
136
+
137
+ #### 用户信息
138
+
139
+ ```javascript
140
+ import { useUserInfo } from '@fmdeui/fmui';
141
+
142
+ const { userInfo, setUserInfo } = useUserInfo();
143
+
144
+ // 设置用户信息
145
+ setUserInfo({
146
+ userId: '1',
147
+ userName: 'admin',
148
+ userAccount: 'admin'
149
+ });
150
+ ```
151
+
152
+ ### 3. 工具函数
153
+
154
+ #### 存储工具
155
+
156
+ ```javascript
157
+ import { Local, Session } from '@fmdeui/fmui';
158
+
159
+ // 本地存储
160
+ Local.set('key', 'value');
161
+ const value = Local.get('key');
162
+ Local.remove('key');
163
+ Local.clear();
164
+
165
+ // 会话存储
166
+ Session.set('key', 'value');
167
+ const value = Session.get('key');
168
+ Session.remove('key');
169
+ Session.clear();
170
+ ```
171
+
172
+ #### 网络请求
173
+
174
+ ```javascript
175
+ import { service, request2, getToken, clearAccessTokens } from '@fmdeui/fmui';
176
+
177
+ // 发送请求
178
+ const response = await service.get('/api/user');
179
+
180
+ // 带参数的请求
181
+ const response = await request2('/api/user', {
182
+ method: 'post',
183
+ data: { name: 'admin' }
184
+ });
185
+
186
+ // 获取 token
187
+ const token = getToken();
188
+
189
+ // 清除 token
190
+ clearAccessTokens();
191
+ ```
192
+
193
+ #### 时间格式化
194
+
195
+ ```javascript
196
+ import { formatDate, formatPast } from '@fmdeui/fmui';
197
+
198
+ // 格式化日期
199
+ const dateStr = formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss');
200
+
201
+ // 格式化相对时间
202
+ const pastStr = formatPast(new Date(Date.now() - 3600000)); // 1小时前
203
+ ```
204
+
205
+ #### 验证工具
206
+
207
+ ```javascript
208
+ import { verifyEmail, verifyPhone, verifyPassword } from '@fmdeui/fmui';
209
+
210
+ // 验证邮箱
211
+ const isEmail = verifyEmail('test@example.com');
212
+
213
+ // 验证手机号
214
+ const isPhone = verifyPhone('13800138000');
215
+
216
+ // 验证密码
217
+ const isPassword = verifyPassword('Password123');
218
+ ```
219
+
220
+ #### 文件下载
221
+
222
+ ```javascript
223
+ import { downloadByUrl, downloadByData } from '@fmdeui/fmui';
224
+
225
+ // 通过 URL 下载
226
+ await downloadByUrl('https://example.com/file.pdf', '文件.pdf');
227
+
228
+ // 通过数据下载
229
+ await downloadByData(data, 'data.json', 'application/json');
230
+ ```
231
+
232
+ #### Base64 转换
233
+
234
+ ```javascript
235
+ import { fileToBase64, base64ToFile } from '@fmdeui/fmui';
236
+
237
+ // 文件转 Base64
238
+ const base64 = await fileToBase64(file);
239
+
240
+ // Base64 转文件
241
+ const file = base64ToFile(base64, 'image.png');
242
+ ```
243
+
244
+ ### 4. 钩子函数
245
+
246
+ #### 权限管理
247
+
248
+ ```javascript
249
+ import { auth, auths, hAuth } from '@fmdeui/fmui';
250
+
251
+ // 单个权限检查
252
+ const hasPermission = auth('user:add');
253
+
254
+ // 多个权限检查
255
+ const hasPermissions = auths(['user:add', 'user:edit']);
256
+
257
+ // 指令形式
258
+ // <button v-auth="'user:add'">添加用户</button>
259
+ ```
260
+
261
+ #### 国际化
262
+
263
+ ```javascript
264
+ import { useLocale, setupI18n } from '@fmdeui/fmui';
265
+
266
+ // 设置国际化
267
+ setupI18n({
268
+ locale: 'zh-cn',
269
+ messages: {
270
+ 'zh-cn': {
271
+ hello: '你好'
272
+ },
273
+ 'en': {
274
+ hello: 'Hello'
81
275
  }
82
- ],
83
- staticRoutes: [
84
- {
85
- path: '/register',
86
- name: 'register',
87
- component: () => import('./views/register/index.vue'),
88
- meta: { title: '注册', isPublic: true }
276
+ }
277
+ });
278
+
279
+ // 使用国际化
280
+ const { t } = useLocale();
281
+ const hello = t('hello');
282
+ ```
283
+
284
+ #### 系统信息
285
+
286
+ ```javascript
287
+ import { loadSysInfo, updateFavicon } from '@fmdeui/fmui';
288
+
289
+ // 加载系统信息
290
+ await loadSysInfo();
291
+
292
+ // 更新 favicon
293
+ updateFavicon('https://example.com/favicon.ico');
294
+ ```
295
+
296
+ #### 空闲超时管理
297
+
298
+ ```javascript
299
+ import { initIdleTimeout, updateIdleTimeout, destroyIdleTimeout } from '@fmdeui/fmui';
300
+
301
+ // 初始化空闲超时(10秒)
302
+ initIdleTimeout({ timeout: 10 });
303
+
304
+ // 更新空闲超时时间(30分钟)
305
+ updateIdleTimeout(30 * 60);
306
+
307
+ // 销毁空闲超时
308
+ // destroyIdleTimeout();
309
+ ```
310
+
311
+ ### 5. SignalR 实时通信
312
+
313
+ ```javascript
314
+ import { signalR } from '@fmdeui/fmui';
315
+
316
+ // 监听在线用户列表
317
+ signalR.on('OnlineUserList', (data) => {
318
+ console.log('在线用户列表:', data.userList);
319
+
320
+ // 上下线通知
321
+ ElNotification({
322
+ title: '提示',
323
+ message: `${data.online ? `【${data.realName}】上线了` : `【${data.realName}】离开了`}`,
324
+ type: `${data.online ? 'primary' : 'error'}`,
325
+ position: 'bottom-right',
326
+ });
327
+ });
328
+
329
+ // 监听强制下线
330
+ signalR.on('ForceOffline', async (data) => {
331
+ await signalR.stop();
332
+ // 执行登出操作
333
+ // ...
334
+ });
335
+
336
+ // 发送消息
337
+ signalR.send('SendMessage', { message: 'Hello' });
338
+ ```
339
+
340
+ ### 6. 国际化
341
+
342
+ ```javascript
343
+ import { i18n, languageList, setupI18n } from '@fmdeui/fmui';
344
+
345
+ // 可用语言列表
346
+ console.log(languageList);
347
+
348
+ // 设置国际化
349
+ setupI18n({
350
+ locale: 'zh-cn',
351
+ messages: {
352
+ 'zh-cn': {
353
+ welcome: '欢迎'
354
+ },
355
+ 'en': {
356
+ welcome: 'Welcome'
89
357
  }
90
- ],
91
- merge: true // 启用合并
358
+ }
359
+ });
360
+
361
+ // 使用 i18n 实例
362
+ const welcome = i18n.t('welcome');
363
+ ```
364
+
365
+ ### 7. API 服务
366
+
367
+ ```javascript
368
+ import { useApi, useBaseApi } from '@fmdeui/fmui';
369
+
370
+ // 使用基础 API 服务
371
+ const baseApi = useBaseApi('sysAuth');
372
+ const response = await baseApi.post(null, 'login', { username: 'admin', password: '123456' });
373
+
374
+ // 使用自定义 API 服务
375
+ const api = useApi({
376
+ getUsers: { method: 'get', url: '/api/users' },
377
+ createUser: { method: 'post', url: '/api/users' }
92
378
  });
93
379
 
94
- // 结果:在原有路由基础上追加新的路由
95
- // dynamicRoutes = [原有路由, ...自定义路由]
96
- // staticRoutes = [原有路由, ...自定义路由]
380
+ const users = await api.getUsers();
381
+ const newUser = await api.createUser({ name: 'admin' });
382
+ ```
383
+
384
+ ## 高级配置
385
+
386
+ ### 1. 图标字体配置
387
+
388
+ ```javascript
389
+ import { setIntroduction, setCssCdn, setJsCdn } from '@fmdeui/fmui';
390
+
391
+ // 设置图标字体
392
+ setIntroduction({
393
+ scriptUrl: '//at.alicdn.com/t/font_1788044_0dwu4guekcwr.js'
394
+ });
395
+
396
+ // 单独设置 CSS CDN
397
+ setCssCdn('//at.alicdn.com/t/font_1788044_0dwu4guekcwr.css');
398
+
399
+ // 单独设置 JS CDN
400
+ setJsCdn('//at.alicdn.com/t/font_1788044_0dwu4guekcwr.js');
401
+ ```
402
+
403
+ ### 2. 事件总线
404
+
405
+ ```javascript
406
+ import { mittBus } from '@fmdeui/fmui';
407
+
408
+ // 监听事件
409
+ mittBus.on('event', (data) => {
410
+ console.log('事件触发:', data);
411
+ });
412
+
413
+ // 触发事件
414
+ mittBus.emit('event', { message: 'Hello' });
415
+
416
+ // 移除事件监听
417
+ mittBus.off('event');
418
+ ```
419
+
420
+ ### 3. 水印
421
+
422
+ ```javascript
423
+ import { Watermark } from '@fmdeui/fmui';
424
+
425
+ // 创建水印
426
+ const watermark = new Watermark({
427
+ text: 'fmdeui',
428
+ fontSize: 14,
429
+ color: '#999',
430
+ opacity: 0.1,
431
+ angle: -45,
432
+ density: 20
433
+ });
434
+
435
+ // 销毁水印
436
+ // watermark.destroy();
437
+ ```
438
+
439
+ ## 版本信息
440
+
441
+ 当前版本:`1.0.26`
442
+
443
+ ## 注意事项
444
+
445
+ 1. 使用 SignalR 功能时,确保后端已配置相应的 Hub 服务
446
+ 2. 空闲超时功能会在用户长时间无操作时自动登出
447
+ 3. 路由配置需要在应用启动时完成
448
+ 4. 部分功能依赖 Element Plus 组件库
449
+
450
+ ## 浏览器兼容性
451
+
452
+ - Chrome ≥ 60
453
+ - Firefox ≥ 55
454
+ - Safari ≥ 12
455
+ - Edge ≥ 79
456
+
457
+ ## 许可证
458
+
459
+ MIT License
@@ -0,0 +1,28 @@
1
+ import { App } from 'vue';
2
+ /**
3
+ * 表单事件数据类型
4
+ */
5
+ export interface FormSubmitData {
6
+ name: string;
7
+ data: any;
8
+ }
9
+ export interface FormFieldChangeData {
10
+ fieldName: string;
11
+ value: any;
12
+ isValid: boolean;
13
+ }
14
+ /**
15
+ * 表单事件处理器类型定义
16
+ */
17
+ export interface FormEventHandlers {
18
+ onFormSubmit: (data: FormSubmitData) => Promise<void>;
19
+ onFormReset: () => void;
20
+ onFieldChange: (data: FormFieldChangeData) => void;
21
+ onFormValidate: (errors: Record<string, string>) => void;
22
+ onFormDialogClose: () => void;
23
+ onFormDialogOpen: () => void;
24
+ }
25
+ /**
26
+ * 创建表单事件总线
27
+ */
28
+ export declare const provideFormEvents: (handlers: any, app?: App) => void, useFormEvents: () => any;
@@ -0,0 +1,31 @@
1
+ import { InjectionKey, App } from 'vue';
2
+ /**
3
+ * 事件映射类型
4
+ */
5
+ export type EventMap = Record<string, (...args: any[]) => void>;
6
+ /**
7
+ * 事件总线配置
8
+ */
9
+ export interface EventBusConfig<T extends EventMap> {
10
+ name: string;
11
+ defaultHandlers?: T;
12
+ strict?: boolean;
13
+ }
14
+ /**
15
+ * 创建类型安全的事件总线
16
+ * @param config 配置项
17
+ */
18
+ export declare function createEventBus<T extends EventMap>(config: string | EventBusConfig<T>): {
19
+ /**
20
+ * 在顶层组件中提供事件处理器
21
+ */
22
+ provideEvents(handlers: T, app?: App): void;
23
+ /**
24
+ * 在子组件中注入事件处理器
25
+ */
26
+ useEvents(): T;
27
+ /**
28
+ * 获取注入键(用于高级场景)
29
+ */
30
+ getKey(): InjectionKey<T>;
31
+ };
@@ -6,3 +6,4 @@ export * from './useInfo';
6
6
  export * from './dateTimeShortCust';
7
7
  export * from './idleTimeout';
8
8
  export * from './useVxeTableOptionsHook';
9
+ export * from './composables/useDialogEvents';
package/es/index.mjs CHANGED
@@ -34,6 +34,7 @@ export { initBackEndControlRoutes, setDynamicViewsModules } from './packages/rou
34
34
  export { initFrontEndControlRoutes } from './packages/router/frontEnd.mjs';
35
35
  export { judgementIdCard, verifiyNumberInteger, verifyAccount, verifyAndSpace, verifyCarNum, verifyCnAndSpace, verifyEmail, verifyEnAndSpace, verifyFullName, verifyIPAddress, verifyIdCard, verifyNumberCnUppercase, verifyNumberComma, verifyNumberIntegerAndFloat, verifyNumberPercentage, verifyNumberPercentageFloat, verifyPassword, verifyPasswordPowerful, verifyPasswordStrength, verifyPhone, verifyPostalCode, verifyTelPhone, verifyTextColor, verifyUrl } from './packages/utils/toolsValidate.mjs';
36
36
  export { loadSysInfo, updateFavicon } from './packages/hooks/sysInfo.mjs';
37
+ export { provideFormEvents, useFormEvents } from './packages/hooks/composables/useDialogEvents.mjs';
37
38
  export { restartSignalR, signalR } from './packages/utils/signalR.mjs';
38
39
  export { router } from './packages/router/createRouter.mjs';
39
40
  export { saulVModel } from './packages/utils/saulVModel.mjs';
@@ -0,0 +1,33 @@
1
+ import { createEventBus } from './useEventBus.mjs';
2
+
3
+ const defaultHandlers = {
4
+ onFormSubmit: async () => {
5
+ console.warn("[FormEvents] onFormSubmit \u672A\u5B9E\u73B0");
6
+ },
7
+ onFormReset: () => {
8
+ console.warn("[FormEvents] onFormReset \u672A\u5B9E\u73B0");
9
+ },
10
+ onFieldChange: () => {
11
+ console.warn("[FormEvents] onFieldChange \u672A\u5B9E\u73B0");
12
+ },
13
+ onFormValidate: () => {
14
+ console.warn("[FormEvents] onFormValidate \u672A\u5B9E\u73B0");
15
+ },
16
+ onFormDialogClose: () => {
17
+ console.warn("[FormEvents] onFormDialogClose \u672A\u5B9E\u73B0");
18
+ },
19
+ onFormDialogOpen: () => {
20
+ console.warn("[FormEvents] onFormDialogOpen \u672A\u5B9E\u73B0");
21
+ }
22
+ };
23
+ const {
24
+ provideEvents: provideFormEvents,
25
+ useEvents: useFormEvents
26
+ } = createEventBus({
27
+ name: "formEvents",
28
+ defaultHandlers,
29
+ strict: true
30
+ // 开发环境严格检查
31
+ });
32
+
33
+ export { provideFormEvents, useFormEvents };
@@ -0,0 +1,39 @@
1
+ import { inject, provide } from 'vue';
2
+
3
+ function createEventBus(config) {
4
+ const options = typeof config === "string" ? { name: config, strict: true } : config;
5
+ const injectionKey = /* @__PURE__ */ Symbol(`eventBus:${options.name}`);
6
+ return {
7
+ /**
8
+ * 在顶层组件中提供事件处理器
9
+ */
10
+ provideEvents(handlers, app) {
11
+ if (app) {
12
+ app.provide(injectionKey, handlers);
13
+ } else {
14
+ provide(injectionKey, handlers);
15
+ }
16
+ },
17
+ /**
18
+ * 在子组件中注入事件处理器
19
+ */
20
+ useEvents() {
21
+ const events = inject(injectionKey);
22
+ if (options.strict && !events) {
23
+ console.warn(
24
+ `[EventBus] \u26A0\uFE0F "${options.name}" \u672A\u627E\u5230 provide\uFF01
25
+ \u8BF7\u786E\u4FDD\u5728\u9876\u5C42\u7EC4\u4EF6\u4E2D\u8C03\u7528\u4E86 provideEvents()`
26
+ );
27
+ }
28
+ return events || options.defaultHandlers || {};
29
+ },
30
+ /**
31
+ * 获取注入键(用于高级场景)
32
+ */
33
+ getKey() {
34
+ return injectionKey;
35
+ }
36
+ };
37
+ }
38
+
39
+ export { createEventBus };
@@ -5,3 +5,4 @@ export { loadSysInfo, updateFavicon } from './sysInfo.mjs';
5
5
  export { hasPrivilege, hasRoleCode, isAdmin, isMember, isNormalUser, isSupperAdmin, isTenantAdmin, orgId, orgName, posId, posName, roles, tenantId, userAccount, userEmail, userFriendName, userId, userName, userPhone } from './useInfo.mjs';
6
6
  export { useDateTimeShortCust } from './dateTimeShortCust.mjs';
7
7
  export { destroyIdleTimeout, initIdleTimeout, updateIdleTimeout } from './idleTimeout.mjs';
8
+ export { provideFormEvents, useFormEvents } from './composables/useDialogEvents.mjs';