@nstc-business/imes 1.0.27 → 1.0.28

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.27",
3
+ "version": "1.0.28",
4
4
  "private": false,
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -19,9 +19,7 @@
19
19
  <span v-if="statResult.statCalMethod == 1 && statResult.statShow == 1">
20
20
  {{ statResult.name }}合计:
21
21
  {{
22
- statResult.statResult || statResult.statResult === 0
23
- ? statResult.statResult.toFixed(paramsObj.digits)
24
- : ''
22
+ formatScoreCell(statResult.statResult)
25
23
  }}
26
24
  </span>
27
25
  </div>
@@ -55,17 +53,7 @@
55
53
  <!-- 手工录入的时候不显示调整框,显示手工录入的框,就是 sourceType为3-->
56
54
  <div v-else-if="row[column.prop]?.sourceType === 3">
57
55
  <span v-if="column.disabled">
58
- {{
59
- row[column.prop]?.value || row[column.prop]?.value === 0
60
- ? N.subFixed(row[column.prop]?.value, paramsObj.digits)
61
- : ''
62
- }}
63
-
64
- {{
65
- row[column.prop]?.displayStyle === 1 && (row[column.prop]?.value || row[column.prop]?.value === 0)
66
- ? '%'
67
- : ''
68
- }}
56
+ {{ formatScoreCell(row[column.prop]?.value) }}
69
57
  </span>
70
58
  <div v-else>
71
59
  <InputNumber
@@ -91,17 +79,7 @@
91
79
  <!-- @change="getReason(node)" -->
92
80
  <div v-else-if="row[column.prop]?.sourceType === 0">
93
81
  <span v-if="column.disabled">
94
- {{
95
- row[column.prop]?.value || row[column.prop]?.value === 0
96
- ? N.subFixed(row[column.prop]?.value, paramsObj.digits)
97
- : ''
98
- }}
99
-
100
- {{
101
- row[column.prop]?.displayStyle === 1 && (row[column.prop]?.value || row[column.prop]?.value === 0)
102
- ? '%'
103
- : ''
104
- }}
82
+ {{ formatScoreCell(row[column.prop]?.value) }}
105
83
  </span>
106
84
  <el-select
107
85
  v-else
@@ -151,6 +129,9 @@
151
129
  "
152
130
  ></InputNumber>
153
131
 
132
+ <span v-else-if="column.disabled">
133
+ {{ formatScoreCell(row[column.prop]?.value) }}
134
+ </span>
154
135
  <span v-else>
155
136
  {{
156
137
  row[column.prop]?.value || row[column.prop]?.value === 0
@@ -203,6 +184,7 @@ import { N } from 'n20-common-lib'
203
184
  import { Descriptions, Table, InputNumber } from './ui'
204
185
  import { getScoreMap } from './api'
205
186
  import { formatFloat2 } from '../common'
187
+ import { formatScoreText } from './helpers'
206
188
  export default {
207
189
  name: 'EvaOfCreditConditions',
208
190
  components: { Descriptions, Table, InputNumber },
@@ -235,7 +217,8 @@ export default {
235
217
  // }
236
218
  // })
237
219
  result = this.nodeListData.result
238
- return formatFloat2(result, this.paramsObj.digits)
220
+ // 总得分固定 2 位四舍五入,不读模型 digits
221
+ return formatScoreText(result)
239
222
  },
240
223
  opinionPage() {
241
224
  return (
@@ -245,6 +228,10 @@ export default {
245
228
  }
246
229
  },
247
230
  methods: {
231
+ /** 得分列/合计:固定 2 位四舍五入 */
232
+ formatScoreCell(val) {
233
+ return formatScoreText(val)
234
+ },
248
235
  // 指标值是否可录入
249
236
  showInput(row) {
250
237
  // 授信定量分析指标值,系统取数可编辑 手工填报:3
@@ -105,15 +105,17 @@
105
105
  </el-select>
106
106
  </template>
107
107
  <div v-else>
108
- <!-- 原指标值:非手工填报始终展示;可调整时输入框在下方 -->
108
+ <!-- 原指标值:非手工填报始终展示;可调整时输入框在下方;悬浮展示计算公式(对齐测算详情) -->
109
109
  <el-tooltip
110
110
  v-if="row.sourceType !== 3 && (row.displayFormula || row.relFormula)"
111
111
  placement="top"
112
112
  effect="dark"
113
113
  >
114
- <template #content>
115
- <div>{{ row.displayFormula }}</div>
116
- </template>
114
+ <div slot="content">
115
+ {{ row.displayFormula }}
116
+ <br />
117
+ {{ row.relFormula }}
118
+ </div>
117
119
  <span>{{ indicatorTextFn(row) }}</span>
118
120
  </el-tooltip>
119
121
  <span v-else-if="row.sourceType !== 3">{{ indicatorTextFn(row) }}</span>
@@ -160,7 +162,7 @@
160
162
  row.modifyRank === 1
161
163
  "
162
164
  class="full-w"
163
- :d-num="ctx.modelWrap.digits"
165
+ :d-num="SCORE_DIGITS"
164
166
  :max="row.fullScore"
165
167
  :disabled="ctx.readonly"
166
168
  v-model="row.modifiedResult"
@@ -230,6 +232,7 @@ import { InputNumber } from './ui'
230
232
  import {
231
233
  isQualIndicator,
232
234
  digitsCalc,
235
+ SCORE_DIGITS,
233
236
  resultByShowStyle,
234
237
  indicatorScoreText,
235
238
  indicatorResultText,
@@ -242,6 +245,9 @@ export default {
242
245
  name: 'MeasureEvalFlatTable',
243
246
  components: { InputNumber },
244
247
  inject: ['measureCtx'],
248
+ data() {
249
+ return { SCORE_DIGITS }
250
+ },
245
251
  props: {
246
252
  section: {
247
253
  type: Object,
@@ -231,7 +231,7 @@ export default {
231
231
  return indicatorScoreText(node, this.modelWrap)
232
232
  },
233
233
  formatScore(val) {
234
- if (val === '' || val == null) return ''
234
+ // resultByShowStyle 已固定得分 2 位四舍五入
235
235
  return resultByShowStyle({ result: val }, this.modelWrap)
236
236
  },
237
237
  formatFullScore(node) {
@@ -86,6 +86,7 @@
86
86
  <script>
87
87
  import { InputNumber } from './ui'
88
88
  import { toFixedTrunc, addThousands } from '../common'
89
+ import { formatScoreText } from './helpers'
89
90
 
90
91
  export default {
91
92
  name: 'MeasureStatCell',
@@ -94,6 +95,7 @@ export default {
94
95
  props: {
95
96
  cell: { type: Object, default: null },
96
97
  column: { type: Object, default: () => ({}) },
98
+ /** 指标值小数位(可读模型配置);得分列固定 SCORE_DIGITS */
97
99
  digits: { type: Number, default: 2 }
98
100
  },
99
101
  computed: {
@@ -133,15 +135,11 @@ export default {
133
135
  if (val === '' || val == null) return ''
134
136
  return String(val)
135
137
  }
138
+ // 得分列:固定 2 位四舍五入,不读模型 digits
136
139
  if (this.column.disabled) {
137
140
  const val =
138
141
  cell.result !== '' && cell.result != null ? cell.result : cell.value
139
- if (val === '' || val == null) return ''
140
- let text = Number(val).toFixed(this.digits)
141
- if (cell.showStyle === 2) {
142
- text = addThousands(toFixedTrunc(val, this.digits))
143
- }
144
- return text
142
+ return formatScoreText(val, { thousands: cell.showStyle === 2 })
145
143
  }
146
144
  const val = cell.value
147
145
  if (val === '' || val == null) return ''
@@ -115,7 +115,7 @@
115
115
  row.modifyRank === 1
116
116
  "
117
117
  class="full-w"
118
- :d-num="ctx.modelWrap.digits"
118
+ :d-num="SCORE_DIGITS"
119
119
  :max="row.fullScore"
120
120
  :disabled="ctx.readonly"
121
121
  v-model="row.modifiedResult"
@@ -139,6 +139,7 @@ import { setMergeCells } from '../common'
139
139
  import {
140
140
  isQualIndicator,
141
141
  digitsCalc,
142
+ SCORE_DIGITS,
142
143
  resultByShowStyle,
143
144
  indicatorResultText
144
145
  } from './helpers'
@@ -157,6 +158,9 @@ export default {
157
158
  name: 'MeasureStatFlatTable',
158
159
  components: { InputNumber },
159
160
  inject: ['measureCtx'],
161
+ data() {
162
+ return { SCORE_DIGITS }
163
+ },
160
164
  props: {
161
165
  rows: {
162
166
  type: Array,
@@ -46,7 +46,7 @@ import {
46
46
  hasStatPivotNodes,
47
47
  sumStatBlockScores
48
48
  } from './statModelHelper'
49
- import { showLevelSerial } from './helpers'
49
+ import { showLevelSerial, formatScoreText } from './helpers'
50
50
  import { withRequestTimestamp } from './api'
51
51
  import MeasureStatCell from './MeasureStatCell.vue'
52
52
 
@@ -93,7 +93,7 @@ export default {
93
93
  if (!this.ctx.parentCalced) return '得分小计: --'
94
94
  const total = sumStatBlockScores(block)
95
95
  if (total === null) return '得分小计: --'
96
- return `得分小计: ${Number(total).toFixed(this.digits)}`
96
+ return `得分小计: ${formatScoreText(total)}`
97
97
  },
98
98
  dynamicColumns(block) {
99
99
  return (block.columns || []).filter(c => c.prop !== 'name')
@@ -129,8 +129,20 @@
129
129
  <vxe-column title="指标值" min-width="200" align="center">
130
130
  <template #default="{ row }">
131
131
  <div>
132
- <!-- 原指标值:非手工填报始终展示;可调整时输入框在下方 -->
133
- <span v-if="row.sourceType !== 3">{{ indicatorTextFn(row) }}</span>
132
+ <!-- 原指标值:非手工填报始终展示;悬浮展示计算公式(对齐测算详情) -->
133
+ <el-tooltip
134
+ v-if="row.sourceType !== 3 && (row.displayFormula || row.relFormula)"
135
+ placement="top"
136
+ effect="dark"
137
+ >
138
+ <div slot="content">
139
+ {{ row.displayFormula }}:
140
+ <br />
141
+ {{ row.relFormula }}
142
+ </div>
143
+ <span>{{ indicatorTextFn(row) }}</span>
144
+ </el-tooltip>
145
+ <span v-else-if="row.sourceType !== 3">{{ indicatorTextFn(row) }}</span>
134
146
  <InputNumber
135
147
  v-if="row.sourceType === 3 && row.itemType === 21"
136
148
  class="full-w"
@@ -176,7 +188,7 @@
176
188
  row.result !== null
177
189
  "
178
190
  class="full-w"
179
- :d-num="digitsFn(row)"
191
+ :d-num="SCORE_DIGITS"
180
192
  :disabled="ctx.readonly"
181
193
  v-model="row.modifiedResult"
182
194
  placeholder="请输入"
@@ -266,15 +278,17 @@
266
278
  <vxe-column title="指标值" min-width="260" align="center">
267
279
  <template #default="{ row }">
268
280
  <div v-if="isQuantIndicatorFn(row)">
269
- <!-- 原指标值:非手工填报始终展示;可调整时输入框在下方 -->
281
+ <!-- 原指标值:非手工填报始终展示;可调整时输入框在下方;悬浮展示计算公式(对齐测算详情) -->
270
282
  <el-tooltip
271
283
  v-if="row.sourceType !== 3 && (row.displayFormula || row.relFormula)"
272
284
  placement="top"
273
285
  effect="dark"
274
286
  >
275
- <template #content>
276
- <div>{{ row.displayFormula }}</div>
277
- </template>
287
+ <div slot="content">
288
+ {{ row.displayFormula }}
289
+ <br />
290
+ {{ row.relFormula }}
291
+ </div>
278
292
  <span>{{ indicatorTextFn(row) }}</span>
279
293
  </el-tooltip>
280
294
  <span v-else-if="row.sourceType !== 3">{{ indicatorTextFn(row) }}</span>
@@ -312,9 +326,11 @@
312
326
  placement="top"
313
327
  effect="dark"
314
328
  >
315
- <template #content>
316
- <div>{{ row.displayFormula }}</div>
317
- </template>
329
+ <div slot="content">
330
+ {{ row.displayFormula }}
331
+ <br />
332
+ {{ row.relFormula }}
333
+ </div>
318
334
  <span>{{ subModelIndicatorFn(row) }}</span>
319
335
  </el-tooltip>
320
336
  <span v-else>{{ subModelIndicatorFn(row) || '—' }}</span>
@@ -343,7 +359,7 @@
343
359
  row.result !== '' && row.result !== null && row.modifyRank === 1
344
360
  "
345
361
  class="full-w"
346
- :d-num="ctx.modelWrap.digits"
362
+ :d-num="SCORE_DIGITS"
347
363
  :max="row.fullScore"
348
364
  :disabled="ctx.readonly"
349
365
  v-model="row.modifiedResult"
@@ -422,6 +438,7 @@ import {
422
438
  showLevelSerial,
423
439
  typeMeta,
424
440
  digitsCalc,
441
+ SCORE_DIGITS,
425
442
  resultByShowStyle,
426
443
  indicatorScoreText,
427
444
  indicatorResultText,
@@ -435,6 +452,9 @@ export default {
435
452
  name: 'MeasureTreeTable',
436
453
  components: { InputNumber, MeasureQualAnalysis, MeasureSubModelPanel },
437
454
  inject: ['measureCtx'],
455
+ data() {
456
+ return { SCORE_DIGITS }
457
+ },
438
458
  props: {
439
459
  section: {
440
460
  type: Object,
@@ -9,7 +9,7 @@
9
9
  * modifyRank:0 不调整 1 调整指标得分 2 调整指标值
10
10
  */
11
11
  import { N } from 'n20-common-lib'
12
- import { toFixedTrunc, addThousands } from '../common'
12
+ import { addThousands } from '../common'
13
13
  import { resolveManualFillValue, statItemChildren } from './statModelHelper'
14
14
 
15
15
  export const ITEM_TYPE = {
@@ -209,7 +209,7 @@ export function typeMeta(row) {
209
209
  return map[nodeTypeOf(row)] || map.group
210
210
  }
211
211
 
212
- /** 小数位:优先取指标自身 showDigits,否则取模型整体 digits */
212
+ /** 小数位:优先取指标自身 showDigits,否则取模型整体 digits(仅用于指标值等非得分展示) */
213
213
  export function digitsCalc(row, modelWrap) {
214
214
  if (row && (row.showDigits || row.showDigits === 0)) {
215
215
  return row.showDigits
@@ -217,25 +217,39 @@ export function digitsCalc(row, modelWrap) {
217
217
  return modelWrap ? modelWrap.digits : 2
218
218
  }
219
219
 
220
- /** 模型指标得分 / 模型指标系数数值(权重之后的 result) */
220
+ /**
221
+ * 得分展示固定小数位(总得分/指标得分/模型指标得分等)
222
+ * 不读业务系统模型「保留小数位数」配置,始终四舍五入保留 2 位
223
+ */
224
+ export const SCORE_DIGITS = 2
225
+
226
+ /**
227
+ * 得分数值格式化:四舍五入,固定保留 SCORE_DIGITS 位
228
+ * @param {*} val
229
+ * @param {{ thousands?: boolean }} [options]
230
+ */
231
+ export function formatScoreText(val, options = {}) {
232
+ if (val === '' || val == null) return ''
233
+ const num = Number(val)
234
+ if (Number.isNaN(num)) return String(val)
235
+ let text = num.toFixed(SCORE_DIGITS)
236
+ if (options.thousands) {
237
+ text = addThousands(text)
238
+ }
239
+ return text
240
+ }
241
+
242
+ /** 模型指标得分 / 模型指标系数数值(权重之后的 result);得分不读模型 digits */
221
243
  export function resultByShowStyle(row, modelWrap) {
222
- let val = ''
223
- const digits = digitsCalc(row, modelWrap)
224
- if (row.showStyle === 2) {
225
- val =
226
- row.result || row.result === 0
227
- ? addThousands(toFixedTrunc(row.result, digits))
228
- : ''
229
- } else {
230
- val =
231
- row.result || row.result === 0 ? Number(row.result).toFixed(digits) : ''
244
+ if (!row || (row.result !== 0 && (row.result === '' || row.result == null))) {
245
+ return ''
232
246
  }
233
- return val
247
+ return formatScoreText(row.result, { thousands: row.showStyle === 2 })
234
248
  }
235
249
 
236
250
  /**
237
251
  * 指标得分(权重之前):result * 100 / weight
238
- * 与旧测算详情 valueScore 算法一致;无权重时不展示
252
+ * 与旧测算详情 valueScore 算法一致;无权重时不展示;得分固定 2 位四舍五入
239
253
  */
240
254
  export function indicatorScoreText(row, modelWrap) {
241
255
  if (!row || (row.result !== 0 && (row.result === '' || row.result == null))) {
@@ -244,8 +258,12 @@ export function indicatorScoreText(row, modelWrap) {
244
258
  if (!row.weight) {
245
259
  return resultByShowStyle(row, modelWrap)
246
260
  }
247
- const digits = digitsCalc(row, modelWrap)
248
- return N.div(N.mul(row.result, 100, digits + 2), row.weight, digits)
261
+ const raw = N.div(
262
+ N.mul(row.result, 100, SCORE_DIGITS + 2),
263
+ row.weight,
264
+ SCORE_DIGITS + 2
265
+ )
266
+ return formatScoreText(raw, { thousands: row.showStyle === 2 })
249
267
  }
250
268
 
251
269
  /** 是否展示满分值(showFullScore:1 展示;0 不展示;空值兼容旧数据按展示处理) */
@@ -214,7 +214,8 @@ import {
214
214
  isCalcRootModel as checkCalcRootModel,
215
215
  isStatRootModel as checkStatRootModel,
216
216
  subModelResultText as formatSubModelResult,
217
- saveSubModelValueText
217
+ saveSubModelValueText,
218
+ formatScoreText
218
219
  } from './helpers'
219
220
  import { preprocessStatIndicatorDeepList, mergeStatModelNode, statItemChildren } from './statModelHelper'
220
221
  import { withRequestTimestamp } from './api'
@@ -407,15 +408,21 @@ export default {
407
408
  if (this.model.version === '' || this.model.version == null) return '--'
408
409
  return `版本${this.model.version}`
409
410
  },
410
- /** 测算结果展示:优先 resultText,统计模型计算模式可回退到 result */
411
+ /** 测算结果展示:优先 resultText,统计模型计算模式可回退到 result;得分固定 2 位四舍五入 */
411
412
  displayResultText() {
412
- if (this.resultText !== '' && this.resultText != null) {
413
- return this.resultText
414
- }
415
- if (this.calcResult !== '' && this.calcResult != null) {
416
- return this.calcResult
413
+ const raw =
414
+ this.resultText !== '' && this.resultText != null
415
+ ? this.resultText
416
+ : this.calcResult !== '' && this.calcResult != null
417
+ ? this.calcResult
418
+ : null
419
+ if (raw === null || raw === '') return '--'
420
+ const text = String(raw).trim()
421
+ // 纯数字得分:固定 2 位;非数字文案原样展示
422
+ if (/^-?\d+(\.\d+)?$/.test(text)) {
423
+ return formatScoreText(text)
417
424
  }
418
- return '--'
425
+ return String(raw)
419
426
  },
420
427
  /** 评价模型展示「模型得分」,计算模型展示「模型公式」 */
421
428
  formulaRowLabel() {
@@ -1330,10 +1337,8 @@ export default {
1330
1337
  },
1331
1338
 
1332
1339
  formatScoreNum(val) {
1333
- if (val === '' || val == null) return ''
1334
- const digits = this.model.digits != null ? this.model.digits : 2
1335
- const num = Number(val)
1336
- return Number.isNaN(num) ? String(val) : num.toFixed(digits)
1340
+ // 得分固定 2 位四舍五入,不读模型 digits 配置
1341
+ return formatScoreText(val)
1337
1342
  },
1338
1343
 
1339
1344
  /**
@@ -262,6 +262,14 @@ function isShowFullScoreNode(row) {
262
262
  return !!(row && row.showFullScore !== 0)
263
263
  }
264
264
 
265
+ /**
266
+ * 统计项是否展示指标得分列(statShow:1 展示;0 不展示;空值经 resolveStatMeta 已默认 1)
267
+ * 与业务端 EvaOfCreditConditionsRewrite 一致
268
+ */
269
+ function isShowStatScoreCol(statMeta) {
270
+ return !!(statMeta && Number(statMeta.statShow) === 1)
271
+ }
272
+
265
273
  /** 某一统计项列是否需要「满分值」列(任一行开启则展示) */
266
274
  function shouldShowFullScoreCol(indicatorItems, statsName) {
267
275
  return (indicatorItems || []).some(ind => {
@@ -347,8 +355,8 @@ export async function buildStatModelTables(treeData, fetchScoreMap, modelWrap) {
347
355
  align: 'center',
348
356
  slotName: label
349
357
  })
350
- // 测算页始终展示指标得分列;statShow 仅约束业务端(授信等)是否展示
351
- if (statMeta.calType == 0) {
358
+ // 与业务端一致:按统计项「指标得分是否展示」(statShow) 决定是否展示得分列
359
+ if (statMeta.calType == 0 && isShowStatScoreCol(statMeta)) {
352
360
  columns.push({
353
361
  label: item.statsName + '指标得分',
354
362
  prop: item.statsName + '指标得分',