@nstc-business/imes 1.0.39 → 1.0.41
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 +1 -1
- package/src/components/measureCalc/MeasureEvalFlatTable.vue +5 -0
- package/src/components/measureCalc/MeasureQualAnalysis.vue +8 -3
- package/src/components/measureCalc/MeasureStatFlatTable.vue +2 -0
- package/src/components/measureCalc/MeasureTreeTable.vue +2 -0
- package/src/components/measureCalc/helpers.qualReason.test.js +58 -0
- package/src/components/measureCalc/index.vue +9 -0
- package/src/components/measureCalc/qualReason.js +29 -0
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="measure-eval-flat">
|
|
3
|
+
<!-- 横条放在表头上方:表格按内容撑高时,底部横条会落到页面可视区外,右侧列无法滚动 -->
|
|
3
4
|
<vxe-table
|
|
4
5
|
border
|
|
5
6
|
class="v3-n20-table-pro"
|
|
6
7
|
:data="rows"
|
|
7
8
|
:row-config="{ keyField: '_rowKey' }"
|
|
8
9
|
:scroll-y="{ enabled: false }"
|
|
10
|
+
:scrollbar-config="{ x: { position: 'top' } }"
|
|
9
11
|
>
|
|
10
12
|
<vxe-column v-if="showSerial" title="序号" width="72" align="center">
|
|
11
13
|
<template #default="{ rowIndex }">{{ rowIndex + 1 }}</template>
|
|
@@ -245,6 +247,7 @@ import {
|
|
|
245
247
|
showLevelSerial,
|
|
246
248
|
isShowFullScore
|
|
247
249
|
} from './helpers'
|
|
250
|
+
import { fillQualReasonFromOption } from './qualReason'
|
|
248
251
|
|
|
249
252
|
export default {
|
|
250
253
|
name: 'MeasureEvalFlatTable',
|
|
@@ -337,6 +340,8 @@ export default {
|
|
|
337
340
|
this.$set(target, 'scoreText', option.scoreText)
|
|
338
341
|
this.$set(target, 'scoreValue', option.scoreValue)
|
|
339
342
|
target.picker = option
|
|
343
|
+
fillQualReasonFromOption(target, option, true)
|
|
344
|
+
this.$set(target, 'reason', target.reason)
|
|
340
345
|
this.syncQual(target, {
|
|
341
346
|
itemID: target.itemID,
|
|
342
347
|
scoreMapID: option.scoreMapID,
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
</span>
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
|
+
<!-- 横条放在表头上方:表格按内容撑高时,底部横条会落到页面可视区外,右侧列无法滚动 -->
|
|
29
30
|
<vxe-table
|
|
30
31
|
v-show="isExpanded(index)"
|
|
31
32
|
border
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
:data="group.children"
|
|
34
35
|
:row-config="{ keyField: '_rowKey' }"
|
|
35
36
|
:scroll-y="{ enabled: false }"
|
|
37
|
+
:scrollbar-config="{ x: { position: 'top' } }"
|
|
36
38
|
>
|
|
37
39
|
<vxe-column v-if="showSerial" title="序号" width="72" align="center">
|
|
38
40
|
<template #default="{ rowIndex }">{{ rowIndex + 1 }}</template>
|
|
@@ -154,6 +156,7 @@ import {
|
|
|
154
156
|
fullScoreText,
|
|
155
157
|
isShowFullScore
|
|
156
158
|
} from './helpers'
|
|
159
|
+
import { fillQualReasonFromOption } from './qualReason'
|
|
157
160
|
|
|
158
161
|
export default {
|
|
159
162
|
name: 'MeasureQualAnalysis',
|
|
@@ -251,13 +254,15 @@ export default {
|
|
|
251
254
|
const resolve = this.measureCtx().resolveLeafNode
|
|
252
255
|
return resolve ? resolve(node) || node : node
|
|
253
256
|
},
|
|
254
|
-
applyNodeSelection(node, option) {
|
|
257
|
+
applyNodeSelection(node, option, forceReason = false) {
|
|
255
258
|
if (!node || !option) return
|
|
256
259
|
this.$set(node, 'value', option)
|
|
257
260
|
this.$set(node, 'scoreMapID', option.scoreMapID)
|
|
258
261
|
this.$set(node, 'scoreText', option.scoreText)
|
|
259
262
|
this.$set(node, 'scoreValue', option.scoreValue)
|
|
260
263
|
this.$set(node, 'picker', option)
|
|
264
|
+
fillQualReasonFromOption(node, option, forceReason)
|
|
265
|
+
this.$set(node, 'reason', node.reason)
|
|
261
266
|
},
|
|
262
267
|
pushQualDraft(node, patch) {
|
|
263
268
|
const sync = this.measureCtx().syncQualSelection
|
|
@@ -280,7 +285,7 @@ export default {
|
|
|
280
285
|
item => item.scoreMapID == scoreMapID
|
|
281
286
|
)
|
|
282
287
|
if (!option) return
|
|
283
|
-
this.applyNodeSelection(target, option)
|
|
288
|
+
this.applyNodeSelection(target, option, true)
|
|
284
289
|
this.$set(target, 'result', null)
|
|
285
290
|
this.pushQualDraft(target, {
|
|
286
291
|
itemID: target.itemID,
|
|
@@ -313,7 +318,7 @@ export default {
|
|
|
313
318
|
const option = (node.optionList || []).find(
|
|
314
319
|
o => o.scoreMapID == draft.scoreMapID
|
|
315
320
|
)
|
|
316
|
-
if (option) this.applyNodeSelection(node, option)
|
|
321
|
+
if (option) this.applyNodeSelection(node, option, false)
|
|
317
322
|
}
|
|
318
323
|
if (draft.reason != null && draft.reason !== node.reason) {
|
|
319
324
|
this.$set(node, 'reason', draft.reason)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="measure-stat-flat">
|
|
3
3
|
<div v-if="!rows.length" class="stat-empty">暂无统计数据</div>
|
|
4
|
+
<!-- 横条放在表头上方:表格按内容撑高时,底部横条会落到页面可视区外,右侧列无法滚动 -->
|
|
4
5
|
<vxe-table
|
|
5
6
|
v-else
|
|
6
7
|
border
|
|
@@ -9,6 +10,7 @@
|
|
|
9
10
|
:merge-cells="mergeCells"
|
|
10
11
|
:row-config="{ keyField: '_rowKey' }"
|
|
11
12
|
:scroll-y="{ enabled: false }"
|
|
13
|
+
:scrollbar-config="{ x: { position: 'top' } }"
|
|
12
14
|
>
|
|
13
15
|
<vxe-column field="pName" title="指标项" min-width="150" align="center" />
|
|
14
16
|
<vxe-column field="statsName" title="统计项名称" min-width="150" align="center" />
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
<!-- 横条放在表头上方:表格按内容撑高时,底部横条会落到页面可视区外,右侧列无法滚动 -->
|
|
2
3
|
<vxe-table
|
|
3
4
|
border
|
|
4
5
|
ref="xTable"
|
|
@@ -7,6 +8,7 @@
|
|
|
7
8
|
:data="nodes"
|
|
8
9
|
:expand-config="{ lazy: false, visibleMethod: canExpand }"
|
|
9
10
|
:scroll-y="{ enabled: false }"
|
|
11
|
+
:scrollbar-config="{ x: { position: 'top' } }"
|
|
10
12
|
>
|
|
11
13
|
<vxe-column v-if="hasContainer" type="expand" width="44">
|
|
12
14
|
<template #content="{ row }">
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 定性指标评价理由回填:选选项带到节点 reason;测算结果非空 reason 才覆盖
|
|
3
|
+
*/
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
|
|
7
|
+
const src = fs
|
|
8
|
+
.readFileSync(path.join(__dirname, 'qualReason.js'), 'utf8')
|
|
9
|
+
.replace(/export /g, '')
|
|
10
|
+
const exported = {}
|
|
11
|
+
new Function(
|
|
12
|
+
'exports',
|
|
13
|
+
src +
|
|
14
|
+
'\nexports.hasFilledReason = hasFilledReason' +
|
|
15
|
+
'\nexports.fillQualReasonFromOption = fillQualReasonFromOption' +
|
|
16
|
+
'\nexports.mergeCalcResultReason = mergeCalcResultReason'
|
|
17
|
+
)(exported)
|
|
18
|
+
|
|
19
|
+
const { hasFilledReason, fillQualReasonFromOption, mergeCalcResultReason } = exported
|
|
20
|
+
|
|
21
|
+
function assert(cond, msg) {
|
|
22
|
+
if (!cond) throw new Error(msg)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
assert(hasFilledReason('有内容') === true, '非空理由应为 true')
|
|
26
|
+
assert(hasFilledReason('') === false, '空字符串应为 false')
|
|
27
|
+
assert(hasFilledReason(' ') === false, '空白应为 false')
|
|
28
|
+
assert(hasFilledReason(null) === false, 'null 应为 false')
|
|
29
|
+
|
|
30
|
+
const option = { scoreMapID: 1, scoreText: '否', reason: '至少下调1级,最低调至CC级' }
|
|
31
|
+
|
|
32
|
+
const emptyNode = { reason: '' }
|
|
33
|
+
fillQualReasonFromOption(emptyNode, option, false)
|
|
34
|
+
assert(emptyNode.reason === option.reason, '节点理由为空时应从选项带回,实际: ' + emptyNode.reason)
|
|
35
|
+
|
|
36
|
+
const savedNode = { reason: '用户已保存的理由' }
|
|
37
|
+
fillQualReasonFromOption(savedNode, option, false)
|
|
38
|
+
assert(savedNode.reason === '用户已保存的理由', '回显时不应覆盖已有理由')
|
|
39
|
+
|
|
40
|
+
const selectNode = { reason: '旧选项理由' }
|
|
41
|
+
fillQualReasonFromOption(selectNode, option, true)
|
|
42
|
+
assert(selectNode.reason === option.reason, '用户新选选项时应覆盖为当前选项理由')
|
|
43
|
+
|
|
44
|
+
const noOptionReason = { reason: '' }
|
|
45
|
+
fillQualReasonFromOption(noOptionReason, { reason: '' }, true)
|
|
46
|
+
assert(noOptionReason.reason === '', '选项没有理由时不应写脏值')
|
|
47
|
+
|
|
48
|
+
const target = { reason: '界面上已填' }
|
|
49
|
+
mergeCalcResultReason(target, { reason: '测算日志理由' })
|
|
50
|
+
assert(target.reason === '测算日志理由', '测算回写非空理由应覆盖')
|
|
51
|
+
|
|
52
|
+
mergeCalcResultReason(target, { reason: '' })
|
|
53
|
+
assert(target.reason === '测算日志理由', '测算回写空理由不应把界面理由冲掉')
|
|
54
|
+
|
|
55
|
+
mergeCalcResultReason(target, {})
|
|
56
|
+
assert(target.reason === '测算日志理由', '测算结果无 reason 字段时保持原值')
|
|
57
|
+
|
|
58
|
+
console.log('helpers.qualReason.test.js ok')
|
|
@@ -258,6 +258,7 @@ import {
|
|
|
258
258
|
} from './helpers'
|
|
259
259
|
import { preprocessStatIndicatorDeepList, mergeStatModelNode, statItemChildren } from './statModelHelper'
|
|
260
260
|
import { withRequestTimestamp } from './api'
|
|
261
|
+
import { fillQualReasonFromOption, mergeCalcResultReason } from './qualReason'
|
|
261
262
|
import { formatFloat2 } from '../common'
|
|
262
263
|
import { printJS } from 'n20-common-lib/src/plugins/Print'
|
|
263
264
|
import calculateDetailDialog from '../calculateDetail/dialog.vue'
|
|
@@ -653,6 +654,8 @@ export default {
|
|
|
653
654
|
this.$set(target, 'scoreText', selected.scoreText)
|
|
654
655
|
this.$set(target, 'scoreValue', selected.scoreValue)
|
|
655
656
|
this.$set(target, 'picker', selected)
|
|
657
|
+
fillQualReasonFromOption(target, selected, false)
|
|
658
|
+
this.$set(target, 'reason', target.reason)
|
|
656
659
|
})
|
|
657
660
|
}
|
|
658
661
|
return selected || null
|
|
@@ -808,6 +811,7 @@ export default {
|
|
|
808
811
|
const matched =
|
|
809
812
|
data.find(o => o.scoreMapID == row.scoreMapID) ||
|
|
810
813
|
data.find(o => o.scoreText == row.scoreText) ||
|
|
814
|
+
data.find(o => o.scoreText == row.indicatorValText) ||
|
|
811
815
|
data.find(o => o.scoreValue == row.indicatorResult)
|
|
812
816
|
if (matched) {
|
|
813
817
|
this.$set(row, 'value', matched)
|
|
@@ -815,6 +819,8 @@ export default {
|
|
|
815
819
|
this.$set(row, 'scoreText', matched.scoreText)
|
|
816
820
|
this.$set(row, 'scoreValue', matched.scoreValue)
|
|
817
821
|
this.$set(row, 'picker', matched)
|
|
822
|
+
fillQualReasonFromOption(row, matched, false)
|
|
823
|
+
this.$set(row, 'reason', row.reason)
|
|
818
824
|
}
|
|
819
825
|
}
|
|
820
826
|
} catch (e) {
|
|
@@ -1392,6 +1398,9 @@ export default {
|
|
|
1392
1398
|
this.$set(target, key, source[key])
|
|
1393
1399
|
}
|
|
1394
1400
|
})
|
|
1401
|
+
if (mergeCalcResultReason(target, source)) {
|
|
1402
|
+
this.$set(target, 'reason', target.reason)
|
|
1403
|
+
}
|
|
1395
1404
|
// 未调整时后端 modifiedVal 常为 0,不能覆盖手工填报的指标值
|
|
1396
1405
|
if (shouldApplyModifiedVal(target, source)) {
|
|
1397
1406
|
this.$set(target, 'modifiedVal', source.modifiedVal)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 定性指标评价理由回填
|
|
3
|
+
* 时间:2026-09-21;人员:AI && 徐红飞;入参:节点/选项/测算结果;出参:是否写回;方法内容:选项理由带到评价理由,测算空值不覆盖
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export function hasFilledReason(val) {
|
|
7
|
+
return val != null && String(val).trim() !== ''
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 把评分选项上的评价说明写到节点评价理由。
|
|
12
|
+
* force=true:用户刚选选项,用当前选项 reason 覆盖。
|
|
13
|
+
* force=false:回显/拉选项,仅当节点 reason 为空时补齐,避免冲掉日志里已保存的理由。
|
|
14
|
+
*/
|
|
15
|
+
export function fillQualReasonFromOption(row, option, force = false) {
|
|
16
|
+
if (!row || !option) return false
|
|
17
|
+
if (!hasFilledReason(option.reason)) return false
|
|
18
|
+
if (!force && hasFilledReason(row.reason)) return false
|
|
19
|
+
row.reason = option.reason
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** 测算结果回写:仅非空 reason 覆盖,避免空串冲掉界面已填理由 */
|
|
24
|
+
export function mergeCalcResultReason(target, source) {
|
|
25
|
+
if (!target || !source) return false
|
|
26
|
+
if (!hasFilledReason(source.reason)) return false
|
|
27
|
+
target.reason = source.reason
|
|
28
|
+
return true
|
|
29
|
+
}
|