@nstc-business/imes 1.1.5 → 1.1.6

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.1.5",
3
+ "version": "1.1.6",
4
4
  "private": false,
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -157,20 +157,28 @@
157
157
  <vxe-column title="模型指标得分" width="140" align="center">
158
158
  <template #default="{ row }">
159
159
  <div>{{ resultFn(row) }}</div>
160
- <InputNumber
161
- v-if="
160
+ <div
161
+ v-if="
162
162
  !isQualFn(row) &&
163
163
  row.result !== '' &&
164
164
  row.result !== null &&
165
165
  row.modifyRank === 1
166
166
  "
167
- class="full-w"
168
- :d-num="SCORE_DIGITS"
169
- :max="row.fullScore"
170
- :disabled="ctx.readonly"
171
- v-model="row.modifiedResult"
172
- placeholder="修改模型指标得分"
173
- />
167
+ class="modified-result-cell"
168
+ :class="{ 'is-over-limit': isModifiedResultOverFn(row) }"
169
+ >
170
+ <InputNumber
171
+ class="full-w"
172
+ :d-num="SCORE_DIGITS"
173
+ :disabled="ctx.readonly"
174
+ v-model="row.modifiedResult"
175
+ placeholder="修改模型指标得分"
176
+ @change="onModifiedResultChange(row)"
177
+ />
178
+ <div v-if="isModifiedResultOverFn(row)" class="modified-result-tip">
179
+ 调整得分不能超过{{ modifiedResultLimitTextFn(row) }}
180
+ </div>
181
+ </div>
174
182
  </template>
175
183
  </vxe-column>
176
184
  <vxe-column
@@ -245,7 +253,9 @@ import {
245
253
  indicatorResultText,
246
254
  fullScoreText,
247
255
  showLevelSerial,
248
- isShowFullScore
256
+ isShowFullScore,
257
+ modifiedResultLimitText,
258
+ isModifiedResultOverLimit
249
259
  } from './helpers'
250
260
  import { fillQualReasonFromOption } from './qualReason'
251
261
 
@@ -456,4 +466,15 @@ export default {
456
466
  /deep/ .el-select .el-input__inner {
457
467
  text-align: center;
458
468
  }
469
+ .modified-result-cell.is-over-limit ::v-deep .el-input__inner {
470
+ border-color: #ff3b30;
471
+ }
472
+ .modified-result-tip {
473
+ margin-top: 2px;
474
+ line-height: 16px;
475
+ font-size: 12px;
476
+ color: #ff3b30;
477
+ text-align: left;
478
+ white-space: normal;
479
+ }
459
480
  </style>
@@ -111,19 +111,27 @@
111
111
  <vxe-column title="指标得分" width="140" align="center">
112
112
  <template #default="{ row }">
113
113
  <div>{{ resultFn(row) }}</div>
114
- <InputNumber
115
- v-if="
114
+ <div
115
+ v-if="
116
116
  row.result !== '' &&
117
117
  row.result !== null &&
118
118
  row.modifyRank === 1
119
119
  "
120
- class="full-w"
121
- :d-num="SCORE_DIGITS"
122
- :max="row.fullScore"
123
- :disabled="ctx.readonly"
124
- v-model="row.modifiedResult"
125
- placeholder="修改指标得分"
126
- />
120
+ class="modified-result-cell"
121
+ :class="{ 'is-over-limit': isModifiedResultOverFn(row) }"
122
+ >
123
+ <InputNumber
124
+ class="full-w"
125
+ :d-num="SCORE_DIGITS"
126
+ :disabled="ctx.readonly"
127
+ v-model="row.modifiedResult"
128
+ placeholder="修改指标得分"
129
+ @change="onModifiedResultChange(row)"
130
+ />
131
+ <div v-if="isModifiedResultOverFn(row)" class="modified-result-tip">
132
+ 调整得分不能超过{{ modifiedResultLimitTextFn(row) }}
133
+ </div>
134
+ </div>
127
135
  </template>
128
136
  </vxe-column>
129
137
 
@@ -144,7 +152,9 @@ import {
144
152
  digitsCalc,
145
153
  SCORE_DIGITS,
146
154
  resultByShowStyle,
147
- indicatorResultText
155
+ indicatorResultText,
156
+ modifiedResultLimitText,
157
+ isModifiedResultOverLimit
148
158
  } from './helpers'
149
159
 
150
160
  /** 与表格列顺序一致,供 setMergeCells 计算列索引 */
@@ -207,6 +217,24 @@ export default {
207
217
  this.$set(row, 'scoreMapID', option.scoreMapID)
208
218
  this.$set(row, 'scoreText', option.scoreText)
209
219
  this.$set(row, 'scoreValue', option.scoreValue)
220
+ },
221
+ /** 调整得分上限展示文案(标红提示用) */
222
+ modifiedResultLimitTextFn(row) {
223
+ return modifiedResultLimitText(row)
224
+ },
225
+ /** 调整得分是否超限(标红判定) */
226
+ isModifiedResultOverFn(row) {
227
+ return isModifiedResultOverLimit(row)
228
+ },
229
+ /** 调整得分失焦提交:超限时弹出明显提示(不拦截输入、不改写原值) */
230
+ onModifiedResultChange(row) {
231
+ if (!isModifiedResultOverLimit(row)) return
232
+ const weightText =
233
+ row.weight === '' || row.weight == null ? 100 : row.weight
234
+ this.$message.warning(
235
+ `${row.name || '该指标'}的调整得分不能超过${modifiedResultLimitText(row)}` +
236
+ `(指标满分值${row.fullScore}×占模型权重${weightText}%)`
237
+ )
210
238
  }
211
239
  }
212
240
  }
@@ -258,4 +286,15 @@ export default {
258
286
  /deep/ .el-select .el-input__inner {
259
287
  text-align: center;
260
288
  }
289
+ .modified-result-cell.is-over-limit ::v-deep .el-input__inner {
290
+ border-color: #ff3b30;
291
+ }
292
+ .modified-result-tip {
293
+ margin-top: 2px;
294
+ line-height: 16px;
295
+ font-size: 12px;
296
+ color: #ff3b30;
297
+ text-align: left;
298
+ white-space: normal;
299
+ }
261
300
  </style>
@@ -182,19 +182,28 @@
182
182
  <vxe-column title="模型指标系数数值" min-width="200" align="center">
183
183
  <template #default="{ row }">
184
184
  <template v-if="isQuantIndicatorFn(row) || isSubModelFn(row)">
185
- <InputNumber
186
- v-if="
185
+ <div
186
+ v-if="
187
187
  isQuantIndicatorFn(row) &&
188
188
  row.modifyRank === 1 &&
189
189
  row.result !== '' &&
190
190
  row.result !== null
191
191
  "
192
- class="full-w"
193
- :d-num="SCORE_DIGITS"
194
- :disabled="ctx.readonly"
195
- v-model="row.modifiedResult"
196
- placeholder="请输入"
197
- />
192
+ class="modified-result-cell"
193
+ :class="{ 'is-over-limit': isModifiedResultOverFn(row) }"
194
+ >
195
+ <InputNumber
196
+ class="full-w"
197
+ :d-num="SCORE_DIGITS"
198
+ :disabled="ctx.readonly"
199
+ v-model="row.modifiedResult"
200
+ placeholder="请输入"
201
+ @change="onModifiedResultChange(row)"
202
+ />
203
+ <div v-if="isModifiedResultOverFn(row)" class="modified-result-tip">
204
+ 调整得分不能超过{{ modifiedResultLimitTextFn(row) }}
205
+ </div>
206
+ </div>
198
207
  <span v-else>{{ resultFn(row) }}</span>
199
208
  </template>
200
209
  <span v-else class="color-placeholder">—</span>
@@ -359,17 +368,25 @@
359
368
  <template #default="{ row }">
360
369
  <template v-if="isQuantIndicatorFn(row)">
361
370
  <div>{{ resultFn(row) }}</div>
362
- <InputNumber
363
- v-if="
371
+ <div
372
+ v-if="
364
373
  row.result !== '' && row.result !== null && row.modifyRank === 1
365
374
  "
366
- class="full-w"
367
- :d-num="SCORE_DIGITS"
368
- :max="row.fullScore"
369
- :disabled="ctx.readonly"
370
- v-model="row.modifiedResult"
371
- placeholder="修改模型指标得分"
372
- />
375
+ class="modified-result-cell"
376
+ :class="{ 'is-over-limit': isModifiedResultOverFn(row) }"
377
+ >
378
+ <InputNumber
379
+ class="full-w"
380
+ :d-num="SCORE_DIGITS"
381
+ :disabled="ctx.readonly"
382
+ v-model="row.modifiedResult"
383
+ placeholder="修改模型指标得分"
384
+ @change="onModifiedResultChange(row)"
385
+ />
386
+ <div v-if="isModifiedResultOverFn(row)" class="modified-result-tip">
387
+ 调整得分不能超过{{ modifiedResultLimitTextFn(row) }}
388
+ </div>
389
+ </div>
373
390
  </template>
374
391
  <template v-else-if="isSubModelFn(row) && ctx.parentCalced">
375
392
  <div>{{ resultFn(row) }}</div>
@@ -453,7 +470,9 @@ import {
453
470
  fullScoreText,
454
471
  hierarchySerial,
455
472
  hierarchySerialPrefix,
456
- isShowFullScore
473
+ isShowFullScore,
474
+ modifiedResultLimitText,
475
+ isModifiedResultOverLimit
457
476
  } from './helpers'
458
477
 
459
478
  export default {
@@ -684,6 +703,24 @@ export default {
684
703
  },
685
704
  childNumberPrefix(row) {
686
705
  return hierarchySerialPrefix(this.rowSerial(row))
706
+ },
707
+ /** 调整得分上限展示文案(标红提示用) */
708
+ modifiedResultLimitTextFn(row) {
709
+ return modifiedResultLimitText(row)
710
+ },
711
+ /** 调整得分是否超限(标红判定) */
712
+ isModifiedResultOverFn(row) {
713
+ return isModifiedResultOverLimit(row)
714
+ },
715
+ /** 调整得分失焦提交:超限时弹出明显提示(不拦截输入、不改写原值) */
716
+ onModifiedResultChange(row) {
717
+ if (!isModifiedResultOverLimit(row)) return
718
+ const weightText =
719
+ row.weight === '' || row.weight == null ? 100 : row.weight
720
+ this.$message.warning(
721
+ `${row.name || '该指标'}的调整得分不能超过${modifiedResultLimitText(row)}` +
722
+ `(指标满分值${row.fullScore}×占模型权重${weightText}%)`
723
+ )
687
724
  }
688
725
  }
689
726
  }
@@ -833,4 +870,15 @@ export default {
833
870
  color: #ff3b30 !important;
834
871
  }
835
872
  }
873
+ .modified-result-cell.is-over-limit ::v-deep .el-input__inner {
874
+ border-color: #ff3b30;
875
+ }
876
+ .modified-result-tip {
877
+ margin-top: 2px;
878
+ line-height: 16px;
879
+ font-size: 12px;
880
+ color: #ff3b30;
881
+ text-align: left;
882
+ white-space: normal;
883
+ }
836
884
  </style>
@@ -551,6 +551,62 @@ export function isSameScore(a, b) {
551
551
  if (Number.isNaN(na) || Number.isNaN(nb)) return false
552
552
  return na.toFixed(SCORE_DIGITS) === nb.toFixed(SCORE_DIGITS)
553
553
  }
554
+
555
+ /**
556
+ * 调整得分上限:指标满分值 × 占模型权重%
557
+ * 时间:2026-10-22 人员:Qoder && 辛善露
558
+ * 入参:node 指标行、digits 页面得分小数位
559
+ * 出参:Number 上限(已向下截断到 digits 位);null 表示不限制
560
+ * 方法内容:非「调整指标得分」不限制;满分值为空不限制(后端 compareFullScore 不生效);
561
+ * 权重为空按 100 处理(后端 multiplyWeight 权重为空时直接返回 result);
562
+ * 结果向下截断到页面得分小数位,保证提示上限即可输入的最大值
563
+ */
564
+ export function modifiedResultLimit(node, digits = SCORE_DIGITS) {
565
+ if (!node || node.modifyRank !== 1) return null
566
+ if (node.fullScore === '' || node.fullScore == null) return null
567
+ const full = Number(node.fullScore)
568
+ if (Number.isNaN(full)) return null
569
+ let weight = 100
570
+ if (node.weight !== '' && node.weight != null) {
571
+ weight = Number(node.weight)
572
+ if (Number.isNaN(weight)) return null
573
+ }
574
+ // 高精度乘除后按字符串截断,避免 0.29*100 之类的浮点误差
575
+ const raw = String(N.div(N.mul(full, weight, digits + 4), 100, digits + 4))
576
+ const [intPart, decPart = ''] = raw.split('.')
577
+ const cut = decPart.slice(0, digits).padEnd(digits, '0')
578
+ return Number(`${intPart}.${cut}`)
579
+ }
580
+
581
+ /**
582
+ * 调整得分上限展示文案
583
+ * 时间:2026-10-22 人员:Qoder && 辛善露
584
+ * 入参:node 指标行、digits 页面得分小数位
585
+ * 出参:String 上限文案(固定 digits 位);不限制返回空串
586
+ * 方法内容:用于标红文案与 warning 提示,保证与判定阈值同源
587
+ */
588
+ export function modifiedResultLimitText(node, digits = SCORE_DIGITS) {
589
+ const limit = modifiedResultLimit(node, digits)
590
+ return limit === null ? '' : limit.toFixed(digits)
591
+ }
592
+
593
+ /**
594
+ * 调整得分是否超过上限
595
+ * 时间:2026-10-22 人员:Qoder && 辛善露
596
+ * 入参:node 指标行、digits 页面得分小数位
597
+ * 出参:Boolean
598
+ * 方法内容:未调整(空值)或上限为 null 时返回 false;否则按数字比较
599
+ */
600
+ export function isModifiedResultOverLimit(node, digits = SCORE_DIGITS) {
601
+ if (!node || node.modifiedResult === '' || node.modifiedResult == null) {
602
+ return false
603
+ }
604
+ const limit = modifiedResultLimit(node, digits)
605
+ if (limit === null) return false
606
+ const val = Number(node.modifiedResult)
607
+ return !Number.isNaN(val) && val > limit
608
+ }
609
+
554
610
  let _uid = 0
555
611
  /**
556
612
  * 归一化整棵树:
@@ -256,7 +256,9 @@ import {
256
256
  resolveCalcEchoValue,
257
257
  shouldApplyModifiedVal,
258
258
  fillDefaultModifiedResult,
259
- isSameScore
259
+ isSameScore,
260
+ isModifiedResultOverLimit,
261
+ modifiedResultLimitText
260
262
  } from './helpers'
261
263
  import { preprocessStatIndicatorDeepList, mergeStatModelNode, statItemChildren } from './statModelHelper'
262
264
  import { withRequestTimestamp ,getCommonEnum } from './api'
@@ -542,6 +544,7 @@ export default {
542
544
  })
543
545
  },
544
546
  isSubModel,
547
+ isSameScore,
545
548
  subModelResultText(node) {
546
549
  return formatSubModelResult(node, this.model)
547
550
  },
@@ -984,10 +987,20 @@ export default {
984
987
  item.result !== null &&
985
988
  item.modifyRank === 1 &&
986
989
  (item.modifiedResult || item.modifiedResult === 0) &&
987
- !isSameScore(item.modifiedResult, item.result)
990
+ !this.isSameScore(item.modifiedResult, item.result)
988
991
  ) {
989
- calcItem.modifiedResult = item.modifiedResult
990
- hasCalc = true
992
+ if (isModifiedResultOverLimit(item)) {
993
+ // 超限:阻断测算,不写入 indicatorCalcList
994
+ obj.state = false
995
+ const weightText =
996
+ item.weight === '' || item.weight == null ? 100 : item.weight
997
+ this.messageStr +=
998
+ `${item.name}的调整得分不能超过${modifiedResultLimitText(item)}` +
999
+ `(指标满分值${item.fullScore}×占模型权重${weightText}%);`
1000
+ } else {
1001
+ calcItem.modifiedResult = item.modifiedResult
1002
+ hasCalc = true
1003
+ }
991
1004
  }
992
1005
  if (hasCalc) obj.indicatorCalcList.push(calcItem)
993
1006
  return obj