@nstc-business/imes 1.0.0 → 1.0.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nstc-business/imes",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"element-ui": "^2.15.6",
|
|
25
25
|
"jquery": "^3.6.0",
|
|
26
26
|
"moment": "^2.30.1",
|
|
27
|
-
"n20-common-lib": "2.5.18",
|
|
28
27
|
"qrcode": "^1.5.0",
|
|
29
28
|
"resize-detector": "^0.3.0",
|
|
30
29
|
"swiper": "^11.1.14",
|
|
@@ -40,6 +39,7 @@
|
|
|
40
39
|
"src/index.js"
|
|
41
40
|
],
|
|
42
41
|
"devDependencies": {
|
|
42
|
+
"n20-common-lib": "2.5.18",
|
|
43
43
|
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
|
44
44
|
"@babel/plugin-transform-flow-comments": "^7.14.5",
|
|
45
45
|
"@vue/cli-plugin-babel": "~4.5.0",
|
package/src/components/common.js
CHANGED
|
@@ -1,138 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export function formatDate(date, fmt) {
|
|
4
|
-
date = new Date(date)
|
|
5
|
-
if (/(y+)/.test(fmt)) {
|
|
6
|
-
fmt = fmt.replace(
|
|
7
|
-
RegExp.$1,
|
|
8
|
-
(date.getFullYear() + '').substr(4 - RegExp.$1.length)
|
|
9
|
-
)
|
|
10
|
-
}
|
|
11
|
-
let o = {
|
|
12
|
-
'M+': date.getMonth() + 1,
|
|
13
|
-
'd+': date.getDate(),
|
|
14
|
-
'h+': date.getHours(),
|
|
15
|
-
'm+': date.getMinutes(),
|
|
16
|
-
's+': date.getSeconds()
|
|
17
|
-
}
|
|
18
|
-
for (let k in o) {
|
|
19
|
-
if (new RegExp(`(${k})`).test(fmt)) {
|
|
20
|
-
let str = o[k] + ''
|
|
21
|
-
fmt = fmt.replace(
|
|
22
|
-
RegExp.$1,
|
|
23
|
-
RegExp.$1.length === 1 ? str : padLeftZero(str)
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return fmt
|
|
28
|
-
}
|
|
29
|
-
function padLeftZero(str) {
|
|
30
|
-
return ('00' + str).substr(str.length)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 公式转换,支持复杂运算逻辑
|
|
35
|
-
* @param {array} statisticItems 数据映射数组
|
|
36
|
-
* @param {string} formula 公式
|
|
37
|
-
* @returns {object} codeFormula cod公式,randomFormula 随机数公式
|
|
38
|
-
*/
|
|
39
|
-
export const replaceStatsNameWithCode = (statisticItems, formula) => {
|
|
40
|
-
// 创建statsName到code的映射
|
|
41
|
-
const nameToCodeMap = statisticItems.reduce((map, item) => {
|
|
42
|
-
if (item.formula) {
|
|
43
|
-
map[item.statsName] = {
|
|
44
|
-
formula: item.formula
|
|
45
|
-
}
|
|
46
|
-
} else {
|
|
47
|
-
map[item.statsName] = item.code
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return map
|
|
51
|
-
}, {})
|
|
52
|
-
|
|
53
|
-
// 创建statsName到随机数的映射
|
|
54
|
-
const nameToRandomMap = statisticItems.reduce((map, item) => {
|
|
55
|
-
if (item.formula) {
|
|
56
|
-
map[item.statsName] = {
|
|
57
|
-
formula: item.formula
|
|
58
|
-
}
|
|
59
|
-
} else {
|
|
60
|
-
map[item.statsName] = Math.random().toFixed(10)
|
|
61
|
-
}
|
|
62
|
-
return map
|
|
63
|
-
}, {})
|
|
64
|
-
|
|
65
|
-
// 增强的正则表达式,支持多层嵌套的复杂表达式
|
|
66
|
-
const complexPattern =
|
|
67
|
-
/(?:\([^()]*\)|[\u4e00-\u9fa5a-zA-Z0-9-]+)(?:\s*[+\-*/]\s*(?:\([^()]*\)|[\u4e00-\u9fa5a-zA-Z0-9-]+))*/g
|
|
68
|
-
|
|
69
|
-
// 生成code公式
|
|
70
|
-
const codeFormula = formula.replace(complexPattern, match => {
|
|
71
|
-
// 处理带括号的表达式
|
|
72
|
-
const hasParentheses = match.startsWith('(') && match.endsWith(')')
|
|
73
|
-
const content = hasParentheses ? match.slice(1, -1) : match
|
|
74
|
-
|
|
75
|
-
// 先替换括号内的内容
|
|
76
|
-
const innerReplaced = content.replace(
|
|
77
|
-
/[\u4e00-\u9fa5a-zA-Z0-9-]+/g,
|
|
78
|
-
part =>
|
|
79
|
-
typeof nameToCodeMap[part] === 'object'
|
|
80
|
-
? nameToCodeMap[part]?.formula
|
|
81
|
-
: nameToCodeMap[part] === undefined
|
|
82
|
-
? part
|
|
83
|
-
: `#${nameToCodeMap[part]}#`
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
// 再处理运算符
|
|
87
|
-
const result = innerReplaced
|
|
88
|
-
.split(/([+\-*/()])/)
|
|
89
|
-
.map(part => {
|
|
90
|
-
const trimmed = part.trim()
|
|
91
|
-
return nameToCodeMap[trimmed] ? `#${nameToCodeMap[trimmed]}#` : part
|
|
92
|
-
})
|
|
93
|
-
.join('')
|
|
94
|
-
|
|
95
|
-
return hasParentheses ? `(${result})` : result
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
// 生成随机数公式
|
|
99
|
-
const randomFormula = formula.replace(complexPattern, match => {
|
|
100
|
-
// 处理带括号的表达式
|
|
101
|
-
const hasParentheses = match.startsWith('(') && match.endsWith(')')
|
|
102
|
-
const content = hasParentheses ? match.slice(1, -1) : match
|
|
103
|
-
|
|
104
|
-
// 先替换括号内的内容
|
|
105
|
-
const innerReplaced = content.replace(
|
|
106
|
-
/[\u4e00-\u9fa5a-zA-Z0-9-]+/g,
|
|
107
|
-
part => {
|
|
108
|
-
const random = nameToRandomMap[part]
|
|
109
|
-
return typeof random === 'object'
|
|
110
|
-
? random.formula
|
|
111
|
-
: random === undefined
|
|
112
|
-
? part
|
|
113
|
-
: random
|
|
114
|
-
}
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
// 再处理运算符
|
|
118
|
-
const result = innerReplaced
|
|
119
|
-
.split(/([+\-*/()])/)
|
|
120
|
-
.map(part => {
|
|
121
|
-
const trimmed = part.trim()
|
|
122
|
-
const random = nameToRandomMap[trimmed]
|
|
123
|
-
return random === undefined ? part : random
|
|
124
|
-
})
|
|
125
|
-
.join('')
|
|
126
|
-
|
|
127
|
-
return hasParentheses ? `(${result})` : result
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
codeFormula,
|
|
132
|
-
randomFormula
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
1
|
+
import {N} from 'n20-common-lib'
|
|
136
2
|
/**
|
|
137
3
|
* 设置表格合并行的公共方法
|
|
138
4
|
* @param {any[]} list 表格数据
|
|
@@ -142,6 +8,8 @@ export const replaceStatsNameWithCode = (statisticItems, formula) => {
|
|
|
142
8
|
* @param {String} field 表头取值的字段名
|
|
143
9
|
*/
|
|
144
10
|
|
|
11
|
+
|
|
12
|
+
|
|
145
13
|
export function setMergeCells({
|
|
146
14
|
list = [],
|
|
147
15
|
columns = [],
|
|
@@ -224,146 +92,6 @@ export const formatFloat2 = (num, digit3 = 2) => {
|
|
|
224
92
|
return parseFloat(N.subFixed(num, digit3))
|
|
225
93
|
}
|
|
226
94
|
|
|
227
|
-
/**
|
|
228
|
-
* 校验Table每行字段是否为空
|
|
229
|
-
* @param {Object} requiredFields 字段映射对象,例:{minVal: '最小值', maxVal: '最大值', score: '分数'}
|
|
230
|
-
* @param {Array} data 要验证的数据数组
|
|
231
|
-
* @returns {Error|null} 验证通过返回null,失败返回Error对象
|
|
232
|
-
*/
|
|
233
|
-
export const validateFieldPresence = (requiredFields = {}, data = []) => {
|
|
234
|
-
// 添加参数有效性检查
|
|
235
|
-
if (!Array.isArray(data)) return new Error('数据参数必须为数组')
|
|
236
|
-
|
|
237
|
-
for (const [index, row] of data.entries()) {
|
|
238
|
-
// 遍历字段映射对象的键
|
|
239
|
-
for (const field of Object.keys(requiredFields)) {
|
|
240
|
-
// 添加字段存在性检查
|
|
241
|
-
if (!Object.prototype.hasOwnProperty.call(row, field)) {
|
|
242
|
-
return new Error(`第${index + 1}条规则:当前行缺少必要字段[${field}]`)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// 加强空值判断
|
|
246
|
-
if (row[field] === '' || row[field] == null) {
|
|
247
|
-
return new Error(
|
|
248
|
-
`第${index + 1}条规则:${requiredFields[field] || field}不能为空`
|
|
249
|
-
)
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// 明确返回验证通过状态
|
|
255
|
-
return null
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* 校验数字格式
|
|
260
|
-
* @param {Object} options 配置项
|
|
261
|
-
* @param {Object} options.requiredFields 字段映射对象 {minVal: '最小值', maxVal: '最大值'}
|
|
262
|
-
* @param {Array} options.data 要验证的数据数组
|
|
263
|
-
* @param {RegExp} options.validRegex 验证正则,默认/^-?\d+(?:\.\d{1,6})?$/
|
|
264
|
-
* @returns {Error|null}
|
|
265
|
-
*/
|
|
266
|
-
export const validateNumberFormat = ({
|
|
267
|
-
requiredFields = {},
|
|
268
|
-
data = [],
|
|
269
|
-
validRegex = /^-?\d+(?:\.\d{1,6})?$/
|
|
270
|
-
} = {}) => {
|
|
271
|
-
if (!Array.isArray(data)) return new Error('数据参数必须为数组')
|
|
272
|
-
|
|
273
|
-
for (const [index, row] of data.entries()) {
|
|
274
|
-
for (const [field, fieldName] of Object.entries(requiredFields)) {
|
|
275
|
-
const value = String(row[field] ?? '') // 处理undefined/null
|
|
276
|
-
|
|
277
|
-
if (!validRegex.test(value)) {
|
|
278
|
-
return new Error(`第${index + 1}条规则:${fieldName}格式不正确`)
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return null
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* 校验区间重叠
|
|
287
|
-
* @param {Array} data
|
|
288
|
-
* @param {Object} requiredFields = {},
|
|
289
|
-
* @returns
|
|
290
|
-
*/
|
|
291
|
-
export const validateRangeOverlap = (
|
|
292
|
-
data = [],
|
|
293
|
-
requiredFields = {
|
|
294
|
-
minVal: '下限',
|
|
295
|
-
maxVal: '上限'
|
|
296
|
-
}
|
|
297
|
-
) => {
|
|
298
|
-
if (!Array.isArray(data)) return new Error('数据参数必须为数组')
|
|
299
|
-
// 增强参数校验
|
|
300
|
-
const fields = Object.keys(requiredFields)
|
|
301
|
-
if (fields.length !== 2) {
|
|
302
|
-
return new Error('字段映射对象必须且只能包含两个字段[minKey, maxKey]')
|
|
303
|
-
}
|
|
304
|
-
const [minKey, maxKey] = fields
|
|
305
|
-
|
|
306
|
-
for (let i = 0; i < data.length; i++) {
|
|
307
|
-
const current = data[i]
|
|
308
|
-
|
|
309
|
-
// 合并字段存在性检查
|
|
310
|
-
for (const key of [minKey, maxKey]) {
|
|
311
|
-
// 修复属性检查方式,增加对象类型判断
|
|
312
|
-
if (
|
|
313
|
-
!current ||
|
|
314
|
-
typeof current !== 'object' ||
|
|
315
|
-
!Object.prototype.hasOwnProperty.call(current, key)
|
|
316
|
-
) {
|
|
317
|
-
return new Error(`第${i + 1}条规则:缺少${requiredFields[key]}字段`)
|
|
318
|
-
}
|
|
319
|
-
// 空值检查添加到此处
|
|
320
|
-
if (current[key] === '' || current[key] == null) {
|
|
321
|
-
return new Error(`第${i + 1}条规则:${requiredFields[key]}不能为空`)
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
// 增强数值转换
|
|
325
|
-
const [minVal, maxVal] = [Number(current[minKey]), Number(current[maxKey])]
|
|
326
|
-
if (isNaN(minVal)) {
|
|
327
|
-
return new Error(`第${i + 1}条规则:${requiredFields[minKey]}值无效`)
|
|
328
|
-
}
|
|
329
|
-
if (isNaN(maxVal)) {
|
|
330
|
-
return new Error(`第${i + 1}条规则:${requiredFields[maxKey]}值无效`)
|
|
331
|
-
}
|
|
332
|
-
if (minVal >= maxVal) {
|
|
333
|
-
return new Error(
|
|
334
|
-
`第${i + 1}条规则:${requiredFields[minKey]}不能大于等于${requiredFields[maxKey]}`
|
|
335
|
-
)
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// 优化区间检查性能
|
|
339
|
-
for (let j = i + 1; j < data.length; j++) {
|
|
340
|
-
const other = data[j]
|
|
341
|
-
// 添加对other行的校验
|
|
342
|
-
if ([minKey, maxKey].some(k => !Object.prototype.hasOwnProperty.call(other, k))) continue
|
|
343
|
-
|
|
344
|
-
if (isRangeOverlap(current, other, minKey, maxKey)) {
|
|
345
|
-
return new Error(`第${i + 1}条和第${j + 1}条规则存在区间重叠`)
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
return null
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
export const isRangeOverlap = (a, b, minKey = 'minVal', maxKey = 'maxVal') => {
|
|
353
|
-
const aMin = Number(a[minKey])
|
|
354
|
-
const aMax = Number(a[maxKey])
|
|
355
|
-
const bMin = Number(b[minKey])
|
|
356
|
-
const bMax = Number(b[maxKey])
|
|
357
|
-
|
|
358
|
-
return (
|
|
359
|
-
!isNaN(aMin) &&
|
|
360
|
-
!isNaN(aMax) &&
|
|
361
|
-
!isNaN(bMin) &&
|
|
362
|
-
!isNaN(bMax) &&
|
|
363
|
-
Math.max(aMin, bMin) < Math.min(aMax, bMax)
|
|
364
|
-
)
|
|
365
|
-
}
|
|
366
|
-
|
|
367
95
|
export function toFixedTrunc(num, decimals) {
|
|
368
96
|
if (isNaN(num) || num === undefined || num === null) return num
|
|
369
97
|
|
|
@@ -379,41 +107,4 @@ export function toFixedTrunc(num, decimals) {
|
|
|
379
107
|
|
|
380
108
|
export function addThousands(data) {
|
|
381
109
|
return N.addThousands(data)
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* 深度克隆
|
|
386
|
-
* @param target
|
|
387
|
-
* @return {}
|
|
388
|
-
*/
|
|
389
|
-
export const deepClone = (target, map = new Map()) => {
|
|
390
|
-
// 检测数据的类型
|
|
391
|
-
if (typeof target === 'object' && target !== null) {
|
|
392
|
-
// 克隆数据之前, 进行判断, 数据之前是否克隆过
|
|
393
|
-
const cache = map.get(target)
|
|
394
|
-
if (cache) {
|
|
395
|
-
return cache
|
|
396
|
-
}
|
|
397
|
-
// 判断目标数据的类型
|
|
398
|
-
const isArray = Array.isArray(target)
|
|
399
|
-
// 创建一个容器
|
|
400
|
-
const result = isArray ? [] : {}
|
|
401
|
-
// 将新的结果存入到容器中
|
|
402
|
-
map.set(target, result)
|
|
403
|
-
// 如果目标数据为数组
|
|
404
|
-
if (isArray) {
|
|
405
|
-
// forEach 遍历
|
|
406
|
-
target.forEach((item, index) => {
|
|
407
|
-
result[index] = deepClone(item, map)
|
|
408
|
-
})
|
|
409
|
-
} else {
|
|
410
|
-
// 如果是对象, 获取所有的键名, 然后 forEach 遍历
|
|
411
|
-
Object.keys(target).forEach((key) => {
|
|
412
|
-
result[key] = deepClone(target[key], map)
|
|
413
|
-
})
|
|
414
|
-
}
|
|
415
|
-
return result
|
|
416
|
-
} else {
|
|
417
|
-
return target
|
|
418
|
-
}
|
|
419
|
-
}
|
|
110
|
+
}
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
|
|
52
52
|
<script>
|
|
53
53
|
import {N, Page, ExpandablePane, Descriptions} from 'n20-common-lib'
|
|
54
|
-
import tree from './tree.vue'
|
|
55
|
-
import modelCalcTest from './modelCalcTest.vue'
|
|
54
|
+
import tree from './model-calculate/tree.vue'
|
|
55
|
+
import modelCalcTest from './model-calculate/modelCalcTest.vue'
|
|
56
56
|
|
|
57
57
|
export default {
|
|
58
58
|
props: {
|