fast-crud-ui3 1.5.16 → 1.5.17
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/lib/assets/fonts/iconfont.d.ts +0 -0
- package/lib/components/checkbox-group/index.d.ts +2 -0
- package/lib/components/checkbox-group/src/fast-checkbox-group.d.ts +72 -0
- package/lib/components/content-dialog/index.d.ts +2 -0
- package/lib/components/content-dialog/src/fast-cell-content.d.ts +83 -0
- package/lib/components/json-viewer/index.d.ts +2 -0
- package/lib/components/json-viewer/src/fast-json-viewer.d.ts +48 -0
- package/lib/components/mapping.d.ts +5 -0
- package/lib/components/object-picker/index.d.ts +2 -0
- package/lib/components/object-picker/src/fast-object-picker.d.ts +132 -0
- package/lib/components/select/index.d.ts +2 -0
- package/lib/components/select/src/fast-select.d.ts +83 -0
- package/lib/components/table/index.d.ts +2 -0
- package/lib/components/table/src/RowConfirm.d.ts +39 -0
- package/lib/components/table/src/dynamic-filter-form.d.ts +118 -0
- package/lib/components/table/src/dynamic-filter-list.d.ts +57 -0
- package/lib/components/table/src/easy-filter.d.ts +118 -0
- package/lib/components/table/src/export-confirm.d.ts +12 -0
- package/lib/components/table/src/quick-filter-form.d.ts +42 -0
- package/lib/components/table/src/row-form.d.ts +33 -0
- package/lib/components/table/src/stored-filter-manager.d.ts +55 -0
- package/lib/components/table/src/stored-filter.d.ts +37 -0
- package/lib/components/table/src/table-head-cell.d.ts +9 -0
- package/lib/components/table/src/table.d.ts +507 -0
- package/lib/components/table/src/util.d.ts +77 -0
- package/lib/components/table-column/config.d.ts +5 -0
- package/lib/components/table-column/index.d.ts +2 -0
- package/lib/components/table-column/src/table-column.d.ts +256 -0
- package/lib/components/table-column-date-picker/config.d.ts +5 -0
- package/lib/components/table-column-date-picker/index.d.ts +2 -0
- package/lib/components/table-column-date-picker/src/table-column-date-picker.d.ts +173 -0
- package/lib/components/table-column-file/config.d.ts +5 -0
- package/lib/components/table-column-file/index.d.ts +2 -0
- package/lib/components/table-column-file/src/table-column-file.d.ts +285 -0
- package/lib/components/table-column-img/config.d.ts +5 -0
- package/lib/components/table-column-img/index.d.ts +2 -0
- package/lib/components/table-column-img/src/table-column-img.d.ts +285 -0
- package/lib/components/table-column-input/config.d.ts +5 -0
- package/lib/components/table-column-input/index.d.ts +2 -0
- package/lib/components/table-column-input/src/table-column-input.d.ts +173 -0
- package/lib/components/table-column-number/config.d.ts +5 -0
- package/lib/components/table-column-number/index.d.ts +2 -0
- package/lib/components/table-column-number/src/table-column-number.d.ts +173 -0
- package/lib/components/table-column-object/config.d.ts +5 -0
- package/lib/components/table-column-object/index.d.ts +2 -0
- package/lib/components/table-column-object/src/table-column-object.d.ts +315 -0
- package/lib/components/table-column-select/config.d.ts +5 -0
- package/lib/components/table-column-select/index.d.ts +2 -0
- package/lib/components/table-column-select/src/table-column-select.d.ts +276 -0
- package/lib/components/table-column-switch/config.d.ts +5 -0
- package/lib/components/table-column-switch/index.d.ts +2 -0
- package/lib/components/table-column-switch/src/table-column-switch.d.ts +175 -0
- package/lib/components/table-column-textarea/config.d.ts +5 -0
- package/lib/components/table-column-textarea/index.d.ts +2 -0
- package/lib/components/table-column-textarea/src/table-column-textarea.d.ts +173 -0
- package/lib/components/table-column-time-picker/config.d.ts +5 -0
- package/lib/components/table-column-time-picker/index.d.ts +2 -0
- package/lib/components/table-column-time-picker/src/table-column-time-picker.d.ts +173 -0
- package/lib/components/upload/index.d.ts +2 -0
- package/lib/components/upload/src/fast-upload.d.ts +120 -0
- package/lib/fast-crud-ui3.cjs.js +44 -17
- package/lib/fast-crud-ui3.es.js +9978 -5939
- package/lib/fast-crud-ui3.umd.js +44 -17
- package/lib/global.d.ts +42 -0
- package/lib/index.d.ts +56 -0
- package/lib/mixins/table-column.d.ts +104 -0
- package/lib/mixins/upload.d.ts +15 -0
- package/lib/model/cond.d.ts +48 -0
- package/lib/model/editComponentConfig.d.ts +25 -0
- package/lib/model/fastTableOption.d.ts +510 -0
- package/lib/model/filterComponentConfig.d.ts +55 -0
- package/lib/model/opt.d.ts +20 -0
- package/lib/model/order.d.ts +28 -0
- package/lib/model/pageQuery.d.ts +43 -0
- package/lib/model/query.d.ts +101 -0
- package/lib/model/rel.d.ts +5 -0
- package/lib/style.css +1 -1
- package/lib/util/cache.d.ts +17 -0
- package/lib/util/dialog.d.ts +49 -0
- package/lib/util/escape.d.ts +7 -0
- package/lib/util/http.d.ts +8 -0
- package/lib/util/pick.d.ts +9 -0
- package/lib/util/util.d.ts +311 -0
- package/package.json +19 -5
- package/packages/assets/fonts/iconfont.css +163 -0
- package/packages/assets/fonts/iconfont.js +1 -0
- package/packages/assets/fonts/iconfont.ttf +0 -0
- package/packages/assets/fonts/iconfont.woff +0 -0
- package/packages/assets/fonts/iconfont.woff2 +0 -0
- package/packages/components/checkbox-group/index.js +7 -0
- package/packages/components/checkbox-group/src/fast-checkbox-group.vue +83 -0
- package/packages/components/content-dialog/index.js +7 -0
- package/packages/components/content-dialog/src/fast-cell-content.vue +115 -0
- package/packages/components/json-viewer/index.js +7 -0
- package/packages/components/json-viewer/src/fast-json-viewer.vue +54 -0
- package/packages/components/mapping.js +95 -0
- package/packages/components/object-picker/index.js +7 -0
- package/packages/components/object-picker/src/fast-object-picker.vue +170 -0
- package/packages/components/select/index.js +7 -0
- package/packages/components/select/src/fast-select.vue +89 -0
- package/packages/components/table/index.js +7 -0
- package/packages/components/table/src/RowConfirm.vue +87 -0
- package/packages/components/table/src/dynamic-filter-form.vue +253 -0
- package/packages/components/table/src/dynamic-filter-list.vue +172 -0
- package/packages/components/table/src/easy-filter.vue +129 -0
- package/packages/components/table/src/export-confirm.vue +55 -0
- package/packages/components/table/src/quick-filter-form.vue +140 -0
- package/packages/components/table/src/row-form.vue +137 -0
- package/packages/components/table/src/stored-filter-manager.vue +240 -0
- package/packages/components/table/src/stored-filter.vue +180 -0
- package/packages/components/table/src/table-head-cell.vue +41 -0
- package/packages/components/table/src/table.vue +1309 -0
- package/packages/components/table/src/util.js +496 -0
- package/packages/components/table-column/config.js +64 -0
- package/packages/components/table-column/index.js +7 -0
- package/packages/components/table-column/src/table-column.vue +44 -0
- package/packages/components/table-column-date-picker/config.js +139 -0
- package/packages/components/table-column-date-picker/index.js +7 -0
- package/packages/components/table-column-date-picker/src/table-column-date-picker.vue +54 -0
- package/packages/components/table-column-file/config.js +83 -0
- package/packages/components/table-column-file/index.js +7 -0
- package/packages/components/table-column-file/src/table-column-file.vue +79 -0
- package/packages/components/table-column-img/config.js +83 -0
- package/packages/components/table-column-img/index.js +7 -0
- package/packages/components/table-column-img/src/table-column-img.vue +82 -0
- package/packages/components/table-column-input/config.js +77 -0
- package/packages/components/table-column-input/index.js +7 -0
- package/packages/components/table-column-input/src/table-column-input.vue +60 -0
- package/packages/components/table-column-number/config.js +89 -0
- package/packages/components/table-column-number/index.js +7 -0
- package/packages/components/table-column-number/src/table-column-number.vue +54 -0
- package/packages/components/table-column-object/config.js +66 -0
- package/packages/components/table-column-object/index.js +7 -0
- package/packages/components/table-column-object/src/table-column-object.vue +75 -0
- package/packages/components/table-column-select/config.js +66 -0
- package/packages/components/table-column-select/index.js +7 -0
- package/packages/components/table-column-select/src/table-column-select.vue +101 -0
- package/packages/components/table-column-switch/config.js +55 -0
- package/packages/components/table-column-switch/index.js +7 -0
- package/packages/components/table-column-switch/src/table-column-switch.vue +82 -0
- package/packages/components/table-column-textarea/config.js +77 -0
- package/packages/components/table-column-textarea/index.js +7 -0
- package/packages/components/table-column-textarea/src/table-column-textarea.vue +56 -0
- package/packages/components/table-column-time-picker/config.js +62 -0
- package/packages/components/table-column-time-picker/index.js +7 -0
- package/packages/components/table-column-time-picker/src/table-column-time-picker.vue +53 -0
- package/packages/components/upload/index.js +7 -0
- package/packages/components/upload/src/fast-upload.vue +272 -0
- package/packages/global.d.ts +42 -0
- package/packages/index.js +145 -0
- package/packages/mixins/table-column.js +133 -0
- package/packages/mixins/upload.js +14 -0
- package/packages/model/cond.js +74 -0
- package/packages/model/editComponentConfig.js +72 -0
- package/packages/model/fastTableOption.js +761 -0
- package/packages/model/filterComponentConfig.js +191 -0
- package/packages/model/opt.js +21 -0
- package/packages/model/order.js +37 -0
- package/packages/model/pageQuery.js +52 -0
- package/packages/model/query.js +161 -0
- package/packages/model/rel.js +5 -0
- package/packages/style.scss +5 -0
- package/packages/util/cache.js +92 -0
- package/packages/util/dialog.js +133 -0
- package/packages/util/escape.js +34 -0
- package/packages/util/http.js +18 -0
- package/packages/util/pick.js +92 -0
- 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
|
+
}
|