fast-crud-ui3 1.5.16 → 1.5.18-beta

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 (168) hide show
  1. package/lib/assets/fonts/iconfont.d.ts +0 -0
  2. package/lib/components/checkbox-group/index.d.ts +2 -0
  3. package/lib/components/checkbox-group/src/fast-checkbox-group.d.ts +72 -0
  4. package/lib/components/content-dialog/index.d.ts +2 -0
  5. package/lib/components/content-dialog/src/fast-cell-content.d.ts +83 -0
  6. package/lib/components/json-viewer/index.d.ts +2 -0
  7. package/lib/components/json-viewer/src/fast-json-viewer.d.ts +48 -0
  8. package/lib/components/mapping.d.ts +5 -0
  9. package/lib/components/object-picker/index.d.ts +2 -0
  10. package/lib/components/object-picker/src/fast-object-picker.d.ts +132 -0
  11. package/lib/components/select/index.d.ts +2 -0
  12. package/lib/components/select/src/fast-select.d.ts +83 -0
  13. package/lib/components/table/index.d.ts +2 -0
  14. package/lib/components/table/src/RowConfirm.d.ts +39 -0
  15. package/lib/components/table/src/dynamic-filter-form.d.ts +118 -0
  16. package/lib/components/table/src/dynamic-filter-list.d.ts +57 -0
  17. package/lib/components/table/src/easy-filter.d.ts +118 -0
  18. package/lib/components/table/src/export-confirm.d.ts +12 -0
  19. package/lib/components/table/src/quick-filter-form.d.ts +42 -0
  20. package/lib/components/table/src/row-form.d.ts +33 -0
  21. package/lib/components/table/src/stored-filter-manager.d.ts +55 -0
  22. package/lib/components/table/src/stored-filter.d.ts +37 -0
  23. package/lib/components/table/src/table-head-cell.d.ts +9 -0
  24. package/lib/components/table/src/table.d.ts +507 -0
  25. package/lib/components/table/src/util.d.ts +77 -0
  26. package/lib/components/table-column/config.d.ts +5 -0
  27. package/lib/components/table-column/index.d.ts +2 -0
  28. package/lib/components/table-column/src/table-column.d.ts +256 -0
  29. package/lib/components/table-column-date-picker/config.d.ts +5 -0
  30. package/lib/components/table-column-date-picker/index.d.ts +2 -0
  31. package/lib/components/table-column-date-picker/src/table-column-date-picker.d.ts +173 -0
  32. package/lib/components/table-column-file/config.d.ts +5 -0
  33. package/lib/components/table-column-file/index.d.ts +2 -0
  34. package/lib/components/table-column-file/src/table-column-file.d.ts +285 -0
  35. package/lib/components/table-column-img/config.d.ts +5 -0
  36. package/lib/components/table-column-img/index.d.ts +2 -0
  37. package/lib/components/table-column-img/src/table-column-img.d.ts +285 -0
  38. package/lib/components/table-column-input/config.d.ts +5 -0
  39. package/lib/components/table-column-input/index.d.ts +2 -0
  40. package/lib/components/table-column-input/src/table-column-input.d.ts +173 -0
  41. package/lib/components/table-column-number/config.d.ts +5 -0
  42. package/lib/components/table-column-number/index.d.ts +2 -0
  43. package/lib/components/table-column-number/src/table-column-number.d.ts +173 -0
  44. package/lib/components/table-column-object/config.d.ts +5 -0
  45. package/lib/components/table-column-object/index.d.ts +2 -0
  46. package/lib/components/table-column-object/src/table-column-object.d.ts +315 -0
  47. package/lib/components/table-column-select/config.d.ts +5 -0
  48. package/lib/components/table-column-select/index.d.ts +2 -0
  49. package/lib/components/table-column-select/src/table-column-select.d.ts +276 -0
  50. package/lib/components/table-column-switch/config.d.ts +5 -0
  51. package/lib/components/table-column-switch/index.d.ts +2 -0
  52. package/lib/components/table-column-switch/src/table-column-switch.d.ts +175 -0
  53. package/lib/components/table-column-textarea/config.d.ts +5 -0
  54. package/lib/components/table-column-textarea/index.d.ts +2 -0
  55. package/lib/components/table-column-textarea/src/table-column-textarea.d.ts +173 -0
  56. package/lib/components/table-column-time-picker/config.d.ts +5 -0
  57. package/lib/components/table-column-time-picker/index.d.ts +2 -0
  58. package/lib/components/table-column-time-picker/src/table-column-time-picker.d.ts +173 -0
  59. package/lib/components/upload/index.d.ts +2 -0
  60. package/lib/components/upload/src/fast-upload.d.ts +120 -0
  61. package/lib/fast-crud-ui3.cjs.js +44 -17
  62. package/lib/fast-crud-ui3.es.js +9991 -5946
  63. package/lib/fast-crud-ui3.umd.js +44 -17
  64. package/lib/global.d.ts +42 -0
  65. package/lib/index.d.ts +56 -0
  66. package/lib/mixins/table-column.d.ts +104 -0
  67. package/lib/mixins/upload.d.ts +15 -0
  68. package/lib/model/cond.d.ts +48 -0
  69. package/lib/model/editComponentConfig.d.ts +25 -0
  70. package/lib/model/fastTableOption.d.ts +513 -0
  71. package/lib/model/filterComponentConfig.d.ts +55 -0
  72. package/lib/model/opt.d.ts +20 -0
  73. package/lib/model/order.d.ts +28 -0
  74. package/lib/model/pageQuery.d.ts +43 -0
  75. package/lib/model/query.d.ts +101 -0
  76. package/lib/model/rel.d.ts +5 -0
  77. package/lib/style.css +1 -1
  78. package/lib/util/cache.d.ts +17 -0
  79. package/lib/util/dialog.d.ts +49 -0
  80. package/lib/util/escape.d.ts +7 -0
  81. package/lib/util/http.d.ts +8 -0
  82. package/lib/util/pick.d.ts +9 -0
  83. package/lib/util/util.d.ts +311 -0
  84. package/package.json +19 -5
  85. package/packages/assets/fonts/iconfont.css +163 -0
  86. package/packages/assets/fonts/iconfont.js +1 -0
  87. package/packages/assets/fonts/iconfont.ttf +0 -0
  88. package/packages/assets/fonts/iconfont.woff +0 -0
  89. package/packages/assets/fonts/iconfont.woff2 +0 -0
  90. package/packages/components/checkbox-group/index.js +7 -0
  91. package/packages/components/checkbox-group/src/fast-checkbox-group.vue +83 -0
  92. package/packages/components/content-dialog/index.js +7 -0
  93. package/packages/components/content-dialog/src/fast-cell-content.vue +115 -0
  94. package/packages/components/json-viewer/index.js +7 -0
  95. package/packages/components/json-viewer/src/fast-json-viewer.vue +54 -0
  96. package/packages/components/mapping.js +95 -0
  97. package/packages/components/object-picker/index.js +7 -0
  98. package/packages/components/object-picker/src/fast-object-picker.vue +170 -0
  99. package/packages/components/select/index.js +7 -0
  100. package/packages/components/select/src/fast-select.vue +90 -0
  101. package/packages/components/table/index.js +7 -0
  102. package/packages/components/table/src/RowConfirm.vue +87 -0
  103. package/packages/components/table/src/dynamic-filter-form.vue +253 -0
  104. package/packages/components/table/src/dynamic-filter-list.vue +172 -0
  105. package/packages/components/table/src/easy-filter.vue +129 -0
  106. package/packages/components/table/src/export-confirm.vue +55 -0
  107. package/packages/components/table/src/quick-filter-form.vue +140 -0
  108. package/packages/components/table/src/row-form.vue +137 -0
  109. package/packages/components/table/src/stored-filter-manager.vue +240 -0
  110. package/packages/components/table/src/stored-filter.vue +180 -0
  111. package/packages/components/table/src/table-head-cell.vue +41 -0
  112. package/packages/components/table/src/table.vue +1309 -0
  113. package/packages/components/table/src/util.js +496 -0
  114. package/packages/components/table-column/config.js +64 -0
  115. package/packages/components/table-column/index.js +7 -0
  116. package/packages/components/table-column/src/table-column.vue +44 -0
  117. package/packages/components/table-column-date-picker/config.js +139 -0
  118. package/packages/components/table-column-date-picker/index.js +7 -0
  119. package/packages/components/table-column-date-picker/src/table-column-date-picker.vue +54 -0
  120. package/packages/components/table-column-file/config.js +83 -0
  121. package/packages/components/table-column-file/index.js +7 -0
  122. package/packages/components/table-column-file/src/table-column-file.vue +79 -0
  123. package/packages/components/table-column-img/config.js +83 -0
  124. package/packages/components/table-column-img/index.js +7 -0
  125. package/packages/components/table-column-img/src/table-column-img.vue +82 -0
  126. package/packages/components/table-column-input/config.js +77 -0
  127. package/packages/components/table-column-input/index.js +7 -0
  128. package/packages/components/table-column-input/src/table-column-input.vue +60 -0
  129. package/packages/components/table-column-number/config.js +89 -0
  130. package/packages/components/table-column-number/index.js +7 -0
  131. package/packages/components/table-column-number/src/table-column-number.vue +54 -0
  132. package/packages/components/table-column-object/config.js +66 -0
  133. package/packages/components/table-column-object/index.js +7 -0
  134. package/packages/components/table-column-object/src/table-column-object.vue +75 -0
  135. package/packages/components/table-column-select/config.js +67 -0
  136. package/packages/components/table-column-select/index.js +7 -0
  137. package/packages/components/table-column-select/src/table-column-select.vue +101 -0
  138. package/packages/components/table-column-switch/config.js +55 -0
  139. package/packages/components/table-column-switch/index.js +7 -0
  140. package/packages/components/table-column-switch/src/table-column-switch.vue +82 -0
  141. package/packages/components/table-column-textarea/config.js +77 -0
  142. package/packages/components/table-column-textarea/index.js +7 -0
  143. package/packages/components/table-column-textarea/src/table-column-textarea.vue +56 -0
  144. package/packages/components/table-column-time-picker/config.js +62 -0
  145. package/packages/components/table-column-time-picker/index.js +7 -0
  146. package/packages/components/table-column-time-picker/src/table-column-time-picker.vue +53 -0
  147. package/packages/components/upload/index.js +7 -0
  148. package/packages/components/upload/src/fast-upload.vue +272 -0
  149. package/packages/global.d.ts +42 -0
  150. package/packages/index.js +145 -0
  151. package/packages/mixins/table-column.js +133 -0
  152. package/packages/mixins/upload.js +14 -0
  153. package/packages/model/cond.js +74 -0
  154. package/packages/model/editComponentConfig.js +72 -0
  155. package/packages/model/fastTableOption.js +769 -0
  156. package/packages/model/filterComponentConfig.js +191 -0
  157. package/packages/model/opt.js +21 -0
  158. package/packages/model/order.js +37 -0
  159. package/packages/model/pageQuery.js +52 -0
  160. package/packages/model/query.js +161 -0
  161. package/packages/model/rel.js +5 -0
  162. package/packages/style.scss +5 -0
  163. package/packages/util/cache.js +92 -0
  164. package/packages/util/dialog.js +133 -0
  165. package/packages/util/escape.js +34 -0
  166. package/packages/util/http.js +18 -0
  167. package/packages/util/pick.js +92 -0
  168. package/packages/util/util.js +892 -0
@@ -0,0 +1,892 @@
1
+ import _ from 'lodash-es'
2
+ import moment from "moment/moment"
3
+ import {ElMessage} from "element-plus";
4
+
5
+
6
+ /**
7
+ * 剪掉字符串指定的前缀, 如果不是此前缀开头,则直接返回str
8
+ * @param str 待操作的字符串
9
+ * @param prefix 指定前缀
10
+ */
11
+ export function cutPrefix(str, prefix) {
12
+ if (!isString(str) || !isString(prefix) || !str.startsWith(prefix)) {
13
+ return str
14
+ }
15
+
16
+ return str.slice(prefix.length)
17
+ }
18
+
19
+ /**
20
+ * 断言
21
+ * @param cond
22
+ * @param msg
23
+ */
24
+ export function assert(cond, msg) {
25
+ if (!cond) {
26
+ throw new Error(msg);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * 断言并利用错误提示, 会抛出异常
32
+ * @param cond
33
+ * @param msg
34
+ */
35
+ export function assertTip(cond, msg) {
36
+ try {
37
+ assert(cond, msg)
38
+ } catch (err) {
39
+ ElMessage.error(msg)
40
+ throw err
41
+ }
42
+ }
43
+
44
+ export function addStartWith(str, startWith) {
45
+ return str.startsWith(startWith) ? str : startWith + str;
46
+ }
47
+
48
+ /**
49
+ * 若为空字符串,则取默认值
50
+ * @param str {string}
51
+ * @param defaultStr {string}
52
+ * @return {*}
53
+ */
54
+ export function defaultIfBlank(str, defaultStr) {
55
+ return ifBlank(str) ? defaultStr : str;
56
+ }
57
+
58
+ /**
59
+ * 是否是空字符串. undefined和null、均为空格也视为空字符串
60
+ * @param str {string}
61
+ * @return {boolean}
62
+ */
63
+ export function ifBlank(str) {
64
+ return str === undefined || str === null || (isString(str) && str.trim().length === 0);
65
+ }
66
+
67
+ export function toStr(val) {
68
+ return val + ''
69
+ }
70
+
71
+ /**
72
+ * 三元元算符简化
73
+ * @param cond
74
+ * @param trueVal
75
+ * @param falseVal
76
+ * @returns {*}
77
+ */
78
+ export function ternary(cond, trueVal, falseVal) {
79
+ return cond ? trueVal : falseVal
80
+ }
81
+
82
+ /**
83
+ * val若为空则取默认值defaultVal
84
+ * @param val {string | Array | Object}
85
+ * @param defaultVal {any}
86
+ * @return {*}
87
+ */
88
+ export function defaultIfEmpty(val, defaultVal) {
89
+ return isEmpty(val) ? defaultVal : val;
90
+ }
91
+
92
+ /**
93
+ * 驼峰转=>?(默认下划线)
94
+ * @param str {string} 待处理的字符串
95
+ * @param separator {string} 默认为下划线("_"), 表示驼峰转下划线
96
+ * @returns {*}
97
+ */
98
+ export function camelCaseTo(str, separator = '_') {
99
+ if (!/[A-Z]/.test(str)) return str; // 无需转换直接返回
100
+ return str.replace(/([A-Z])/g, `${separator}$1`).toLowerCase();
101
+ }
102
+
103
+ /**
104
+ * ?(默认下划线)转驼峰。单个字符串转换
105
+ * @param str {string} 待处理字符串
106
+ * @param separator 默认下划线
107
+ */
108
+ export function caseToCamel(str, separator = '_') {
109
+ if (!str.includes(separator)) return str; // 无需转换直接返回
110
+ const regex = new RegExp(`\\${separator}([a-z])`, 'g');
111
+ return str.replace(regex, (_, letter) => letter.toUpperCase());
112
+ }
113
+
114
+ /**
115
+ * ?(默认下划线)转驼峰。将一个对象类型中的所有key转换。若obj不是对象类型,则直接返回obj,否则将返回一个新的object
116
+ * @param obj 对象
117
+ * @param separator 默认下划线
118
+ */
119
+ export function convertKeyFromCaseToCamel(obj, separator = "_") {
120
+ if (!isObject(obj)) {
121
+ return obj
122
+ }
123
+ const newObj = {}
124
+ const keys = Object.keys(obj)
125
+ for (let i = 0; i < keys.length; i++) {
126
+ const key = keys[i]
127
+ const newKey = caseToCamel(key, separator)
128
+ newObj[newKey] = obj[key]
129
+ }
130
+ return newObj
131
+ }
132
+
133
+ /**
134
+ * 判断值是否为对象. 数组、null等都将返回false, 只有严格的{}才会返回true
135
+ * @param val {any}
136
+ */
137
+ export function isObject(val) {
138
+ let toStr = Object.prototype.toString.call(val);
139
+ return toStr === '[object Object]'
140
+ }
141
+
142
+ /**
143
+ * 是否是数组类型
144
+ * @param val {any}
145
+ * @return {boolean}
146
+ */
147
+ export function isArray(val) {
148
+ let toStr = Object.prototype.toString.call(val);
149
+ return toStr === '[object Array]'
150
+ }
151
+
152
+ /**
153
+ * 是否是布尔值
154
+ * @param val {any}
155
+ * @return {boolean}
156
+ */
157
+ export function isBoolean(val) {
158
+ let toStr = Object.prototype.toString.call(val);
159
+ return toStr === '[object Boolean]'
160
+ }
161
+
162
+ /**
163
+ * 是否是字符串
164
+ * @param val {any}
165
+ * @return {boolean}
166
+ */
167
+ export function isString(val) {
168
+ let toStr = Object.prototype.toString.call(val);
169
+ return toStr === '[object String]'
170
+ }
171
+
172
+ /**
173
+ * 是否是数值类型
174
+ * @param val {any}
175
+ * @return {boolean}
176
+ */
177
+ export function isNumber(val) {
178
+ let toStr = Object.prototype.toString.call(val);
179
+ return toStr === '[object Number]'
180
+ }
181
+
182
+ /**
183
+ * 是否是函数
184
+ * @param val {any}
185
+ * @return {boolean}
186
+ */
187
+ export function isFunction(val) {
188
+ let toStr = Object.prototype.toString.call(val);
189
+ return toStr === '[object Function]'
190
+ }
191
+
192
+ /**
193
+ * 是否是null值
194
+ * @param val {any}
195
+ * @return {boolean}
196
+ */
197
+ export function isNull(val) {
198
+ let toStr = Object.prototype.toString.call(val);
199
+ return toStr === '[object Null]'
200
+ }
201
+
202
+ /**
203
+ * 是否是undefined值
204
+ * @param val {any}
205
+ * @return {boolean}
206
+ */
207
+ export function isUndefined(val) {
208
+ let toStr = Object.prototype.toString.call(val);
209
+ return toStr === '[object Undefined]'
210
+ }
211
+
212
+ /**
213
+ * undefined、null、string、number、boolean视为简单类型,返回true
214
+ * @param val
215
+ * @return {boolean}
216
+ */
217
+ export function isSampleType(val) {
218
+ return isUndefined(val) || isNull(val) || isString(val) || isNumber(val) || isBoolean(val)
219
+ }
220
+
221
+ /**
222
+ * 是否是json字符串
223
+ * @param val
224
+ */
225
+ export function isJsonStr(val) {
226
+ if (!isString(val)) {
227
+ return false
228
+ }
229
+ try {
230
+ const obj = JSON.parse(val)
231
+ return obj !== null && isObject(obj)
232
+ } catch (e) {
233
+ return false
234
+ }
235
+ }
236
+
237
+ /**
238
+ * 转换为json, 若无法转换则抛出异常
239
+ * @param val
240
+ * @return {*}
241
+ */
242
+ export function toJson(val) {
243
+ if (isObject(val)) {
244
+ return val
245
+ }
246
+ if (isJsonStr(val)) {
247
+ return JSON.parse(val)
248
+ }
249
+ throw new Error(`Can't convert to json: ${val}`)
250
+ }
251
+
252
+ /**
253
+ * 是否是http或https打头的url
254
+ * @param val
255
+ * @return {*|boolean}
256
+ */
257
+ export function isUrl(val) {
258
+ if (!isString(val)) {
259
+ return false
260
+ }
261
+ return val.startsWith('http://') || val.startsWith('https://')
262
+ }
263
+
264
+ /**
265
+ * 判断一个值是否超过长度
266
+ * @param val 可能是字符串、数字、json等
267
+ * @param width 长度,px像素值(Number类型)
268
+ * @param font 字体设置。默认 "14px Arial", 不同字体大小会影响计算
269
+ */
270
+ export function isOverLength(val, width, font = '14px Arial') {
271
+ return calLength(val, font) > width
272
+ }
273
+
274
+ /**
275
+ * 给定一个值,计算其渲染长度(px)
276
+ * @param val
277
+ * @param font
278
+ */
279
+ export function calLength(val, font = '14px Arial') {
280
+ if (val == null) return 0;
281
+ // 转成字符串
282
+ let str;
283
+ if (typeof val === "object") {
284
+ try {
285
+ str = JSON.stringify(val);
286
+ } catch (e) {
287
+ str = String(val);
288
+ }
289
+ } else {
290
+ str = String(val);
291
+ }
292
+
293
+ // 创建canvas上下文测量文字宽度
294
+ const canvas = document.createElement("canvas");
295
+ const context = canvas.getContext("2d");
296
+ context.font = font;
297
+ return context.measureText(str).width;
298
+ }
299
+
300
+ /**
301
+ * 返回值的类型:
302
+ * [object String]、[object Number]、[object Object]、[object Boolean]、
303
+ * [object Array]、[object Function]、[object Null]、[object Undefined]
304
+ * @param value
305
+ * @returns {string}
306
+ */
307
+ export function typeOf(value) {
308
+ return Object.prototype.toString.call(value);
309
+ }
310
+
311
+
312
+ /**
313
+ * 判断一个值是否为空。
314
+ * 如果是
315
+ * 1. 字符串, 则判断是否为空字符串(空格也被视为空)
316
+ * 2. 对象, 则判断是否无任何键值
317
+ * 3. 数组, 则判断是否无任何数组成员
318
+ * 4. null, 返回true
319
+ * 5. undefined, true
320
+ * 6. 其他情况均返回false
321
+ * @param value {string | Object | Array | undefined | null}
322
+ * @return {boolean}
323
+ */
324
+ export function isEmpty(value) {
325
+ if (value && typeof value === 'object' && value.$ && value.$.vnode) {
326
+ throw new Error('组件实例不要用isEmpty判空!')
327
+ }
328
+ switch (typeOf(value)) {
329
+ case '[object String]':
330
+ return value.trim() === '';
331
+ case "[object Object]":
332
+ return _.isEmpty(value);
333
+ case "[object Array]":
334
+ return value.length === 0;
335
+ case "[object Undefined]":
336
+ case "[object Null]":
337
+ return true;
338
+ }
339
+ return false;
340
+ }
341
+
342
+ /**
343
+ * 清空对象所有的键值
344
+ * @param obj {Object}
345
+ */
346
+ export function clear(obj) {
347
+ if (isObject(obj)) {
348
+ for (let key in obj) {
349
+ delete obj[key]
350
+ }
351
+ }
352
+ }
353
+
354
+ /**
355
+ * 将字符串转为对象或数组
356
+ * @param str {string}
357
+ * @returns {Object | Array}
358
+ */
359
+ export function parse(str) {
360
+ if (isEmpty(str)) {
361
+ return {}
362
+ }
363
+
364
+ return JSON.parse(str)
365
+ }
366
+
367
+ /**
368
+ * 深度拷贝。如果非对象或数组,直接返回。
369
+ * @param obj {Object | Array}
370
+ * @return {Object | Array | any}
371
+ */
372
+ export function deepClone(obj) {
373
+ if (isObject(obj)) {
374
+ // return Object.assign({}, obj)
375
+ try {
376
+ return _.cloneDeep(obj);
377
+ } catch (err) {
378
+ console.error(err)
379
+ return {...obj}
380
+ }
381
+ }
382
+ if (isArray(obj)) {
383
+ // return Object.assign([], obj)
384
+ try {
385
+ return _.cloneDeep(obj);
386
+ } catch (err) {
387
+ console.error(err);
388
+ return [...obj];
389
+ }
390
+ }
391
+ return obj;
392
+ }
393
+
394
+ /**
395
+ * @description merge 策略: 将opt2 merge到opt1, 对于opt1已有的key-value, 默认不覆盖(可由predicate决定), 对于opt2中新的key-value, 追加到opt1中。传入
396
+ * deep值表示是否深度执行merge逻辑(不传入则为true). 函数将更改opt1的值, 同时返回opt1
397
+ * @param opt1 {Object} opt1中的k-v将保留。如果不是object类型或者是null类型,则直接返回op1
398
+ * @param opt2 {Object} 不会改变opt2。如果不是object类型或者是null类型,则直接返回op1
399
+ * @param deep {boolean} 是否深拷贝模式, 默认true
400
+ * @param ignoreNullAndUndefined {boolean} 若为true, 则当opt2中的键值如果是null或undefined, 则不会覆盖到opt1中。默认是false
401
+ * @param coverFn {Function} 具体k-v合并时的断言。当opt1, opt2有相同key时, 有时我们也希望能合并, 这时可以通过此参数来决定, 提供一个函数,参数: opt1, opt2, key, 返回true/false, 为true则表示也合并, 否则不合并
402
+ * @returns {Object} 返回merge后的opt1的深拷贝对象
403
+ */
404
+ export function merge(opt1, opt2, deep = true, ignoreNullAndUndefined = false, coverFn = (obj1, obj2, key, valueOfObj2) => {
405
+ }) {
406
+ if (opt1 === null || !isObject(opt1) || opt2 === null || !isObject(opt2)) {
407
+ return opt1;
408
+ }
409
+
410
+ const deepMerge = function (obj1, obj2) {
411
+ if (!isObject(obj1) || !isObject(obj2)) return;
412
+ for (let key in obj2) {
413
+ let valueOfObj1 = obj1[key]
414
+ let valueOfObj2 = obj2[key]
415
+
416
+ if (ignoreNullAndUndefined && (isUndefined(valueOfObj2) || isNull(valueOfObj2))) {
417
+ continue;
418
+ }
419
+
420
+ if (!(key in obj1)) {
421
+ obj1[key] = deepClone(valueOfObj2);
422
+ } else {
423
+ if (isObject(valueOfObj1) && isObject(valueOfObj2) && deep) {
424
+ deepMerge(valueOfObj1, valueOfObj2);
425
+ } else {
426
+ coverFn(obj1, obj2, key, valueOfObj2)
427
+ // obj1[key] = deepClone(valueOfObj2);
428
+ }
429
+ }
430
+ }
431
+ };
432
+
433
+ // deep merge
434
+ deepMerge(opt1, opt2);
435
+ return opt1;
436
+ }
437
+
438
+ /**
439
+ * 将opt2中key的值,赋值到opt1中的同名key上;若opt1上没有同名key则忽略。返回值更新后的opt1
440
+ * @description
441
+ * @param opt1 {Object}
442
+ * @param opt2 {Object}
443
+ * @param deep {boolean}
444
+ * @param ignoreNullAndUndefined {boolean}
445
+ */
446
+ export function mergeValue(opt1, opt2, deep = true, ignoreNullAndUndefined = false) {
447
+ if (opt1 === null || !isObject(opt1) || opt2 === null || !isObject(opt2)) {
448
+ return opt1;
449
+ }
450
+ const deepMerge = function (obj1, obj2) {
451
+ if (!isObject(obj1) || !isObject(obj2)) return;
452
+ for (let key in obj1) {
453
+ let valueOfObj1 = obj1[key]
454
+ if (!(key in obj2)) {
455
+ continue
456
+ }
457
+
458
+ let valueOfObj2 = obj2[key]
459
+ if (ignoreNullAndUndefined && (isUndefined(valueOfObj2) || isNull(valueOfObj2))) {
460
+ continue
461
+ }
462
+ if (isObject(valueOfObj1) && isObject(valueOfObj2) && deep) {
463
+ deepMerge(valueOfObj1, valueOfObj2)
464
+ }
465
+ obj1[key] = valueOfObj2
466
+ }
467
+ }
468
+ deepMerge(opt1, opt2)
469
+ return opt1
470
+ }
471
+
472
+ /**
473
+ * @description merge 策略2: 对两个对象中的属性和值执行merge操作, 将opt2中的key-value根据key merge到opt1上: 若op1也存在这个key,则取opt2这个key的值
474
+ * 覆盖到opt1上; 若opt1中不存在, 则会被直接追加到opt1中, 因此函数会更改opt1, 执行完后, opt1将是merge后的对象。最后将opt1的深拷贝返回
475
+ * @param opt1 {Object} opt1中的k-v将被覆盖。如果不是object类型或者是null类型,则直接返回op1
476
+ * @param opt2 {Object} 如果不是object类型或者是null类型,则直接返回op1
477
+ * @param deep {boolean} 是否深拷贝模式, 默认true
478
+ * @param ignoreNullAndUndefined {boolean} 若为true, 则当opt2中的键值如果是null或undefined, 则不会覆盖到opt1中。默认是false
479
+ * @returns {Object} 返回merge后的opt1的深拷贝对象
480
+ */
481
+ export function coverMerge(opt1, opt2, deep = true, ignoreNullAndUndefined = false) {
482
+ if (opt1 === null || !isObject(opt1) || opt2 === null || !isObject(opt2)) {
483
+ return opt1;
484
+ }
485
+
486
+ const deepMerge = function (obj1, obj2) {
487
+ if (!isObject(obj1) || !isObject(obj2)) return;
488
+ for (let key in obj2) {
489
+ let valueOfObj1 = obj1[key]
490
+ let valueOfObj2 = obj2[key]
491
+
492
+ if (ignoreNullAndUndefined && (isUndefined(valueOfObj2) || isNull(valueOfObj2))) {
493
+ continue
494
+ }
495
+
496
+ if (key in obj1) {
497
+ if (isObject(valueOfObj1) && isObject(valueOfObj2) && deep) {
498
+ deepMerge(valueOfObj1, valueOfObj2)
499
+ } else {
500
+ obj1[key] = deepClone(valueOfObj2)
501
+ }
502
+ } else {
503
+ obj1[key] = deepClone(valueOfObj2)
504
+ }
505
+ }
506
+ }
507
+
508
+ deepMerge(opt1, opt2);
509
+ return opt1;
510
+ }
511
+
512
+ /**
513
+ * 解析语法彩蛋条件
514
+ * @param cond
515
+ * @param optMapping
516
+ * @return {*}
517
+ */
518
+ export function easyOptParse(cond, optMapping = {}) {
519
+ for (const [reg, obj] of Object.entries(optMapping)) {
520
+ const regex = new RegExp(reg);
521
+ const {opt, valExtract} = obj
522
+ if (regex.test(cond.val)) {
523
+ cond.opt = opt
524
+ cond.val = valExtract(cond)
525
+ break
526
+ }
527
+ }
528
+ return cond;
529
+ }
530
+
531
+ /**
532
+ * 向数组中去重添加元素, 如果重复, 则以item覆盖重复的元素(保持位置)。如果不存在重复元素,则添加,根据addToStart参数决定添加到数组的开头还是结尾(push/unshift)
533
+ * @param arr 数组
534
+ * @param item 待添加的元素
535
+ * @param repeatPredicate 去重断言函数, 返回去重判断的结果值(true/false)
536
+ * @param addToStart 添加到数组的开头还是结果(push/unshift)
537
+ */
538
+ export function noRepeatAdd(arr, item, repeatPredicate = (ele, item) => ele === item, addToStart = false) {
539
+ if (!isArray(arr)) {
540
+ return;
541
+ }
542
+ let existRepeat = false;
543
+ for (let i = 0; i < arr.length; i++) {
544
+ if (repeatPredicate(arr[i], item)) {
545
+ existRepeat = true;
546
+ arr.splice(i, 1, item);
547
+ }
548
+ }
549
+ if (!existRepeat) {
550
+ addToStart ? arr.unshift(item) : arr.push(item);
551
+ }
552
+ }
553
+
554
+ export function getNameFromUrl(url) {
555
+ const decodeUrl = decodeURIComponent(url);
556
+ const lastSlashIndex = decodeUrl.lastIndexOf('/');
557
+ const lastBackslashIndex = decodeUrl.lastIndexOf('\\');
558
+ const lastIndex = Math.max(lastSlashIndex, lastBackslashIndex);
559
+ if (lastIndex === -1) {
560
+ return decodeUrl;
561
+ }
562
+ return decodeUrl.substring(lastIndex + 1);
563
+ }
564
+
565
+ /**
566
+ * 从fileItems中获取第一个url。
567
+ * @param fileItems 期望是[{name:'', url:''}, ..],如果非数组或空数组,返回null; 为数组则取首个元素,首个元素为对象类型,取url属性返回, 否则直接返回
568
+ * @returns {*|null}
569
+ */
570
+ export function getFirstUrlFromFileItems(fileItems) {
571
+ if (!isArray(fileItems) || fileItems.length === 0) {
572
+ return null;
573
+ }
574
+ const firstItem = fileItems[0];
575
+ if (isObject(firstItem)) {
576
+ return firstItem.url;
577
+ }
578
+ return firstItem; // 直接视为url
579
+ }
580
+
581
+ /**
582
+ * 获取元素的完整高度, 包括offsetHeight + 上下margin值
583
+ * @param ele
584
+ */
585
+ export function getFullHeight(ele) {
586
+ if (isUndefined(ele)) {
587
+ return 0;
588
+ }
589
+ const style = window.getComputedStyle(ele);
590
+ const marginTop = parseFloat(style.marginTop) || 0;
591
+ const marginBottom = parseFloat(style.marginBottom) || 0;
592
+ return ele.offsetHeight + marginTop + marginBottom;
593
+ }
594
+
595
+ /**
596
+ * 获取元素内部高度, 内高
597
+ * @param ele
598
+ * @returns {number}
599
+ */
600
+ export function getInnerHeight(ele) {
601
+ if (isUndefined(ele)) {
602
+ return 0;
603
+ }
604
+ const style = window.getComputedStyle(ele);
605
+ const paddingTop = parseFloat(style.paddingTop) || 0;
606
+ const paddingBottom = parseFloat(style.paddingBottom) || 0;
607
+ return ele.clientHeight - (paddingTop + paddingBottom);
608
+ }
609
+
610
+ /**
611
+ * 按前匹配或后匹配替换对象的键名。例如obj中有name_q, str为_q, 则替换后返回的对象里name_q变成name
612
+ * @param obj 对象
613
+ * @param str 前缀或后缀
614
+ * @param position 匹配位置. start: 前缀, end: 后缀。不传默认是end
615
+ * @returns {{}}
616
+ */
617
+ export function replaceKey(obj, str, position = 'end') {
618
+ if (!isObject(obj)) {
619
+ throw new Error("replaceKey: obj is not an object");
620
+ }
621
+ if (!isString(str)) {
622
+ throw new Error("replaceKey: str is not a string");
623
+ }
624
+ const result = {};
625
+
626
+ Object.keys(obj).forEach((key) => {
627
+ let newKey = key;
628
+
629
+ if (position === "start" && key.startsWith(str)) {
630
+ newKey = key.slice(str.length); // 去掉开头的字符串
631
+ } else if (position === "end" && key.endsWith(str)) {
632
+ newKey = key.slice(0, -str.length); // 去掉末尾的字符串
633
+ }
634
+
635
+ result[newKey] = obj[key];
636
+ });
637
+
638
+ return result;
639
+ }
640
+
641
+ /**
642
+ * 超出指定长度则超出部分转换为...
643
+ * @param val
644
+ * @param len
645
+ * @returns {string|*}
646
+ */
647
+ export const ellipsis = function (val, len) {
648
+ if (isEmpty(val) || !isString(val)) return '';
649
+ if (!isNumber(len)) {
650
+ console.warn('The "ellipsis" filter requires a numeric second argument as the maxLength.');
651
+ return val;
652
+ }
653
+
654
+ return val.length > len ? val.slice(0, len) + '...' : val;
655
+ }
656
+
657
+ /**
658
+ * 日期格式化
659
+ * @param val
660
+ * @param format
661
+ * @returns {string}
662
+ */
663
+ export const dateFormat = function (val, format) {
664
+ const date = new Date(val)
665
+ const adjustFormat = format.replace(/yyyy/g, 'YYYY').replace(/dd/g, 'DD')
666
+ return moment(date).format(adjustFormat)
667
+ }
668
+
669
+ /**
670
+ * 获取指定时间当天起始时间
671
+ * @param date 若为空,则取当前时间
672
+ * @return {Date}
673
+ */
674
+ export const getBeginOfDate = function (date) {
675
+ let d
676
+ if (isEmpty(date)) {
677
+ d = new Date()
678
+ } else {
679
+ d = _.cloneDeep(date)
680
+ }
681
+ d.setHours(0, 0, 0, 0)
682
+ return d
683
+ }
684
+
685
+ /**
686
+ * 获取指定时间当周起始时间
687
+ * @param date
688
+ * @return {Date}
689
+ */
690
+ export const getBeginOfWeek = function (date) {
691
+ let d
692
+ if (isEmpty(date)) {
693
+ d = new Date()
694
+ } else {
695
+ d = _.cloneDeep(date)
696
+ }
697
+ const day = d.getDay();
698
+ const diff = d.getDate() - day + (day === 0 ? -6 : 1)
699
+ d.setDate(diff)
700
+ d.setHours(0, 0, 0, 0)
701
+ return d
702
+ }
703
+
704
+ /**
705
+ * 获取指定时间当月起始时间
706
+ * @param date
707
+ */
708
+ export const getBeginOfMonth = function (date) {
709
+ let d
710
+ if (isEmpty(date)) {
711
+ d = new Date()
712
+ } else {
713
+ d = _.cloneDeep(date)
714
+ }
715
+ d.setDate(1); // 设置为当月的 1 号
716
+ d.setHours(0, 0, 0, 0);
717
+ return d
718
+ }
719
+
720
+ /**
721
+ * 从属性key中提取事件名。例如: onChange 提取出来就是change
722
+ * @param key
723
+ * @return {string|null}
724
+ */
725
+ export function extractEventName(key) {
726
+ if (isEmpty(key) || !key.startsWith('on')) return null;
727
+ const raw = key.slice(2);
728
+ return raw.charAt(0).toLowerCase() + raw.slice(1); // 保留驼峰
729
+ }
730
+
731
+ /**
732
+ * 生成css grid布局中的gridTemplateAreas值
733
+ * @param rowNum 每行的数量
734
+ * @param totalItems 对象数组或者普通数组, 如果是对象数组, 则判断每个元素是否含有block, 若含有则将当前行全部命名为相同的区域名;若非对象数组或者不含有block则维持原逻辑
735
+ * @return {string} 可直接用于grid-template-areas
736
+ */
737
+ export function buildGridTemplateAreas(rowNum, totalItems) {
738
+ const rows = [];
739
+ let rowCharCode = 97; // 'a'
740
+ let count = 0;
741
+
742
+ while (count < totalItems.length) {
743
+ const row = [];
744
+ const item = totalItems[count];
745
+
746
+ if (item && typeof item === 'object' && item.block) {
747
+ // 整行都是同一块,rowNum 列都填相同区域名
748
+ for (let j = 0; j < rowNum; j++) {
749
+ row.push(String.fromCharCode(rowCharCode) + (j + 1));
750
+ }
751
+ count += 1; // block行只占1个元素
752
+ } else {
753
+ // 普通行,按照原逻辑填充
754
+ for (let j = 0; j < rowNum; j++) {
755
+ row.push(String.fromCharCode(rowCharCode) + (j + 1));
756
+ count++;
757
+ }
758
+ }
759
+
760
+ rows.push(`"${row.join(' ')}"`);
761
+ rowCharCode++;
762
+ }
763
+
764
+ return rows.join('\n');
765
+ }
766
+
767
+ /**
768
+ * 将str中的插值替换为obj中的真实值。例如"/user?id={id}" 则将取obj中的id属性值替换为 "/user?id=2"
769
+ * @param str
770
+ * @param obj
771
+ */
772
+ export function strFormat(str, obj) {
773
+ if (!isString(str)) return str
774
+ return str.replace(/{(.*?)}/g, (_, key) => {
775
+ const val = obj[key.trim()]
776
+ // 如果没有找到值,就原样返回占位符
777
+ return !isUndefined(val) && !isNull(val) ? val : `{${key}}`
778
+ })
779
+ }
780
+
781
+ /**
782
+ * 提取 URL 字符串中的 query 参数为对象
783
+ * @param {string} url
784
+ * @returns {Object} path和query为key组成的对象, 注意: 入参url若不是/开头,则返回的path值也不是/开头
785
+ */
786
+ export function extractUrlAndQueryParams(url) {
787
+ const defaultResult = {path: url, query: {}}
788
+ if (isEmpty(url)) {
789
+ return defaultResult
790
+ }
791
+ const beginSlash = url.startsWith('/')
792
+ try {
793
+ // 如果传的是相对路径(/user?...),拼一个基准域名
794
+ const fullUrl = isUrl(url) ? url : window.location.origin + (beginSlash ? url : '/' + url)
795
+ const u = new URL(fullUrl)
796
+ const query = {}
797
+ for (const [key, value] of u.searchParams.entries()) {
798
+ query[key] = value
799
+ }
800
+ return {
801
+ path: beginSlash ? u.pathname : cutPrefix(u.pathname, '/'),
802
+ query: query
803
+ }
804
+ } catch (e) {
805
+ console.error('extractQueryParams error:', e)
806
+ return defaultResult
807
+ }
808
+ }
809
+
810
+
811
+ /**
812
+ * 判断版本号是否大于等于目标版本, 若某个位不为数字,则视为0
813
+ * @param {string} current 当前版本号,如 "2.9.8"
814
+ * @param {string} target 目标版本号,如 "2.9.9"
815
+ * @returns {boolean} 当前版本 >= 目标版本 返回 true,否则 false
816
+ */
817
+ export function versionGte(current, target) {
818
+ if (isEmpty(target)) {
819
+ return true
820
+ }
821
+ if (isEmpty(current)) {
822
+ return false
823
+ }
824
+ const parse = (v) => v.split('.').map((n) => {
825
+ try {
826
+ return parseInt(n, 10)
827
+ } catch (err) {
828
+ return 0
829
+ }
830
+ });
831
+ const cur = parse(current);
832
+ const tar = parse(target);
833
+ // 补齐三位
834
+ while (cur.length < 3) cur.push(0);
835
+ while (tar.length < 3) tar.push(0);
836
+
837
+ for (let i = 0; i < 3; i++) {
838
+ if (cur[i] > tar[i]) return true;
839
+ if (cur[i] < tar[i]) return false;
840
+ // 相等就继续下一位比较
841
+ }
842
+ return true; // 完全相等也算 >=
843
+ }
844
+
845
+ /**
846
+ * 转义值为label
847
+ * @param val 单个值或数组
848
+ * @param options
849
+ * @param valKey
850
+ * @param labelKey
851
+ * @return {*} 如果是数组返回的label值也是数据
852
+ */
853
+ export function escapeLabel(val, options, valKey, labelKey) {
854
+ if (isArray(val)) {
855
+ return val.map(v => escapeLabel(v, options, valKey, labelKey))
856
+ } else {
857
+ try {
858
+ const option = options.find(o => o[valKey] === val)
859
+ if (option) {
860
+ return option[labelKey] || val
861
+ }
862
+ return val
863
+ } catch (err) {
864
+ console.error(err)
865
+ return val // 降级显示原本的值
866
+ }
867
+ }
868
+ }
869
+
870
+
871
+ /**
872
+ * 递归地对对象的键进行排序
873
+ * * @param {*} obj
874
+ * @returns {*}
875
+ */
876
+ export function sortKey(obj) {
877
+ if (typeof obj !== 'object' || obj === null) {
878
+ return obj;
879
+ }
880
+ if (Array.isArray(obj)) {
881
+ // 递归处理数组中的对象
882
+ return obj.map(sortKey);
883
+ }
884
+
885
+ // 对对象属性名进行排序
886
+ const sortedKeys = Object.keys(obj).sort();
887
+ const sortedObject = {};
888
+ for (const key of sortedKeys) {
889
+ sortedObject[key] = sortKey(obj[key]);
890
+ }
891
+ return sortedObject;
892
+ }