vue-super-crud 1.7.2 → 1.8.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.
- package/lib/index.css +1 -1
- package/lib/super-crud.min.js +2 -2
- package/package.json +1 -1
- package/src/config/common.js +3 -1
- package/src/config/crud.js +28 -4
- package/src/index.js +16 -11
- package/src/template/formatData.js +83 -86
package/package.json
CHANGED
package/src/config/common.js
CHANGED
@@ -9,8 +9,9 @@ export const renderItem = {
|
|
9
9
|
},
|
10
10
|
dict: {
|
11
11
|
strict: true,
|
12
|
-
type: [String, Object],
|
12
|
+
type: [String, Object, Function],
|
13
13
|
properties: {
|
14
|
+
key: String,
|
14
15
|
request: Function,
|
15
16
|
label: String, // 数据字典中label字段的属性名
|
16
17
|
value: String, // 数据字典中value字段的属性名
|
@@ -54,6 +55,7 @@ export const renderItem = {
|
|
54
55
|
},
|
55
56
|
}, // 验证规则
|
56
57
|
position: Boolean, // 是否开启位置渲染
|
58
|
+
formatData: [Object, String], // 响应式数据格式化
|
57
59
|
};
|
58
60
|
|
59
61
|
export const buttonItem = {
|
package/src/config/crud.js
CHANGED
@@ -77,6 +77,30 @@ export default {
|
|
77
77
|
type: String,
|
78
78
|
default: "small",
|
79
79
|
},
|
80
|
+
persistPageSize: Boolean, // 是否持久化拖动宽度
|
81
|
+
persistWidth: Boolean, // 是否持久化拖动宽度
|
82
|
+
delayRender: Boolean, // 是否启用延迟渲染
|
83
|
+
delayRenderConfig: {
|
84
|
+
// 延迟渲染配置
|
85
|
+
type: [Boolean, Object],
|
86
|
+
default: () => ({
|
87
|
+
batchSize: 16,
|
88
|
+
maxProcessTime: 16,
|
89
|
+
frameDelay: 2,
|
90
|
+
strategy: "cell",
|
91
|
+
}),
|
92
|
+
properties: {
|
93
|
+
batchSize: Number, // 每批处理的元素数量,数值越大渲染越快,但可能导致卡顿
|
94
|
+
maxProcessTime: Number, // 每帧最大处理时间(ms),防止单帧处理时间过长
|
95
|
+
frameDelay: Number, // 批次间的帧间隔,数值越大越平滑,但渲染完成时间越长
|
96
|
+
},
|
97
|
+
}, // 是否启用延迟渲染
|
98
|
+
virtualized: Boolean, // 是否启用虚拟列表
|
99
|
+
itemSize: {
|
100
|
+
// 延迟渲染、虚拟列表的固定行高
|
101
|
+
type: Number,
|
102
|
+
default: 40,
|
103
|
+
},
|
80
104
|
summaryData: Array, // 外部传入的统计数据
|
81
105
|
// 是否禁用
|
82
106
|
disabled: Boolean,
|
@@ -140,6 +164,7 @@ export default {
|
|
140
164
|
},
|
141
165
|
},
|
142
166
|
}),
|
167
|
+
addChild: buttonItem, // 子级新增按钮配置
|
143
168
|
batchDelete: buttonItem, // 批量删除按钮配置
|
144
169
|
delete: buttonItem, // 删除按钮配置
|
145
170
|
view: buttonItem, // 查看按钮配置,仅限`dialog`模式
|
@@ -250,9 +275,6 @@ export default {
|
|
250
275
|
default: () => ({
|
251
276
|
pageNum: "pageNum",
|
252
277
|
pageSize: "pageSize",
|
253
|
-
detailResult: "data",
|
254
|
-
listResult: "data",
|
255
|
-
total: "total",
|
256
278
|
}),
|
257
279
|
},
|
258
280
|
// 是否本地生成唯一标识
|
@@ -281,7 +303,6 @@ export default {
|
|
281
303
|
type: [Boolean, Object],
|
282
304
|
default: () => ({
|
283
305
|
show: true,
|
284
|
-
width: 290,
|
285
306
|
resetBtn: true,
|
286
307
|
}),
|
287
308
|
properties: {
|
@@ -337,6 +358,7 @@ export default {
|
|
337
358
|
layout: "total, sizes, prev, pager, next, jumper",
|
338
359
|
background: true,
|
339
360
|
pagerCount: 5,
|
361
|
+
memorizeScroll: true, // 临时保存分页滚动位置
|
340
362
|
}),
|
341
363
|
},
|
342
364
|
// 空状态配置
|
@@ -405,6 +427,7 @@ export default {
|
|
405
427
|
calcWidth: Number,
|
406
428
|
defaultWidth: Number,
|
407
429
|
sameRowSpan: [String, Boolean],
|
430
|
+
spanProp: [String, Boolean],
|
408
431
|
fixed: [String, Boolean],
|
409
432
|
handles: {
|
410
433
|
type: Array,
|
@@ -465,6 +488,7 @@ export default {
|
|
465
488
|
hiddenList: Boolean, // 是否只隐藏列表
|
466
489
|
children: Array, // 嵌套列子列
|
467
490
|
sameRowSpan: [String, Boolean], // 是否合并单元格
|
491
|
+
spanProp: [String, Boolean], // 是否合并单元格
|
468
492
|
spanMethod: Function, // 合并单元格方法
|
469
493
|
isEdit: [Boolean, Function], // 是否允许编辑
|
470
494
|
summary: {
|
package/src/index.js
CHANGED
@@ -12,6 +12,9 @@ import tabs from "pak/tabs";
|
|
12
12
|
import verifyInput from "pak/verifyInput";
|
13
13
|
import button from "pak/button";
|
14
14
|
import position from "pak/core/components/position";
|
15
|
+
import grid from "pak/grid/index.vue";
|
16
|
+
import cell from "pak/grid/cell.vue";
|
17
|
+
import lazyRender from "pak/lazyRender/index.vue";
|
15
18
|
|
16
19
|
import { mergeTemplate } from "./template";
|
17
20
|
import directive from "pak/directive";
|
@@ -33,28 +36,30 @@ const components = [
|
|
33
36
|
verifyInput,
|
34
37
|
button,
|
35
38
|
position,
|
39
|
+
grid,
|
40
|
+
cell,
|
41
|
+
lazyRender,
|
36
42
|
];
|
37
43
|
|
38
44
|
const install = function (Vue, opts = {}) {
|
39
45
|
// 判断是否安装
|
40
46
|
if (install.installed) return;
|
41
47
|
install.installed = true;
|
42
|
-
if (opts.template) {
|
43
|
-
mergeTemplate(opts.template);
|
44
|
-
}
|
45
|
-
window.Vue = Vue;
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
Vue.prototype.$scDict = globalDict(Vue, opts.dict || {});
|
49
|
+
// 合并外部代码模板
|
50
|
+
opts.template && mergeTemplate(opts.template);
|
50
51
|
|
52
|
+
// 初始化配置管理器
|
51
53
|
configManager.create(config, opts);
|
52
|
-
|
54
|
+
|
53
55
|
// 遍历注册全局组件
|
54
|
-
components.forEach((component) =>
|
55
|
-
|
56
|
-
|
56
|
+
components.forEach((component) => Vue.component(component.name, component));
|
57
|
+
|
58
|
+
Vue.prototype.$scOpt = opts;
|
59
|
+
Vue.prototype.$scDialog = dialog;
|
60
|
+
Vue.prototype.$scDict = globalDict(Vue, opts.dict || {});
|
57
61
|
directive(Vue);
|
62
|
+
window.Vue = Vue;
|
58
63
|
};
|
59
64
|
|
60
65
|
// 判断是否是直接引入文件
|
@@ -241,12 +241,11 @@ export default {
|
|
241
241
|
numberFormat: (item) => {
|
242
242
|
const config = {
|
243
243
|
precision: 2, // 精度(小数位数)
|
244
|
-
round:
|
244
|
+
round: false, // 是否四舍五入
|
245
245
|
toFixed: false, // 是否固定小数位数
|
246
246
|
thousandth: false, // 是否显示千分位
|
247
247
|
prefix: "", // 前缀
|
248
248
|
suffix: "", // 后缀
|
249
|
-
keepZero: false, // 是否保留末尾0
|
250
249
|
...(get(item, "formatData") || item),
|
251
250
|
};
|
252
251
|
|
@@ -258,23 +257,50 @@ export default {
|
|
258
257
|
};
|
259
258
|
|
260
259
|
// 处理数字精度
|
261
|
-
const formatPrecision = (num) => {
|
260
|
+
const formatPrecision = (num, originalStr = "") => {
|
262
261
|
if (typeof num !== "number") return num;
|
262
|
+
let result;
|
263
|
+
if (config.precision !== 0) {
|
264
|
+
const endsWithDot = originalStr.endsWith(".");
|
265
|
+
// 检查原始字符串是否以0结尾的小数
|
266
|
+
const endsWithZero =
|
267
|
+
originalStr.includes(".") && originalStr.endsWith("0");
|
268
|
+
const decimalPlaces = endsWithZero
|
269
|
+
? originalStr.split(".")[1].length
|
270
|
+
: 0;
|
271
|
+
|
272
|
+
// 使用字符串操作来保持精确度
|
273
|
+
const numStr = String(num);
|
274
|
+
const parts = numStr.split(".");
|
275
|
+
if (parts.length > 1) {
|
276
|
+
const integerPart = parts[0];
|
277
|
+
const decimalPart = parts[1];
|
278
|
+
if (config.round) {
|
279
|
+
result = Number(Number(num).toFixed(config.precision));
|
280
|
+
} else {
|
281
|
+
// 直接截取所需的小数位数
|
282
|
+
result = Number(
|
283
|
+
integerPart + "." + decimalPart.slice(0, config.precision)
|
284
|
+
);
|
285
|
+
}
|
286
|
+
} else {
|
287
|
+
result = num;
|
288
|
+
}
|
263
289
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
if (!config.keepZero) {
|
274
|
-
num = String(Number(num));
|
290
|
+
// 如果原始输入以0结尾,使用原始小数位数
|
291
|
+
if (endsWithZero && !config.toFixed) {
|
292
|
+
result = Number(result).toFixed(
|
293
|
+
Math.min(config.precision, decimalPlaces)
|
294
|
+
);
|
295
|
+
} else if (endsWithDot && !String(result).includes(".")) {
|
296
|
+
result = result + ".";
|
297
|
+
} else if (config.toFixed) {
|
298
|
+
result = Number(result).toFixed(config.precision);
|
275
299
|
}
|
300
|
+
} else {
|
301
|
+
result = Number(num).toFixed(0);
|
276
302
|
}
|
277
|
-
return
|
303
|
+
return result;
|
278
304
|
};
|
279
305
|
|
280
306
|
// 处理多个小数点的情况(只保留第一个)
|
@@ -289,6 +315,11 @@ export default {
|
|
289
315
|
|
290
316
|
return {
|
291
317
|
input: (value) => {
|
318
|
+
// 处理空值情况
|
319
|
+
if (value === undefined || value === null || value === "") {
|
320
|
+
return "";
|
321
|
+
}
|
322
|
+
|
292
323
|
try {
|
293
324
|
let rawStr = "";
|
294
325
|
if (typeof value === "string") {
|
@@ -297,25 +328,15 @@ export default {
|
|
297
328
|
rawStr = String(value);
|
298
329
|
}
|
299
330
|
|
300
|
-
// 校验是否为有效的数字格式(允许负号和小数点)
|
301
|
-
if (!/^-?\d*\.?\d*$/.test(rawStr)) {
|
302
|
-
return value;
|
303
|
-
}
|
304
|
-
|
305
|
-
// 检查原始字符串是否以小数点结尾
|
306
|
-
const endsWithDot = rawStr.endsWith(".");
|
307
|
-
|
308
331
|
const num = Number(rawStr);
|
332
|
+
// 如果转换后是 NaN,返回空字符串
|
309
333
|
if (isNaN(num)) {
|
310
|
-
return
|
334
|
+
return "";
|
311
335
|
}
|
312
|
-
let formatted = formatPrecision(num);
|
313
|
-
formatted = String(formatted);
|
314
336
|
|
315
|
-
//
|
316
|
-
|
317
|
-
|
318
|
-
}
|
337
|
+
// 传入原始字符串,用于处理特殊情况
|
338
|
+
let formatted = formatPrecision(num, rawStr);
|
339
|
+
formatted = String(formatted);
|
319
340
|
|
320
341
|
if (config.thousandth) {
|
321
342
|
formatted = formatThousandth(formatted);
|
@@ -324,7 +345,7 @@ export default {
|
|
324
345
|
return `${config.prefix}${formatted}${config.suffix}`;
|
325
346
|
} catch (error) {
|
326
347
|
console.warn("数字格式化失败:", error);
|
327
|
-
return
|
348
|
+
return "";
|
328
349
|
}
|
329
350
|
},
|
330
351
|
// 输出时去除格式化(还原为原始数字字符串)
|
@@ -354,50 +375,16 @@ export default {
|
|
354
375
|
},
|
355
376
|
};
|
356
377
|
},
|
357
|
-
//
|
358
|
-
|
359
|
-
// 预设的正则规则
|
360
|
-
const REGEX_RULES = {
|
361
|
-
number: /[^\d]/g, // 仅数字
|
362
|
-
phone: /[^\d]/g, // 手机号
|
363
|
-
decimal: /[^\d.]/g, // 小数
|
364
|
-
letter: /[^a-zA-Z]/g, // 仅字母
|
365
|
-
chinese: /[^\u4e00-\u9fa5]/g, // 仅中文
|
366
|
-
letterNumber: /[^a-zA-Z0-9]/g, // 字母和数字
|
367
|
-
email: /[^a-zA-Z0-9@._-]/g, // 邮箱
|
368
|
-
custom: null, // 自定义正则
|
369
|
-
};
|
370
|
-
|
378
|
+
// 自定义正则格式化
|
379
|
+
regexFormat: (item) => {
|
371
380
|
// 默认配置
|
372
381
|
const config = {
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
decimal: undefined, // 小数位数(type为decimal时使用)
|
382
|
+
pattern: "", // 自定义正则表达式
|
383
|
+
flags: "g", // 正则标志,默认全局匹配
|
384
|
+
replace: "", // 替换值,默认为空字符串
|
377
385
|
...(get(item, "formatData") || item),
|
378
386
|
};
|
379
387
|
|
380
|
-
// 处理小数格式化
|
381
|
-
const formatDecimal = (value) => {
|
382
|
-
if (!value) return value;
|
383
|
-
|
384
|
-
// 先去除非数字和小数点
|
385
|
-
let formatted = value.replace(/[^\d.]/g, "");
|
386
|
-
|
387
|
-
// 只保留第一个小数点
|
388
|
-
const parts = formatted.split(".");
|
389
|
-
if (parts.length > 2) {
|
390
|
-
formatted = parts[0] + "." + parts.slice(1).join("");
|
391
|
-
}
|
392
|
-
|
393
|
-
// 处理小数位数
|
394
|
-
if (config.decimal !== undefined && parts[1]) {
|
395
|
-
formatted = parts[0] + "." + parts[1].slice(0, config.decimal);
|
396
|
-
}
|
397
|
-
|
398
|
-
return formatted;
|
399
|
-
};
|
400
|
-
|
401
388
|
return {
|
402
389
|
input: (value) => {
|
403
390
|
if (!value) return value;
|
@@ -405,28 +392,38 @@ export default {
|
|
405
392
|
try {
|
406
393
|
let formatted = String(value);
|
407
394
|
|
408
|
-
//
|
409
|
-
if (config.
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
395
|
+
// 验证并应用正则表达式
|
396
|
+
if (config.pattern) {
|
397
|
+
let regex;
|
398
|
+
if (config.pattern instanceof RegExp) {
|
399
|
+
// 如果已经是RegExp对象,直接使用
|
400
|
+
regex = config.pattern;
|
401
|
+
} else {
|
402
|
+
// 如果是字符串,创建RegExp对象
|
403
|
+
regex = new RegExp(config.pattern, config.flags);
|
404
|
+
}
|
405
|
+
|
406
|
+
// 如果是验证模式(以^开头且以$结尾),则进行完整匹配
|
407
|
+
if (
|
408
|
+
config.pattern.toString().startsWith("/^") &&
|
409
|
+
config.pattern.toString().endsWith("$/")
|
410
|
+
) {
|
411
|
+
return regex.test(formatted) ? formatted : "";
|
412
|
+
} else {
|
413
|
+
// 否则进行替换
|
414
|
+
formatted = formatted.replace(regex, config.replace);
|
415
|
+
}
|
416
416
|
}
|
417
417
|
|
418
|
-
|
419
|
-
const rule = config.pattern
|
420
|
-
? new RegExp(config.pattern, "g")
|
421
|
-
: REGEX_RULES[config.inputType];
|
422
|
-
|
423
|
-
return formatted.replace(rule, "");
|
418
|
+
return formatted;
|
424
419
|
} catch (error) {
|
425
|
-
console.warn("
|
420
|
+
console.warn("自定义正则格式化失败:", error);
|
426
421
|
return value;
|
427
422
|
}
|
428
423
|
},
|
429
|
-
output: (value) =>
|
424
|
+
output: (value) => {
|
425
|
+
return value;
|
426
|
+
},
|
430
427
|
};
|
431
428
|
},
|
432
429
|
// 百分比格式化
|