@utogether/udp-core 2.0.0-beta.26 → 2.0.0-beta.28

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 (183) hide show
  1. package/dist/403-CyoOD-Ik.js +65 -0
  2. package/dist/404-Ch_OHTw0.js +65 -0
  3. package/dist/500-Cf9am7HK.js +67 -0
  4. package/dist/AuthorityInfo-BJ427cqG.js +4 -0
  5. package/dist/AuthorityInfo.vue_vue_type_style_index_0_lang-D9y7AwbB.js +99 -0
  6. package/dist/AuthorityPanel-lVnZ5bce.js +4 -0
  7. package/dist/AuthorityPanel.vue_vue_type_style_index_0_lang-nsfhDlvV.js +113 -0
  8. package/dist/Company-qo-lKPkv.js +25 -0
  9. package/dist/CompanyPanel-DkKWAKvY.js +204 -0
  10. package/dist/DataSet-iBHzs75s.js +147 -0
  11. package/dist/Department-CHUQByKX.js +25 -0
  12. package/dist/DepartmentPanel-C742dfOO.js +248 -0
  13. package/dist/DesignPanel-D9oE5R7m.js +4 -0
  14. package/dist/DesignPanel.vue_vue_type_style_index_0_lang-hYldVEbo.js +1097 -0
  15. package/dist/DictView-CrFXprP9.js +110 -0
  16. package/dist/InvOrganization-Cz8SzIgs.js +73 -0
  17. package/dist/Org-Bzt6yKox.js +38 -0
  18. package/dist/Preview-jonigfMQ.js +48 -0
  19. package/dist/ReportDefine-BpiM5Ovq.js +10 -0
  20. package/dist/ReportDesign-fp09cXJ7.js +164 -0
  21. package/dist/ReportQuery-52ZP1PYP.js +74 -0
  22. package/dist/ReportQueryFrom-DSYavJb1.js +4 -0
  23. package/dist/ReportQueryFrom.vue_vue_type_style_index_0_lang-DBGYEp0u.js +177 -0
  24. package/dist/ReportTemplate-CA_UW0eD.js +161 -0
  25. package/dist/Role-DqOt8Bk0.js +25 -0
  26. package/dist/RoleAssign-BdxhefhQ.js +26 -0
  27. package/dist/RolePanel-2gZ3H0ET.js +4 -0
  28. package/dist/RolePanel-BsNd0svJ.js +4 -0
  29. package/dist/RolePanel.vue_vue_type_script_setup_true_lang-DLOwgF99.js +152 -0
  30. package/dist/RolePanel.vue_vue_type_script_setup_true_lang-DmzD9kab.js +131 -0
  31. package/dist/ScrollPanel.vue_vue_type_style_index_0_lang-B9ptUMeI.js +99 -0
  32. package/dist/Staff-D3L8fEoY.js +26 -0
  33. package/dist/StaffInfo-DYRw6ZYJ.js +4 -0
  34. package/dist/StaffInfo.vue_vue_type_script_setup_true_lang-xqEOQnMs.js +107 -0
  35. package/dist/StaffPanel-DkrNH6Px.js +4 -0
  36. package/dist/StaffPanel.vue_vue_type_script_setup_true_lang-BPBMnliy.js +152 -0
  37. package/dist/SysUser-Bl1-cIpJ.js +15 -0
  38. package/dist/SysUserPanel-yxNLaBwt.js +4 -0
  39. package/dist/SysUserPanel.vue_vue_type_script_setup_true_lang-BDcsgSl5.js +352 -0
  40. package/dist/SystemMenu-C4_Arn12.js +155 -0
  41. package/dist/UserInfo-QcNwJCUR.js +4 -0
  42. package/dist/UserInfo.vue_vue_type_style_index_0_lang-DLIeUphX.js +159 -0
  43. package/dist/childView-B23DEO2u.js +4 -0
  44. package/dist/childView-saDZQv9x.js +4 -0
  45. package/dist/childView.vue_vue_type_style_index_0_lang-RsKR6CAC.js +182 -0
  46. package/dist/childView.vue_vue_type_style_index_0_lang-ZFEfavUY.js +142 -0
  47. package/dist/code-rule-2_Ihx_by.js +147 -0
  48. package/dist/core.es.js +26 -6
  49. package/dist/cron-task-BFOPJQIk.js +134 -0
  50. package/dist/flow-task-PoDnE_kE.js +10 -0
  51. package/dist/frameView-f7Ya0Knj.js +43 -0
  52. package/dist/index-BpdTDaTk.js +3213 -0
  53. package/dist/layout-home-v3DPJ7rB.js +231 -0
  54. package/dist/layoutView-DZHoQDH1.js +3190 -0
  55. package/dist/log-in-BPAMJTwH.js +115 -0
  56. package/dist/log-out-DZACF0jg.js +129 -0
  57. package/dist/login-B8cwozax.js +216 -0
  58. package/dist/login-log-CVvRgZSu.js +70 -0
  59. package/dist/lov-view-Ba7Y7xy0.js +98 -0
  60. package/dist/menuInfo-BpRKFYK8.js +4 -0
  61. package/dist/menuInfo.vue_vue_type_style_index_0_lang-DJ5sUC6m.js +359 -0
  62. package/dist/pda-app-C0jJecrL.js +706 -0
  63. package/dist/redirect-DTz8GSnv.js +15 -0
  64. package/dist/resource-BG22Cw4P.js +97 -0
  65. package/dist/su-welcome-DaxhbrC6.js +879 -0
  66. package/dist/sys-config-CG2fMtak.js +384 -0
  67. package/dist/udp-core.css +1 -2
  68. package/dist/useNav-_u2UAQWk.js +84 -0
  69. package/dist/utogether-MlnyYtNS.js +4 -0
  70. package/dist/wecom-push-B75FLee5.js +70 -0
  71. package/index.ts +54 -50
  72. package/package.json +21 -21
  73. package/src/App.vue +79 -78
  74. package/src/api/http.ts +10 -4
  75. package/src/api/index.ts +51 -51
  76. package/src/api/user.ts +64 -64
  77. package/src/components/SuQrcode/src/index.tsx +231 -236
  78. package/src/components/udp/content/index.vue +93 -93
  79. package/src/components/udp/form-upload/form-upload.vue +496 -496
  80. package/src/components/udp/grid/index.vue +643 -544
  81. package/src/components/udp/index.ts +2 -1
  82. package/src/components/udp/modal-form/index.vue +326 -0
  83. package/src/components/udp/utils.ts +420 -420
  84. package/src/layout/components/lay-navbar/index.vue +240 -240
  85. package/src/layout/components/lay-panel/index.vue +2 -6
  86. package/src/layout/components/lay-search/components/SearchModal.vue +185 -181
  87. package/src/layout/components/lay-sidebar/mixNav.vue +261 -261
  88. package/src/layout/components/lay-sidebar/sidebarItem.vue +199 -195
  89. package/src/layout/components/lay-sidebar/vertical.vue +92 -92
  90. package/src/layout/layoutView.vue +1 -0
  91. package/src/main.ts +111 -109
  92. package/src/plugins/i18n/zh.ts +5 -1
  93. package/src/plugins/vxe-table/index.ts +116 -116
  94. package/src/router/index.ts +5 -34
  95. package/src/router/utils.ts +434 -430
  96. package/src/store/modules/permission.ts +1 -1
  97. package/src/store/modules/system.ts +193 -186
  98. package/src/style/print-lock.css +380 -375
  99. package/src/style/suprint.css +990 -985
  100. package/src/style/vxetable.scss +372 -364
  101. package/src/utils/authority/index.ts +19 -2
  102. package/src/utils/dataFormat/index.ts +309 -222
  103. package/src/utils/udp/http/index.ts +126 -67
  104. package/src/utils/udp/http/types.d.ts +15 -14
  105. package/src/views/login/login-view.vue +4 -21
  106. package/src/views/organization/department/DepartmentPanel.vue +3 -4
  107. package/src/views/system/sys/sys-config.vue +344 -344
  108. package/src/views/uhome/components/home-todo.vue +191 -178
  109. package/src/views/uhome/dynamic-card.vue +31 -31
  110. package/src/views/uhome/su-welcome.vue +310 -310
  111. package/src/views/ulogin/login.vue +292 -296
  112. package/src/views/urpt/design/DesignPanel.vue +538 -507
  113. package/src/views/urpt/design/print-data.ts +39 -59
  114. package/tsconfig.json +2 -3
  115. package/types/global.d.ts +234 -234
  116. package/vite.config.ts +2 -1
  117. package/dist/403-D6Wb3JJh.js +0 -72
  118. package/dist/404-B_HNbPNV.js +0 -72
  119. package/dist/500-BMemTTy1.js +0 -77
  120. package/dist/AuthorityInfo-6wHxwiFM.js +0 -91
  121. package/dist/AuthorityPanel-OqF_DvXA.js +0 -98
  122. package/dist/Company-BLXSfow0.js +0 -21
  123. package/dist/CompanyPanel-B4kRZ5Cg.js +0 -199
  124. package/dist/DataSet-CuGZcKC-.js +0 -141
  125. package/dist/Department-oFhsa7cd.js +0 -21
  126. package/dist/DepartmentPanel-B1UGpu-r.js +0 -242
  127. package/dist/DepartmentPanel-BL58AdoT.js +0 -2
  128. package/dist/DesignPanel-DmkFVw1N.js +0 -1196
  129. package/dist/DictView-CC5yMzOq.js +0 -100
  130. package/dist/File-WJXjGYxr.js +0 -89
  131. package/dist/InvOrganization-BwMmD8Ua.js +0 -76
  132. package/dist/Org-HgnOWubi.js +0 -76
  133. package/dist/Preview-CAzWxLmP.js +0 -45
  134. package/dist/ReIcon-DecitXmg.js +0 -413
  135. package/dist/ReportDefine-BgLM-Rjk.js +0 -10
  136. package/dist/ReportDesign-DwchGG2P.js +0 -158
  137. package/dist/ReportQuery-D5jaRJEn.js +0 -101
  138. package/dist/ReportQueryFrom-CNlmtYey.js +0 -198
  139. package/dist/ReportTemplate-CNcTmccs.js +0 -162
  140. package/dist/Role-Be8WfdCA.js +0 -21
  141. package/dist/RoleAssign-CtehGAUf.js +0 -22
  142. package/dist/RolePanel-CAwITg_q.js +0 -131
  143. package/dist/RolePanel-SN0FGFZ7.js +0 -176
  144. package/dist/ScrollPanel-DW30pGz1.js +0 -88
  145. package/dist/Staff-V2YsNKcj.js +0 -22
  146. package/dist/StaffInfo-CKRPW0r4.js +0 -149
  147. package/dist/StaffPanel-BxcgMg7u.js +0 -143
  148. package/dist/SysUser-Dxyj5w5m.js +0 -12
  149. package/dist/SysUserPanel-DI6CWcZo.js +0 -365
  150. package/dist/SystemMenu-BBHREM8T.js +0 -154
  151. package/dist/UserInfo-BMVQ0xwE.js +0 -194
  152. package/dist/_plugin-vue_export-helper-C6QCLu9I.js +0 -8
  153. package/dist/api-BFNxcxSN.js +0 -30
  154. package/dist/authority-BJFEUdrh.js +0 -20
  155. package/dist/await-to-js.es5-DkWYmPXW.js +0 -10
  156. package/dist/childView-BBjPEraB.js +0 -184
  157. package/dist/childView-DNqG2UVm.js +0 -181
  158. package/dist/code-rule-QFrhqFrW.js +0 -151
  159. package/dist/contant-Q77dU_V3.js +0 -4
  160. package/dist/cron-task-BpUDKEAU.js +0 -131
  161. package/dist/flow-task-DAc2NrDU.js +0 -11
  162. package/dist/frameView-Di0zJZUR.js +0 -39
  163. package/dist/layout-home-BVp7vYLR.js +0 -239
  164. package/dist/layoutView-B6Mx2ERA.js +0 -2662
  165. package/dist/log-in-BrNB0mLz.js +0 -117
  166. package/dist/log-out-dYfqvzy6.js +0 -111
  167. package/dist/login-D_Hjy3Jd.js +0 -231
  168. package/dist/login-log-CJak-ANA.js +0 -79
  169. package/dist/lov-view-DM5Nm5tW.js +0 -95
  170. package/dist/menuInfo-BlOY1KZW.js +0 -346
  171. package/dist/mitt-CQgI7DYU.js +0 -27
  172. package/dist/pda-app-CA7YI37u.js +0 -589
  173. package/dist/redirect-N0k4tImU.js +0 -16
  174. package/dist/resource-CfQTHFcs.js +0 -94
  175. package/dist/su-welcome-DVD3S_du.js +0 -799
  176. package/dist/sys-config-Ddb3vBpK.js +0 -316
  177. package/dist/system-Cm3lyBas.js +0 -1528
  178. package/dist/udp-core-DaQd5CF1.js +0 -2028
  179. package/dist/useDataThemeChange-DJ4K3VGp.js +0 -226
  180. package/dist/useNav-BhOJIdrJ.js +0 -106
  181. package/dist/utogether-l7JXs4Lv.js +0 -4
  182. package/dist/water-mark-WDQZ9YqB.js +0 -119
  183. package/dist/wecom-push-kWkAVRCj.js +0 -77
package/src/api/user.ts CHANGED
@@ -1,64 +1,64 @@
1
- /*
2
- * @Author: wei.li
3
- * @Date: 2021-11-17 16:02:30
4
- * @LastEditors: levi7754 levi7754@163.com
5
- * @LastEditTime: 2026-01-23 18:21:36
6
- * @Description: file content
7
- */
8
- import { http } from '@utogether/utils';
9
- import { toDateString } from 'xe-utils';
10
- // import { http } from '../utils/udp/http';
11
- import { getBaseURL } from './';
12
-
13
- import { getPlatform, getBrower } from '../utils/browers';
14
-
15
- // 私钥
16
- export const getPublicKey = () => http.get(`${getBaseURL()}/public/request`);
17
- // 获取验证码
18
- export const getVerify = () => http.request('get', '/captcha');
19
- /**
20
- * @description: 登录系统
21
- * @param {*} 用户和秘钥
22
- */
23
- export const getLogin = (data: object) => http.post(`${getBaseURL()}/uath/login`, data);
24
- // 系统初始化
25
- export const initSystemInfo = () => http.get(`${getBaseURL()}/uums/roleMenu`);
26
- // 查询值集
27
- export const initDict = () => http.get(`${getBaseURL()}/upfm/v1/lov/selectAll`);
28
-
29
- /**
30
- * @description: 登出系统
31
- * @param {*} 用户
32
- */
33
- export const loginoutVms = (data?: object) => http.post(`${getBaseURL()}/public/logout`, data);
34
- /**
35
- * @description: 获取异步菜单
36
- * @param {*} 用户名
37
- */
38
- export const getAsyncRoutes = (data: object) => http.get(`${getBaseURL()}/uums/roleMenu/userMenu`, data);
39
- /**
40
- * @description: 刷新token
41
- * @param {object} data
42
- * @return {*}
43
- */
44
- export const refreshToken = (data: object) => {
45
- return http.request('post', '/refreshToken', { data });
46
- };
47
-
48
- /**
49
- * 用户监控
50
- * @param username 用户名
51
- * @returns
52
- */
53
- export const userMonitor = username => {
54
- const userAgent = navigator.userAgent.toLowerCase();
55
- const { browser, browserVersion } = getBrower(userAgent);
56
- const data = {
57
- userName: username,
58
- loginTime: toDateString(new Date()),
59
- browser,
60
- browserVersion,
61
- operatingSystem: getPlatform(userAgent)
62
- };
63
- return http.request('post', `${getBaseURL()}/upfm/v1/userMonitor`, data);
64
- };
1
+ /*
2
+ * @Author: wei.li
3
+ * @Date: 2021-11-17 16:02:30
4
+ * @LastEditors: levi7754 levi7754@163.com
5
+ * @LastEditTime: 2026-01-23 18:21:36
6
+ * @Description: file content
7
+ */
8
+ import { http } from '@utogether/utils';
9
+ import { toDateString } from 'xe-utils';
10
+ // import { http } from '../utils/udp/http';
11
+ import { getBaseURL } from './';
12
+
13
+ import { getPlatform, getBrower } from '../utils/browers';
14
+
15
+ // 私钥
16
+ export const getPublicKey = () => http.get(`${getBaseURL()}/public/request`);
17
+ // 获取验证码
18
+ export const getVerify = () => http.request('get', '/captcha');
19
+ /**
20
+ * @description: 登录系统
21
+ * @param {*} 用户和秘钥
22
+ */
23
+ export const getLogin = (data: object) => http.post(`${getBaseURL()}/uath/login`, data);
24
+ // 系统初始化
25
+ export const initSystemInfo = () => http.get(`${getBaseURL()}/uums/roleMenu`);
26
+ // 查询值集
27
+ export const initDict = () => http.get(`${getBaseURL()}/upfm/v1/lov/selectAll`);
28
+
29
+ /**
30
+ * @description: 登出系统
31
+ * @param {*} 用户
32
+ */
33
+ export const loginoutVms = (data?: object) => http.post(`${getBaseURL()}/public/logout`, data);
34
+ /**
35
+ * @description: 获取异步菜单
36
+ * @param {*} 用户名
37
+ */
38
+ export const getAsyncRoutes = (data: object) => http.get(`${getBaseURL()}/uums/roleMenu/userMenu`, data);
39
+ /**
40
+ * @description: 刷新token
41
+ * @param {object} data
42
+ * @return {*}
43
+ */
44
+ export const refreshToken = (data: object) => {
45
+ return http.request('post', '/refreshToken', { data });
46
+ };
47
+
48
+ /**
49
+ * 用户监控
50
+ * @param username 用户名
51
+ * @returns
52
+ */
53
+ export const userMonitor = username => {
54
+ const userAgent = navigator.userAgent.toLowerCase();
55
+ const { browser, browserVersion } = getBrower(userAgent);
56
+ const data = {
57
+ userName: username,
58
+ loginTime: toDateString(new Date()),
59
+ browser,
60
+ browserVersion,
61
+ operatingSystem: getPlatform(userAgent)
62
+ };
63
+ return http.request('post', `${getBaseURL()}/upfm/v1/userMonitor`, data);
64
+ };
@@ -1,236 +1,231 @@
1
- import { ref, unref, watch, nextTick, computed, type PropType, defineComponent } from 'vue';
2
- import './index.scss';
3
- import { isString, clone } from 'xe-utils';
4
- import propTypes from '@/utils/propTypes';
5
- import { IconifyIconOffline } from '../../ReIcon';
6
- import QRCode, { type QRCodeRenderersOptions } from 'qrcode';
7
-
8
- interface QrcodeLogo {
9
- src?: string;
10
- logoSize?: number;
11
- bgColor?: string;
12
- borderSize?: number;
13
- crossOrigin?: string;
14
- borderRadius?: number;
15
- logoRadius?: number;
16
- }
17
-
18
- const props = {
19
- // img 或者 canvas,img不支持logo嵌套
20
- tag: propTypes.string.validate((v: string) => ['canvas', 'img'].includes(v)).def('canvas'),
21
- // 二维码内容
22
- text: {
23
- type: [String, Array] as PropType<string | Recordable[]>,
24
- default: null
25
- },
26
- // qrcode.js配置项
27
- options: {
28
- type: Object as PropType<QRCodeRenderersOptions>,
29
- default: (): QRCodeRenderersOptions => ({})
30
- },
31
- // 宽度
32
- width: propTypes.number.def(200),
33
- // logo
34
- logo: {
35
- type: [String, Object] as PropType<Partial<QrcodeLogo> | string>,
36
- default: (): QrcodeLogo | string => ''
37
- },
38
- // 是否过期
39
- disabled: propTypes.bool.def(false),
40
- // 过期提示内容
41
- disabledText: propTypes.string.def('')
42
- };
43
-
44
- export default defineComponent({
45
- name: 'SuQrcode',
46
- props,
47
- emits: ['done', 'click', 'disabled-click'],
48
- setup(props, { emit }) {
49
- const { toCanvas, toDataURL } = QRCode;
50
- const loading = ref(true);
51
- const wrapRef = ref<Nullable<HTMLCanvasElement | HTMLImageElement>>(null);
52
- const renderText = computed(() => String(props.text));
53
- const wrapStyle = computed(() => {
54
- return {
55
- width: props.width + 'px',
56
- height: props.width + 'px'
57
- };
58
- });
59
- const initQrcode = async () => {
60
- await nextTick();
61
- const options = clone(props.options || {}, true);
62
- if (props.tag === 'canvas') {
63
- // 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率
64
- options.errorCorrectionLevel =
65
- options.errorCorrectionLevel || getErrorCorrectionLevel(unref(renderText));
66
- const _width: number = await getOriginWidth(unref(renderText), options);
67
- options.scale = props.width === 0 ? undefined : (props.width / _width) * 4;
68
- const canvasRef: any = await toCanvas(
69
- unref(wrapRef) as HTMLCanvasElement,
70
- unref(renderText),
71
- options
72
- );
73
- if (props.logo) {
74
- const url = await createLogoCode(canvasRef);
75
- emit('done', url);
76
- loading.value = false;
77
- } else {
78
- emit('done', canvasRef.toDataURL());
79
- loading.value = false;
80
- }
81
- } else {
82
- const url = await toDataURL(renderText.value, {
83
- errorCorrectionLevel: 'H',
84
- width: props.width,
85
- ...options
86
- });
87
- (unref(wrapRef) as HTMLImageElement).src = url;
88
- emit('done', url);
89
- loading.value = false;
90
- }
91
- };
92
- watch(
93
- () => renderText.value,
94
- val => {
95
- if (!val) return;
96
- initQrcode();
97
- },
98
- {
99
- deep: true,
100
- immediate: true
101
- }
102
- );
103
- const createLogoCode = (canvasRef: HTMLCanvasElement) => {
104
- const canvasWidth = canvasRef.width;
105
- const logoOptions: QrcodeLogo = Object.assign(
106
- {
107
- logoSize: 0.15,
108
- bgColor: '#ffffff',
109
- borderSize: 0.05,
110
- crossOrigin: 'anonymous',
111
- borderRadius: 8,
112
- logoRadius: 0
113
- },
114
- isString(props.logo) ? {} : props.logo
115
- );
116
- const {
117
- logoSize = 0.15,
118
- bgColor = '#ffffff',
119
- borderSize = 0.05,
120
- crossOrigin = 'anonymous',
121
- borderRadius = 8,
122
- logoRadius = 0
123
- } = logoOptions;
124
- const logoSrc = isString(props.logo) ? props.logo : props.logo.src;
125
- const logoWidth = canvasWidth * logoSize;
126
- const logoXY = (canvasWidth * (1 - logoSize)) / 2;
127
- const logoBgWidth = canvasWidth * (logoSize + borderSize);
128
- const logoBgXY = (canvasWidth * (1 - logoSize - borderSize)) / 2;
129
- const ctx = canvasRef.getContext('2d');
130
- if (!ctx) return;
131
- // logo 底色
132
- canvasRoundRect(ctx)(logoBgXY, logoBgXY, logoBgWidth, logoBgWidth, borderRadius);
133
- ctx.fillStyle = bgColor;
134
- ctx.fill();
135
- // logo
136
- const image = new Image();
137
- if (crossOrigin || logoRadius) {
138
- image.setAttribute('crossOrigin', crossOrigin);
139
- }
140
- (image as any).src = logoSrc;
141
- // 使用image绘制可以避免某些跨域情况
142
- const drawLogoWithImage = (image: HTMLImageElement) => {
143
- ctx.drawImage(image, logoXY, logoXY, logoWidth, logoWidth);
144
- };
145
- // 使用canvas绘制以获得更多的功能
146
- const drawLogoWithCanvas = (image: HTMLImageElement) => {
147
- const canvasImage = document.createElement('canvas');
148
- canvasImage.width = logoXY + logoWidth;
149
- canvasImage.height = logoXY + logoWidth;
150
- const imageCanvas = canvasImage.getContext('2d');
151
- if (!imageCanvas || !ctx) return;
152
- imageCanvas.drawImage(image, logoXY, logoXY, logoWidth, logoWidth);
153
- canvasRoundRect(ctx)(logoXY, logoXY, logoWidth, logoWidth, logoRadius);
154
- if (!ctx) return;
155
- const fillStyle = ctx.createPattern(canvasImage, 'no-repeat');
156
- if (fillStyle) {
157
- ctx.fillStyle = fillStyle;
158
- ctx.fill();
159
- }
160
- };
161
- // 将 logo绘制到 canvas上
162
- return new Promise((resolve: any) => {
163
- image.onload = () => {
164
- logoRadius ? drawLogoWithCanvas(image) : drawLogoWithImage(image);
165
- resolve(canvasRef.toDataURL());
166
- };
167
- });
168
- };
169
- // 得到原QrCode的大小,以便缩放得到正确的QrCode大小
170
- const getOriginWidth = async (content: string, options: QRCodeRenderersOptions) => {
171
- const _canvas = document.createElement('canvas');
172
- await toCanvas(_canvas, content, options);
173
- return _canvas.width;
174
- };
175
- // 对于内容少的QrCode,增大容错率
176
- const getErrorCorrectionLevel = (content: string) => {
177
- if (content.length > 36) {
178
- return 'M';
179
- } else if (content.length > 16) {
180
- return 'Q';
181
- } else {
182
- return 'H';
183
- }
184
- };
185
- // 用于绘制圆角
186
- const canvasRoundRect = (ctx: CanvasRenderingContext2D) => {
187
- return (x: number, y: number, w: number, h: number, r: number) => {
188
- const minSize = Math.min(w, h);
189
- if (r > minSize / 2) {
190
- r = minSize / 2;
191
- }
192
- ctx.beginPath();
193
- ctx.moveTo(x + r, y);
194
- ctx.arcTo(x + w, y, x + w, y + h, r);
195
- ctx.arcTo(x + w, y + h, x, y + h, r);
196
- ctx.arcTo(x, y + h, x, y, r);
197
- ctx.arcTo(x, y, x + w, y, r);
198
- ctx.closePath();
199
- return ctx;
200
- };
201
- };
202
- const clickCode = () => {
203
- emit('click');
204
- };
205
- const disabledClick = () => {
206
- emit('disabled-click');
207
- };
208
- return () => (
209
- <>
210
- <div v-loading={unref(loading)} class="qrcode relative inline-block" style={unref(wrapStyle)}>
211
- {props.tag === 'canvas' ? (
212
- <canvas ref={wrapRef} onClick={clickCode}></canvas>
213
- ) : (
214
- <img ref={wrapRef} onClick={clickCode}></img>
215
- )}
216
- {props.disabled && (
217
- <div
218
- class="qrcode--disabled absolute top-0 left-0 flex w-full h-full items-center justify-center"
219
- onClick={disabledClick}
220
- >
221
- <div class="absolute top-[50%] left-[50%] font-bold">
222
- <IconifyIconOffline
223
- class="cursor-pointer"
224
- icon="refresh-right"
225
- width="30"
226
- color="var(--el-color-primary)"
227
- />
228
- <div>{props.disabledText}</div>
229
- </div>
230
- </div>
231
- )}
232
- </div>
233
- </>
234
- );
235
- }
236
- });
1
+ import { ref, unref, watch, nextTick, computed, type PropType, defineComponent } from 'vue';
2
+ import './index.scss';
3
+ import { isString, clone } from 'xe-utils';
4
+ import propTypes from '@/utils/propTypes';
5
+ import { IconifyIconOffline } from '../../ReIcon';
6
+ import QRCode, { type QRCodeRenderersOptions } from 'qrcode';
7
+
8
+ interface QrcodeLogo {
9
+ src?: string;
10
+ logoSize?: number;
11
+ bgColor?: string;
12
+ borderSize?: number;
13
+ crossOrigin?: string;
14
+ borderRadius?: number;
15
+ logoRadius?: number;
16
+ }
17
+
18
+ const props = {
19
+ // img 或者 canvas,img不支持logo嵌套
20
+ tag: propTypes.string.validate((v: string) => ['canvas', 'img'].includes(v)).def('canvas'),
21
+ // 二维码内容
22
+ text: {
23
+ type: [String, Array] as PropType<string | Recordable[]>,
24
+ default: null
25
+ },
26
+ // qrcode.js配置项
27
+ options: {
28
+ type: Object as PropType<QRCodeRenderersOptions>,
29
+ default: (): QRCodeRenderersOptions => ({})
30
+ },
31
+ // 宽度
32
+ width: propTypes.number.def(200),
33
+ // logo
34
+ logo: {
35
+ type: [String, Object] as PropType<Partial<QrcodeLogo> | string>,
36
+ default: (): QrcodeLogo | string => ''
37
+ },
38
+ // 是否过期
39
+ disabled: propTypes.bool.def(false),
40
+ // 过期提示内容
41
+ disabledText: propTypes.string.def('')
42
+ };
43
+
44
+ export default defineComponent({
45
+ name: 'SuQrcode',
46
+ props,
47
+ emits: ['done', 'click', 'disabled-click'],
48
+ setup(props, { emit }) {
49
+ const { toCanvas, toDataURL } = QRCode;
50
+ const loading = ref(true);
51
+ const wrapRef = ref<Nullable<HTMLCanvasElement | HTMLImageElement>>(null);
52
+ const renderText = computed(() => String(props.text));
53
+ const wrapStyle = computed(() => {
54
+ return {
55
+ width: props.width + 'px',
56
+ height: props.width + 'px'
57
+ };
58
+ });
59
+ const initQrcode = async () => {
60
+ await nextTick();
61
+ const options = clone(props.options || {}, true);
62
+ if (props.tag === 'canvas') {
63
+ // 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率
64
+ options.errorCorrectionLevel = options.errorCorrectionLevel || getErrorCorrectionLevel(unref(renderText));
65
+ const _width: number = await getOriginWidth(unref(renderText), options);
66
+ options.scale = props.width === 0 ? undefined : (props.width / _width) * 4;
67
+ const canvasRef: any = await toCanvas(unref(wrapRef) as HTMLCanvasElement, unref(renderText), options);
68
+ if (props.logo) {
69
+ const url = await createLogoCode(canvasRef);
70
+ emit('done', url);
71
+ loading.value = false;
72
+ } else {
73
+ emit('done', canvasRef.toDataURL());
74
+ loading.value = false;
75
+ }
76
+ } else {
77
+ const url = await toDataURL(renderText.value, {
78
+ errorCorrectionLevel: 'H',
79
+ width: props.width,
80
+ ...options
81
+ });
82
+ (unref(wrapRef) as HTMLImageElement).src = url;
83
+ emit('done', url);
84
+ loading.value = false;
85
+ }
86
+ };
87
+ watch(
88
+ () => renderText.value,
89
+ val => {
90
+ if (!val) return;
91
+ initQrcode();
92
+ },
93
+ {
94
+ deep: true,
95
+ immediate: true
96
+ }
97
+ );
98
+ const createLogoCode = (canvasRef: HTMLCanvasElement) => {
99
+ const canvasWidth = canvasRef.width;
100
+ const logoOptions: QrcodeLogo = Object.assign(
101
+ {
102
+ logoSize: 0.15,
103
+ bgColor: '#ffffff',
104
+ borderSize: 0.05,
105
+ crossOrigin: 'anonymous',
106
+ borderRadius: 8,
107
+ logoRadius: 0
108
+ },
109
+ isString(props.logo) ? {} : props.logo
110
+ );
111
+ const {
112
+ logoSize = 0.15,
113
+ bgColor = '#ffffff',
114
+ borderSize = 0.05,
115
+ crossOrigin = 'anonymous',
116
+ borderRadius = 8,
117
+ logoRadius = 0
118
+ } = logoOptions;
119
+ const logoSrc = isString(props.logo) ? props.logo : props.logo.src;
120
+ const logoWidth = canvasWidth * logoSize;
121
+ const logoXY = (canvasWidth * (1 - logoSize)) / 2;
122
+ const logoBgWidth = canvasWidth * (logoSize + borderSize);
123
+ const logoBgXY = (canvasWidth * (1 - logoSize - borderSize)) / 2;
124
+ const ctx = canvasRef.getContext('2d');
125
+ if (!ctx) return;
126
+ // logo 底色
127
+ canvasRoundRect(ctx)(logoBgXY, logoBgXY, logoBgWidth, logoBgWidth, borderRadius);
128
+ ctx.fillStyle = bgColor;
129
+ ctx.fill();
130
+ // logo
131
+ const image = new Image();
132
+ if (crossOrigin || logoRadius) {
133
+ image.setAttribute('crossOrigin', crossOrigin);
134
+ }
135
+ (image as any).src = logoSrc;
136
+ // 使用image绘制可以避免某些跨域情况
137
+ const drawLogoWithImage = (image: HTMLImageElement) => {
138
+ ctx.drawImage(image, logoXY, logoXY, logoWidth, logoWidth);
139
+ };
140
+ // 使用canvas绘制以获得更多的功能
141
+ const drawLogoWithCanvas = (image: HTMLImageElement) => {
142
+ const canvasImage = document.createElement('canvas');
143
+ canvasImage.width = logoXY + logoWidth;
144
+ canvasImage.height = logoXY + logoWidth;
145
+ const imageCanvas = canvasImage.getContext('2d');
146
+ if (!imageCanvas || !ctx) return;
147
+ imageCanvas.drawImage(image, logoXY, logoXY, logoWidth, logoWidth);
148
+ canvasRoundRect(ctx)(logoXY, logoXY, logoWidth, logoWidth, logoRadius);
149
+ if (!ctx) return;
150
+ const fillStyle = ctx.createPattern(canvasImage, 'no-repeat');
151
+ if (fillStyle) {
152
+ ctx.fillStyle = fillStyle;
153
+ ctx.fill();
154
+ }
155
+ };
156
+ // logo绘制到 canvas上
157
+ return new Promise((resolve: any) => {
158
+ image.onload = () => {
159
+ logoRadius ? drawLogoWithCanvas(image) : drawLogoWithImage(image);
160
+ resolve(canvasRef.toDataURL());
161
+ };
162
+ });
163
+ };
164
+ // 得到原QrCode的大小,以便缩放得到正确的QrCode大小
165
+ const getOriginWidth = async (content: string, options: QRCodeRenderersOptions) => {
166
+ const _canvas = document.createElement('canvas');
167
+ await toCanvas(_canvas, content, options);
168
+ return _canvas.width;
169
+ };
170
+ // 对于内容少的QrCode,增大容错率
171
+ const getErrorCorrectionLevel = (content: string) => {
172
+ if (content.length > 36) {
173
+ return 'M';
174
+ } else if (content.length > 16) {
175
+ return 'Q';
176
+ } else {
177
+ return 'H';
178
+ }
179
+ };
180
+ // 用于绘制圆角
181
+ const canvasRoundRect = (ctx: CanvasRenderingContext2D) => {
182
+ return (x: number, y: number, w: number, h: number, r: number) => {
183
+ const minSize = Math.min(w, h);
184
+ if (r > minSize / 2) {
185
+ r = minSize / 2;
186
+ }
187
+ ctx.beginPath();
188
+ ctx.moveTo(x + r, y);
189
+ ctx.arcTo(x + w, y, x + w, y + h, r);
190
+ ctx.arcTo(x + w, y + h, x, y + h, r);
191
+ ctx.arcTo(x, y + h, x, y, r);
192
+ ctx.arcTo(x, y, x + w, y, r);
193
+ ctx.closePath();
194
+ return ctx;
195
+ };
196
+ };
197
+ const clickCode = () => {
198
+ emit('click');
199
+ };
200
+ const disabledClick = () => {
201
+ emit('disabled-click');
202
+ };
203
+ return () => (
204
+ <>
205
+ <div v-loading={unref(loading)} class="qrcode relative inline-block" style={unref(wrapStyle)}>
206
+ {props.tag === 'canvas' ? (
207
+ <canvas ref={wrapRef} onClick={clickCode}></canvas>
208
+ ) : (
209
+ <img ref={wrapRef} onClick={clickCode}></img>
210
+ )}
211
+ {props.disabled && (
212
+ <div
213
+ class="qrcode--disabled absolute top-0 left-0 flex w-full h-full items-center justify-center"
214
+ onClick={disabledClick}
215
+ >
216
+ <div class="absolute top-[50%] left-[50%] font-bold">
217
+ <IconifyIconOffline
218
+ class="cursor-pointer"
219
+ icon="refresh-right"
220
+ width="30"
221
+ color="var(--el-color-primary)"
222
+ />
223
+ <div>{props.disabledText}</div>
224
+ </div>
225
+ </div>
226
+ )}
227
+ </div>
228
+ </>
229
+ );
230
+ }
231
+ });