@jiangood/open-admin 1.0.0

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 (164) hide show
  1. package/config/dist/common-plugin.js +148 -0
  2. package/config/dist/config.js +45 -0
  3. package/config/dist/index.js +18 -0
  4. package/package.json +41 -0
  5. package/src/app.js +1 -0
  6. package/src/asserts/welcome.png +0 -0
  7. package/src/forms/demoForm.jsx +16 -0
  8. package/src/framework/components/DownloadFileButton.d.ts +11 -0
  9. package/src/framework/components/DownloadFileButton.jsx +33 -0
  10. package/src/framework/components/Ellipsis.jsx +39 -0
  11. package/src/framework/components/Ellipsis.less +8 -0
  12. package/src/framework/components/Gap/index.d.ts +23 -0
  13. package/src/framework/components/Gap/index.jsx +46 -0
  14. package/src/framework/components/LinkButton.d.ts +14 -0
  15. package/src/framework/components/LinkButton.jsx +10 -0
  16. package/src/framework/components/NamedIcon.tsx +15 -0
  17. package/src/framework/components/Page/index.d.ts +17 -0
  18. package/src/framework/components/Page/index.jsx +30 -0
  19. package/src/framework/components/Page/index.less +10 -0
  20. package/src/framework/components/PageLoading.tsx +27 -0
  21. package/src/framework/components/ProModal/index.tsx +66 -0
  22. package/src/framework/components/ProTable/components/ToolBar/index.jsx +123 -0
  23. package/src/framework/components/ProTable/components/ToolBar/index.less +53 -0
  24. package/src/framework/components/ProTable/index.d.ts +42 -0
  25. package/src/framework/components/ProTable/index.jsx +260 -0
  26. package/src/framework/components/ProTable/index.less +14 -0
  27. package/src/framework/components/ProTable/utils/index.js +43 -0
  28. package/src/framework/components/ValueType/index.jsx +34 -0
  29. package/src/framework/components/ValueType/registry.jsx +27 -0
  30. package/src/framework/components/index.ts +17 -0
  31. package/src/framework/components/system/ButtonList.d.ts +8 -0
  32. package/src/framework/components/system/ButtonList.jsx +42 -0
  33. package/src/framework/components/system/HasPerm.tsx +14 -0
  34. package/src/framework/components/system/index.tsx +29 -0
  35. package/src/framework/components/view/ViewBooleanEnableDisable.tsx +20 -0
  36. package/src/framework/components/view/ViewEllipsis.d.ts +11 -0
  37. package/src/framework/components/view/ViewEllipsis.jsx +30 -0
  38. package/src/framework/components/view/ViewFile.d.ts +10 -0
  39. package/src/framework/components/view/ViewFile.jsx +49 -0
  40. package/src/framework/components/view/ViewFileButton.d.ts +10 -0
  41. package/src/framework/components/view/ViewFileButton.jsx +0 -0
  42. package/src/framework/components/view/ViewImage.d.ts +9 -0
  43. package/src/framework/components/view/ViewImage.jsx +60 -0
  44. package/src/framework/components/view/ViewRange/index.d.ts +16 -0
  45. package/src/framework/components/view/ViewRange/index.jsx +20 -0
  46. package/src/framework/components/view/ViewText.tsx +16 -0
  47. package/src/framework/components/view/index.ts +10 -0
  48. package/src/framework/field-components/FieldBoolean.d.ts +13 -0
  49. package/src/framework/field-components/FieldBoolean.jsx +76 -0
  50. package/src/framework/field-components/FieldDate.d.ts +27 -0
  51. package/src/framework/field-components/FieldDate.jsx +114 -0
  52. package/src/framework/field-components/FieldDateRange.d.ts +6 -0
  53. package/src/framework/field-components/FieldDateRange.jsx +104 -0
  54. package/src/framework/field-components/FieldDictSelect.d.ts +13 -0
  55. package/src/framework/field-components/FieldDictSelect.jsx +16 -0
  56. package/src/framework/field-components/FieldEditor.d.ts +10 -0
  57. package/src/framework/field-components/FieldEditor.jsx +58 -0
  58. package/src/framework/field-components/FieldNumberRange.d.ts +13 -0
  59. package/src/framework/field-components/FieldNumberRange.jsx +59 -0
  60. package/src/framework/field-components/FieldPercent.d.ts +12 -0
  61. package/src/framework/field-components/FieldPercent.jsx +27 -0
  62. package/src/framework/field-components/FieldRemoteSelect.d.ts +13 -0
  63. package/src/framework/field-components/FieldRemoteSelect.jsx +87 -0
  64. package/src/framework/field-components/FieldRemoteSelectMultiple.d.ts +13 -0
  65. package/src/framework/field-components/FieldRemoteSelectMultiple.jsx +86 -0
  66. package/src/framework/field-components/FieldRemoteSelectMultipleInline.d.ts +20 -0
  67. package/src/framework/field-components/FieldRemoteSelectMultipleInline.jsx +86 -0
  68. package/src/framework/field-components/FieldRemoteTree.d.ts +21 -0
  69. package/src/framework/field-components/FieldRemoteTree.jsx +45 -0
  70. package/src/framework/field-components/FieldRemoteTreeCascader.d.ts +23 -0
  71. package/src/framework/field-components/FieldRemoteTreeCascader.jsx +61 -0
  72. package/src/framework/field-components/FieldRemoteTreeSelect.d.ts +17 -0
  73. package/src/framework/field-components/FieldRemoteTreeSelect.jsx +67 -0
  74. package/src/framework/field-components/FieldRemoteTreeSelectMultiple.d.ts +17 -0
  75. package/src/framework/field-components/FieldRemoteTreeSelectMultiple.jsx +72 -0
  76. package/src/framework/field-components/FieldSysOrgTree.d.ts +12 -0
  77. package/src/framework/field-components/FieldSysOrgTree.jsx +23 -0
  78. package/src/framework/field-components/FieldSysOrgTreeSelect.d.ts +12 -0
  79. package/src/framework/field-components/FieldSysOrgTreeSelect.jsx +23 -0
  80. package/src/framework/field-components/FieldTable.d.ts +17 -0
  81. package/src/framework/field-components/FieldTable.jsx +108 -0
  82. package/src/framework/field-components/FieldTable.less +29 -0
  83. package/src/framework/field-components/FieldTableSelect.d.ts +19 -0
  84. package/src/framework/field-components/FieldTableSelect.jsx +59 -0
  85. package/src/framework/field-components/FieldUploadFile.d.ts +34 -0
  86. package/src/framework/field-components/FieldUploadFile.jsx +141 -0
  87. package/src/framework/field-components/index.ts +21 -0
  88. package/src/framework/field-components/system/OrgTree.tsx +61 -0
  89. package/src/framework/field-components/system/RoleTree.tsx +53 -0
  90. package/src/framework/field-components/system/index.ts +2 -0
  91. package/src/framework/index.ts +5 -0
  92. package/src/framework/pages/LoginPage.d.ts +16 -0
  93. package/src/framework/pages/LoginPage.jsx +135 -0
  94. package/src/framework/pages/LoginPage.less +53 -0
  95. package/src/framework/pages/LoginPageUtils.ts +36 -0
  96. package/src/framework/pages/index.ts +2 -0
  97. package/src/framework/utils/ArrUtils.ts +229 -0
  98. package/src/framework/utils/ColorsUtils.ts +378 -0
  99. package/src/framework/utils/DateUtils.ts +187 -0
  100. package/src/framework/utils/DeviceUtils.ts +46 -0
  101. package/src/framework/utils/DomUtils.ts +50 -0
  102. package/src/framework/utils/EventBusUtils.ts +144 -0
  103. package/src/framework/utils/Logger.ts +40 -0
  104. package/src/framework/utils/MessageUtils.tsx +170 -0
  105. package/src/framework/utils/ObjectUtils.ts +118 -0
  106. package/src/framework/utils/StorageUtils.ts +50 -0
  107. package/src/framework/utils/StringUtils.ts +436 -0
  108. package/src/framework/utils/TreeUtils.ts +251 -0
  109. package/src/framework/utils/UrlUtils.ts +152 -0
  110. package/src/framework/utils/UuidUtils.ts +88 -0
  111. package/src/framework/utils/ValidateUtils.ts +28 -0
  112. package/src/framework/utils/index.ts +16 -0
  113. package/src/framework/utils/system/DictUtils.ts +97 -0
  114. package/src/framework/utils/system/FormRegistryUtils.ts +77 -0
  115. package/src/framework/utils/system/HttpUtils.ts +247 -0
  116. package/src/framework/utils/system/PageUtils.ts +163 -0
  117. package/src/framework/utils/system/PermUtils.ts +79 -0
  118. package/src/framework/utils/system/SysUtils.ts +97 -0
  119. package/src/framework/utils/system/ThemeUtils.ts +27 -0
  120. package/src/framework/utils/system/index.ts +7 -0
  121. package/src/framework/view-components/ViewApproveStatus.tsx +26 -0
  122. package/src/framework/view-components/ViewBoolean.tsx +6 -0
  123. package/src/framework/view-components/ViewFlowableInstanceProgress.d.ts +12 -0
  124. package/src/framework/view-components/ViewFlowableInstanceProgress.jsx +97 -0
  125. package/src/framework/view-components/ViewFlowableInstanceProgressButton.tsx +26 -0
  126. package/src/framework/view-components/ViewPassword.tsx +25 -0
  127. package/src/framework/view-components/ViewProps.ts +11 -0
  128. package/src/framework/view-components/index.ts +6 -0
  129. package/src/index.ts +2 -0
  130. package/src/layouts/PageRender.d.ts +22 -0
  131. package/src/layouts/PageRender.jsx +90 -0
  132. package/src/layouts/admin/HeaderRight.jsx +104 -0
  133. package/src/layouts/admin/TabPageRender.jsx +158 -0
  134. package/src/layouts/admin/index.jsx +161 -0
  135. package/src/layouts/admin/index.less +65 -0
  136. package/src/layouts/index.jsx +165 -0
  137. package/src/layouts/index.less +24 -0
  138. package/src/loading.jsx +18 -0
  139. package/src/pages/404.jsx +13 -0
  140. package/src/pages/about.jsx +14 -0
  141. package/src/pages/index.jsx +25 -0
  142. package/src/pages/login.jsx +21 -0
  143. package/src/pages/system/api/ApiDoc.jsx +144 -0
  144. package/src/pages/system/api/index.jsx +268 -0
  145. package/src/pages/system/api/perm.jsx +69 -0
  146. package/src/pages/system/dict/Dict.jsx +72 -0
  147. package/src/pages/system/dict/DictItem.jsx +177 -0
  148. package/src/pages/system/dict/index.jsx +25 -0
  149. package/src/pages/system/file/index.jsx +160 -0
  150. package/src/pages/system/job/index.jsx +324 -0
  151. package/src/pages/system/log/index.jsx +78 -0
  152. package/src/pages/system/org/index.jsx +262 -0
  153. package/src/pages/system/role/index.jsx +308 -0
  154. package/src/pages/system/role/perm.jsx +108 -0
  155. package/src/pages/system/sysManual/index.jsx +127 -0
  156. package/src/pages/system/user/UserPerm.jsx +97 -0
  157. package/src/pages/system/user/index.jsx +258 -0
  158. package/src/pages/test.jsx +200 -0
  159. package/src/pages/ureport/index.jsx +16 -0
  160. package/src/pages/userCenter/ChangePassword.jsx +63 -0
  161. package/src/pages/userCenter/index.jsx +90 -0
  162. package/src/pages/userCenter/manual.jsx +59 -0
  163. package/src/pages/userCenter/message.jsx +105 -0
  164. package/src/style/global.less +51 -0
@@ -0,0 +1,378 @@
1
+ /**
2
+ * forked form https://github.com/quasarframework/quasar
3
+ */
4
+
5
+ // 正则表达式用于匹配 rgba 格式的字符串
6
+ const reRGBA = /^rgb(a)?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?([01]?\.?\d*?)?\)$/
7
+
8
+ /**
9
+ * RGB 颜色接口
10
+ * r, g, b 的范围是 [0, 255]
11
+ * a 的范围是 [0, 100] (百分比)
12
+ */
13
+ export interface RGB {
14
+ r: number
15
+ g: number
16
+ b: number
17
+ a?: number // 可选的 alpha (百分比)
18
+ }
19
+
20
+ /**
21
+ * HSV 颜色接口
22
+ * h 的范围是 [0, 360]
23
+ * s, v 的范围是 [0, 100] (百分比)
24
+ * a 的范围是 [0, 100] (百分比)
25
+ */
26
+ export interface HSV {
27
+ h: number
28
+ s: number
29
+ v: number
30
+ a?: number // 可选的 alpha (百分比)
31
+ }
32
+
33
+ /**
34
+ * 颜色工具类,提供颜色相关的转换和操作方法。
35
+ */
36
+ export class ColorsUtils {
37
+ /**
38
+ * 将 RGB 颜色对象转换为十六进制字符串 (包含可选的 alpha 值).
39
+ * @param color RGB 颜色对象
40
+ * @returns 十六进制颜色字符串, 如 '#RRGGBB' 或 '#RRGGBBAA'
41
+ */
42
+ static rgbToHex (color: RGB): string {
43
+ let { r, g, b, a } = color
44
+ const alpha = a !== void 0
45
+
46
+ r = Math.round(r)
47
+ g = Math.round(g)
48
+ b = Math.round(b)
49
+
50
+ if (
51
+ r > 255
52
+ || g > 255
53
+ || b > 255
54
+ || (alpha && a! > 100)
55
+ ) {
56
+ throw new TypeError('Expected 3 numbers below 256 (and optionally one below 100)')
57
+ }
58
+
59
+ const alphaHex = alpha
60
+ ? (Math.round(255 * a! / 100) | 1 << 8).toString(16).slice(1)
61
+ : ''
62
+
63
+ return '#' + ((b | g << 8 | r << 16) | 1 << 24).toString(16).slice(1) + alphaHex
64
+ }
65
+
66
+ /**
67
+ * 将 RGB 颜色对象转换为 rgb() 或 rgba() 字符串.
68
+ * @param color RGB 颜色对象
69
+ * @returns rgb() 或 rgba() 颜色字符串
70
+ */
71
+ static rgbToString (color: RGB): string {
72
+ const { r, g, b, a } = color
73
+ return `rgb${a !== void 0 ? 'a' : ''}(${r},${g},${b}${a !== void 0 ? ',' + (a / 100) : ''})`
74
+ }
75
+
76
+ /**
77
+ * 将十六进制颜色字符串转换为 RGB 颜色对象.
78
+ * 支持 '#RGB', '#RGBA', '#RRGGBB', '#RRGGBBAA' 格式.
79
+ * @param hex 十六进制颜色字符串
80
+ * @returns RGB 颜色对象
81
+ */
82
+ static hexToRgb (hex: string): RGB {
83
+ if (typeof hex !== 'string') {
84
+ throw new TypeError('Expected a string')
85
+ }
86
+
87
+ hex = hex.replace(/^#/, '')
88
+
89
+ if (hex.length === 3) {
90
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
91
+ } else if (hex.length === 4) {
92
+ // 确保 alpha 也被扩展
93
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]
94
+ }
95
+
96
+ const num = parseInt(hex, 16)
97
+
98
+ return hex.length > 6
99
+ ? { r: num >> 24 & 255, g: num >> 16 & 255, b: num >> 8 & 255, a: Math.round((num & 255) / 2.55) }
100
+ : { r: num >> 16, g: num >> 8 & 255, b: num & 255 }
101
+ }
102
+
103
+ /**
104
+ * 将 HSV 颜色对象转换为 RGB 颜色对象.
105
+ * @param color HSV 颜色对象
106
+ * @returns RGB 颜色对象
107
+ */
108
+ static hsvToRgb (color: HSV): RGB {
109
+ let r: number = 0, g: number = 0, b: number = 0
110
+ let { h, s, v, a } = color
111
+ s = s / 100
112
+ v = v / 100
113
+
114
+ h = h / 360
115
+ const
116
+ i = Math.floor(h * 6),
117
+ f = h * 6 - i,
118
+ p = v * (1 - s),
119
+ q = v * (1 - f * s),
120
+ t = v * (1 - (1 - f) * s)
121
+
122
+ switch (i % 6) {
123
+ case 0:
124
+ r = v
125
+ g = t
126
+ b = p
127
+ break
128
+ case 1:
129
+ r = q
130
+ g = v
131
+ b = p
132
+ break
133
+ case 2:
134
+ r = p
135
+ g = v
136
+ b = t
137
+ break
138
+ case 3:
139
+ r = p
140
+ g = q
141
+ b = v
142
+ break
143
+ case 4:
144
+ r = t
145
+ g = p
146
+ b = v
147
+ break
148
+ case 5:
149
+ r = v
150
+ g = p
151
+ b = q
152
+ break
153
+ }
154
+
155
+ return {
156
+ r: Math.round(r * 255),
157
+ g: Math.round(g * 255),
158
+ b: Math.round(b * 255),
159
+ a
160
+ }
161
+ }
162
+
163
+ /**
164
+ * 将 RGB 颜色对象转换为 HSV 颜色对象.
165
+ * @param color RGB 颜色对象
166
+ * @returns HSV 颜色对象
167
+ */
168
+ static rgbToHsv (color: RGB): HSV {
169
+ const { r, g, b, a } = color
170
+ const
171
+ max = Math.max(r, g, b),
172
+ min = Math.min(r, g, b),
173
+ d = max - min,
174
+ s = (max === 0 ? 0 : d / max),
175
+ v = max / 255
176
+ let h: number
177
+
178
+ switch (max) {
179
+ case min:
180
+ h = 0
181
+ break
182
+ case r:
183
+ h = (g - b) + d * (g < b ? 6 : 0)
184
+ h /= 6 * d
185
+ break
186
+ case g:
187
+ h = (b - r) + d * 2
188
+ h /= 6 * d
189
+ break
190
+ case b:
191
+ h = (r - g) + d * 4
192
+ h /= 6 * d
193
+ break
194
+ default:
195
+ h = 0 // 理论上不会走到这里
196
+ }
197
+
198
+ return {
199
+ h: Math.round(h * 360),
200
+ s: Math.round(s * 100),
201
+ v: Math.round(v * 100),
202
+ a
203
+ }
204
+ }
205
+
206
+ /**
207
+ * 将颜色文本 (hex 或 rgb/rgba) 转换为 RGB 颜色对象.
208
+ * @param str 颜色字符串
209
+ * @returns RGB 颜色对象
210
+ */
211
+ static textToRgb (str: string): RGB {
212
+ if (typeof str !== 'string') {
213
+ throw new TypeError('Expected a string')
214
+ }
215
+
216
+ const color = str.replace(/ /g, '')
217
+
218
+ const m = reRGBA.exec(color)
219
+
220
+ if (m === null) {
221
+ return this.hexToRgb(color)
222
+ }
223
+
224
+ const rgb: RGB = {
225
+ r: Math.min(255, parseInt(m[2], 10)),
226
+ g: Math.min(255, parseInt(m[3], 10)),
227
+ b: Math.min(255, parseInt(m[4], 10))
228
+ }
229
+
230
+ if (m[1]) {
231
+ const alpha = parseFloat(m[5])
232
+ // alpha 值在 [0, 1],需要转换为 [0, 100]
233
+ rgb.a = Math.min(1, isNaN(alpha) === true ? 1 : alpha) * 100
234
+ }
235
+
236
+ return rgb
237
+ }
238
+
239
+ /**
240
+ * 调亮或调暗颜色.
241
+ * percent > 0 为调亮 (lighten), percent < 0 为调暗 (darken).
242
+ * @param color 颜色字符串
243
+ * @param percent 百分比偏移量, 范围通常为 [-100, 100]
244
+ * @returns 新的十六进制颜色字符串
245
+ */
246
+ static lighten (color: string, percent: number): string {
247
+ if (typeof color !== 'string') {
248
+ throw new TypeError('Expected a string as color')
249
+ }
250
+ if (typeof percent !== 'number') {
251
+ throw new TypeError('Expected a numeric percent')
252
+ }
253
+
254
+ const rgb = this.textToRgb(color)
255
+ const
256
+ t = percent < 0 ? 0 : 255,
257
+ p = Math.abs(percent) / 100,
258
+ R = rgb.r,
259
+ G = rgb.g,
260
+ B = rgb.b
261
+
262
+ return '#' + (
263
+ 0x1000000 + (Math.round((t - R) * p) + R) * 0x10000
264
+ + (Math.round((t - G) * p) + G) * 0x100
265
+ + (Math.round((t - B) * p) + B)
266
+ ).toString(16).slice(1)
267
+ }
268
+
269
+ /**
270
+ * 计算颜色的亮度 (Luminosity).
271
+ * @param color 颜色字符串或 RGB 对象
272
+ * @returns 颜色的亮度值 (0 到 1)
273
+ */
274
+ static luminosity (color: string | RGB): number {
275
+ if (typeof color !== 'string' && (!color || color.r === void 0)) {
276
+ throw new TypeError('Expected a string or a {r, g, b} object as color')
277
+ }
278
+
279
+ const
280
+ rgb = typeof color === 'string' ? this.textToRgb(color) : color,
281
+ r = rgb.r / 255,
282
+ g = rgb.g / 255,
283
+ b = rgb.b / 255,
284
+ // 标准化 R, G, B 值
285
+ R = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4),
286
+ G = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4),
287
+ B = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4)
288
+
289
+ // W3C WCAG 2.0 亮度公式
290
+ return 0.2126 * R + 0.7152 * G + 0.0722 * B
291
+ }
292
+
293
+ /**
294
+ * 计算颜色的感知亮度 (Brightness).
295
+ * @param color 颜色字符串或 RGB 对象
296
+ * @returns 颜色的感知亮度值 (0 到 255)
297
+ */
298
+ static brightness (color: string | RGB): number {
299
+ if (typeof color !== 'string' && (!color || color.r === void 0)) {
300
+ throw new TypeError('Expected a string or a {r, g, b} object as color')
301
+ }
302
+
303
+ const rgb = typeof color === 'string'
304
+ ? this.textToRgb(color)
305
+ : color
306
+
307
+ // 根据人眼感知度的加权平均 (常用公式)
308
+ return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000
309
+ }
310
+
311
+ /**
312
+ * 将前景颜色 (fgColor) 混合到背景颜色 (bgColor) 上。
313
+ * @param fgColor 前景颜色字符串或 RGB 对象
314
+ * @param bgColor 背景颜色字符串或 RGB 对象
315
+ * @returns 如果 fgColor 是字符串则返回十六进制字符串,否则返回 RGB 对象
316
+ */
317
+ static blend (fgColor: string | RGB, bgColor: string | RGB): string | RGB {
318
+ if (typeof fgColor !== 'string' && (!fgColor || fgColor.r === void 0)) {
319
+ throw new TypeError('Expected a string or a {r, g, b[, a]} object as fgColor')
320
+ }
321
+
322
+ if (typeof bgColor !== 'string' && (!bgColor || bgColor.r === void 0)) {
323
+ throw new TypeError('Expected a string or a {r, g, b[, a]} object as bgColor')
324
+ }
325
+
326
+ const
327
+ rgb1 = typeof fgColor === 'string' ? this.textToRgb(fgColor) : fgColor,
328
+ r1 = rgb1.r / 255,
329
+ g1 = rgb1.g / 255,
330
+ b1 = rgb1.b / 255,
331
+ a1 = rgb1.a !== void 0 ? rgb1.a / 100 : 1, // 前景 alpha (0-1)
332
+ rgb2 = typeof bgColor === 'string' ? this.textToRgb(bgColor) : bgColor,
333
+ r2 = rgb2.r / 255,
334
+ g2 = rgb2.g / 255,
335
+ b2 = rgb2.b / 255,
336
+ a2 = rgb2.a !== void 0 ? rgb2.a / 100 : 1, // 背景 alpha (0-1)
337
+
338
+ // Porter-Duff Over 运算符
339
+ a = a1 + a2 * (1 - a1), // 混合后的总 alpha
340
+ r = Math.round(((r1 * a1 + r2 * a2 * (1 - a1)) / a) * 255),
341
+ g = Math.round(((g1 * a1 + g2 * a2 * (1 - a1)) / a) * 255),
342
+ b = Math.round(((b1 * a1 + b2 * a2 * (1 - a1)) / a) * 255)
343
+
344
+ const ret: RGB = { r, g, b, a: Math.round(a * 100) } // a 转换回 (0-100)
345
+
346
+ // 如果前景颜色输入是字符串,则返回十六进制字符串,否则返回 RGB 对象
347
+ return typeof fgColor === 'string'
348
+ ? this.rgbToHex(ret)
349
+ : ret
350
+ }
351
+
352
+ /**
353
+ * 改变颜色字符串的 alpha 透明度。
354
+ * @param color 颜色字符串 (如 '#RRGGBB' 或 'rgb(r,g,b)')
355
+ * @param offset alpha 的偏移量, 范围 [-1, 1]。正值增加透明度,负值减少透明度。
356
+ * @returns 带有新 alpha 值的十六进制颜色字符串 (#RRGGBBAA)
357
+ */
358
+ static changeAlpha (color: string, offset: number): string {
359
+ if (typeof color !== 'string') {
360
+ throw new TypeError('Expected a string as color')
361
+ }
362
+
363
+ if (offset === void 0 || offset < -1 || offset > 1) {
364
+ throw new TypeError('Expected offset to be between -1 and 1')
365
+ }
366
+
367
+ const { r, g, b, a } = this.textToRgb(color)
368
+ // 当前 alpha (0-1)
369
+ const alpha = a !== void 0 ? a / 100 : 1 // 如果没有 alpha,默认为 1 (100%)
370
+
371
+ // 新的 alpha (0-100)
372
+ const newAlpha = Math.round(Math.min(1, Math.max(0, alpha + offset)) * 100)
373
+
374
+ return this.rgbToHex({
375
+ r, g, b, a: newAlpha
376
+ })
377
+ }
378
+ }
@@ -0,0 +1,187 @@
1
+ import {StringUtils} from './StringUtils';
2
+
3
+ export class DateUtils {
4
+
5
+ public static convertTypeToFormat(type) {
6
+ if (type === 'YEAR') {
7
+ type = 'YYYY'
8
+ } else if (type === 'YEAR_MONTH') {
9
+ type = 'YYYY-MM'
10
+ } else if (type === 'YEAR_QUARTER') {
11
+ type = 'YYYY-QQ'
12
+ } else if (type === 'DAY') {
13
+ type = 'YYYY-MM-DD'
14
+ }
15
+ return type;
16
+ }
17
+
18
+ public static year(date: Date): number {
19
+ return date.getFullYear();
20
+ }
21
+
22
+ /**
23
+ * 获取月份,自动补0
24
+ * @param date
25
+ * @returns {string}
26
+ */
27
+ public static month(date: Date): string {
28
+ const n = date.getMonth() + 1; // (注意月份从0开始,所以要加1)
29
+ return StringUtils.pad(n, 2);
30
+ }
31
+
32
+ /**
33
+ * 获取日期,
34
+ * @param date
35
+ */
36
+ public static date(date: Date): string {
37
+ return StringUtils.pad(date.getDate(), 2);
38
+ }
39
+
40
+ /**
41
+ * 小时,24进制
42
+ * @param date
43
+ * @returns {string}
44
+ */
45
+ public static hour(date: Date): string {
46
+ return StringUtils.pad(date.getHours(), 2);
47
+ }
48
+
49
+ public static minute(date: Date): string {
50
+ return StringUtils.pad(date.getMinutes(), 2);
51
+ }
52
+
53
+ public static second(date: Date): string {
54
+ return StringUtils.pad(date.getSeconds(), 2);
55
+ }
56
+
57
+ public static formatDate(d: Date): string {
58
+ return this.year(d) + '-' + this.month(d) + '-' + this.date(d);
59
+ }
60
+
61
+ public static formatTime(d: Date): string {
62
+ return this.hour(d) + ':' + this.minute(d) + ':' + this.second(d);
63
+ }
64
+
65
+ public static formatDateTime(d: Date): string {
66
+ return this.formatDate(d) + ' ' + this.formatTime(d);
67
+ }
68
+
69
+ /**
70
+ *
71
+ * @param d
72
+ * @returns {string} 2020年1月30日
73
+ */
74
+ public static formatDateCn(d: Date): string {
75
+ return this.year(d) + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日';
76
+ }
77
+
78
+ /***
79
+ 当前时间, 如 2022-01-23 11:59:59
80
+ */
81
+ public static now(): string {
82
+ return this.formatDateTime(new Date());
83
+ }
84
+
85
+ /**
86
+ * 当前日期 ,如 2022-01-23
87
+ *
88
+ */
89
+ public static today(): string {
90
+ return this.formatDate(new Date());
91
+ }
92
+
93
+ public static thisYear(): number {
94
+ return this.year(new Date());
95
+ }
96
+
97
+ public static thisMonth(): string {
98
+ return this.month(new Date());
99
+ }
100
+
101
+ /**
102
+ * 显示友好时间,如 2小时前,1周前
103
+ * @param pastDate 日期, 支持Date,String,Number
104
+ */
105
+ public static friendlyTime(pastDate: Date | string | number): string | undefined {
106
+ if (pastDate == null) {
107
+ return undefined;
108
+ }
109
+ if (!(pastDate instanceof Date)) {
110
+ pastDate = new Date(pastDate);
111
+ }
112
+
113
+ const currentDate = new Date();
114
+ let elapsedMilliseconds = currentDate.getTime() - pastDate.getTime();
115
+ const suffix = elapsedMilliseconds > 0 ? '前' : '后';
116
+ elapsedMilliseconds = Math.abs(elapsedMilliseconds);
117
+
118
+ // 计算年、月、日、小时、分钟和秒的差值
119
+ const elapsedYears = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24 * 365));
120
+ const elapsedMonths = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24 * 30));
121
+ const elapsedDays = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24));
122
+ const elapsedHours = Math.floor(elapsedMilliseconds / (1000 * 60 * 60));
123
+ const elapsedMinutes = Math.floor(elapsedMilliseconds / (1000 * 60));
124
+ const elapsedSeconds = Math.floor(elapsedMilliseconds / 1000);
125
+
126
+ // 根据差值选择友好的格式
127
+ if (elapsedYears >= 1) {
128
+ return `${elapsedYears} 年${suffix}`;
129
+ }
130
+ if (elapsedMonths >= 1) {
131
+ return `${elapsedMonths} 个月${suffix}`;
132
+ }
133
+ if (elapsedDays >= 7) {
134
+ const weeks = Math.floor(elapsedDays / 7);
135
+ return `${weeks} 周${suffix}`;
136
+ }
137
+ if (elapsedDays >= 1) {
138
+ const days = elapsedDays;
139
+ return `${days} 天${suffix}`;
140
+ }
141
+ if (elapsedHours >= 1) {
142
+ return `${elapsedHours} 小时${suffix}`;
143
+ }
144
+ if (elapsedMinutes >= 1) {
145
+ return `${elapsedMinutes} 分钟${suffix}`;
146
+ }
147
+ return `${elapsedSeconds} 秒${suffix}`;
148
+ }
149
+
150
+ /**
151
+ * 总共耗时, 如 3分5秒
152
+ * @param time 数字 (Date.getTime)
153
+ * @returns {string|null}
154
+ */
155
+ public static friendlyTotalTime(time: number | string | null): string | null {
156
+ if (time == null || time === '-') {
157
+ return null;
158
+ }
159
+
160
+ let seconds: number;
161
+ if (typeof time === 'string') {
162
+ seconds = parseInt(time, 10) / 1000;
163
+ } else {
164
+ seconds = time / 1000;
165
+ }
166
+
167
+ seconds = Math.floor(seconds);
168
+
169
+ if (seconds < 60) {
170
+ return seconds + '秒';
171
+ }
172
+
173
+ let min = seconds / 60;
174
+ seconds = seconds % 60;
175
+
176
+ min = Math.floor(min);
177
+ seconds = Math.floor(seconds);
178
+
179
+ return min + '分' + seconds + '秒';
180
+ }
181
+
182
+ public static beginOfMonth(): string {
183
+ const d = new Date();
184
+ d.setDate(1);
185
+ return this.formatDate(d);
186
+ }
187
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * 包含了常用的浏览器和网络工具函数。
3
+ */
4
+ export class DeviceUtils {
5
+
6
+ /**
7
+ * 判断当前设备是否为移动设备 (包括 Windows Phone, Android, iOS)。
8
+ * @returns {boolean} 如果是移动设备返回 true,否则返回 false。
9
+ */
10
+ public static isMobileDevice(): boolean {
11
+ // 使用可选链操作符来安全地访问 navigator 和 window 上的属性,
12
+ // 以防在非浏览器环境中运行 (尽管这个函数主要用于浏览器环境)。
13
+ const userAgent = navigator?.userAgent || navigator?.vendor || (window as any)?.opera || '';
14
+
15
+ // 1. Windows Phone 必须放在 Android 之前,因为它的 UA 也可能包含 "Android"
16
+ if (/windows phone/i.test(userAgent)) {
17
+ return true;
18
+ }
19
+
20
+ // 2. Android devices
21
+ if (/android/i.test(userAgent)) {
22
+ return true;
23
+ }
24
+
25
+ // 3. iOS devices
26
+ // window.MSStream 检查是为了排除旧版 IE 上的触控设备,确保只检测移动设备。
27
+ // 对于 TypeScript,需要断言 window.MSStream 可能不存在。
28
+ if (/iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream) {
29
+ return true;
30
+ }
31
+
32
+ return false;
33
+ }
34
+
35
+ /**
36
+ * 根据当前页面的协议 (http/https) 和主机名构造 WebSocket 的基础 URL (ws/wss)。
37
+ * @returns {string} WebSocket 的基础 URL,例如 "ws://localhost:8080" 或 "wss://example.com"。
38
+ */
39
+ public static getWebsocketBaseUrl(): string {
40
+ // 使用 location.protocol 来确定是 ws 还是 wss。
41
+ const protocol: string = location.protocol === 'http:' ? 'ws:' : 'wss:';
42
+
43
+ // location.host 包含主机名和端口号 (如果有)。
44
+ return `${protocol}//${location.host}`;
45
+ }
46
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @fileoverview DOM 操作工具类
3
+ */
4
+
5
+ /**
6
+ * 封装了获取元素位置和尺寸的工具方法。
7
+ */
8
+ export class DomUtils {
9
+ /**
10
+ * 获取元素相对于视口的偏移量(top 和 left)。
11
+ *
12
+ * @param el 目标 DOM 元素或 window 对象。
13
+ * @returns 包含 top 和 left 属性的对象。
14
+ */
15
+ static offset(el: Element | Window): { top: number; left: number } {
16
+ if (el === window) {
17
+ return { top: 0, left: 0 };
18
+ }
19
+
20
+ // 类型断言,确保 el 是 Element 类型,以便调用 getBoundingClientRect
21
+ const element = el as Element;
22
+ const { top, left } = element.getBoundingClientRect();
23
+
24
+ return { top, left };
25
+ }
26
+
27
+ /**
28
+ * 获取元素的外部高度(如果是 window,则返回视口高度)。
29
+ *
30
+ * @param el 目标 DOM 元素或 window 对象。
31
+ * @returns 元素的高度(以像素为单位)。
32
+ */
33
+ static height(el: Element | Window): number {
34
+ return el === window
35
+ ? window.innerHeight // 视口高度
36
+ : (el as Element).getBoundingClientRect().height; // 元素高度
37
+ }
38
+
39
+ /**
40
+ * 获取元素的外部宽度(如果是 window,则返回视口宽度)。
41
+ *
42
+ * @param el 目标 DOM 元素或 window 对象。
43
+ * @returns 元素的宽度(以像素为单位)。
44
+ */
45
+ static width(el: Element | Window): number {
46
+ return el === window
47
+ ? window.innerWidth // 视口宽度
48
+ : (el as Element).getBoundingClientRect().width; // 元素宽度
49
+ }
50
+ }