调整评分量化表
This commit is contained in:
@@ -129,7 +129,13 @@
|
||||
|
||||
<section-card title="评估标准">
|
||||
<template #extra>
|
||||
<el-button type="primary" plain icon="el-icon-plus" v-if="!readonly" @click="openStandard()">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
v-if="!readonly"
|
||||
@click="openStandard()"
|
||||
>
|
||||
添加评估标准
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -166,7 +172,13 @@
|
||||
<div class="category-line">评分类目:{{ currentCategory.categoryName }}</div>
|
||||
<section-card title="评分项目">
|
||||
<template #extra>
|
||||
<el-button type="primary" plain icon="el-icon-plus" v-if="!readonly" @click="openItem()">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
v-if="!readonly"
|
||||
@click="openItem()"
|
||||
>
|
||||
添加评分项目
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -218,23 +230,93 @@
|
||||
<el-input v-model="itemForm.itemName" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分值" required>
|
||||
<el-input-number v-model="itemForm.score" :min="1" :precision="0" :step="1" :controls="false" />
|
||||
<el-input-number
|
||||
v-model="itemForm.score"
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="得分说明">
|
||||
<el-input v-model="itemForm.scoreDescription" maxlength="300" class="score-description-input" />
|
||||
<el-input
|
||||
v-model="itemForm.scoreDescription"
|
||||
maxlength="300"
|
||||
class="score-description-input"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="选项描述">
|
||||
<el-input v-model="itemForm.optionDescription" maxlength="100" />
|
||||
</el-form-item>
|
||||
<el-form-item label="选项" required>
|
||||
<el-form-item label="选项类型" required>
|
||||
<el-radio-group v-model="itemForm.optionType" @change="handleOptionTypeChange">
|
||||
<el-radio value="option">选项</el-radio>
|
||||
<el-radio value="score">分值</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="itemForm.optionType === 'score'" label="基准数值" required>
|
||||
<el-input
|
||||
:model-value="itemForm.baseValue"
|
||||
inputmode="decimal"
|
||||
@input="handleBaseValueInput"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="itemForm.optionType === 'score' ? '阶梯配置' : '选项'" required>
|
||||
<div class="option-editor">
|
||||
<div class="option-row" v-for="(option, index) in itemForm.options" :key="index">
|
||||
<div
|
||||
class="option-row"
|
||||
:class="{ 'option-row--score': itemForm.optionType === 'score' }"
|
||||
v-for="(option, index) in itemForm.options"
|
||||
:key="index"
|
||||
>
|
||||
<template v-if="itemForm.optionType === 'score'">
|
||||
<el-select v-model="option.changeType" class="option-change-type">
|
||||
<el-option label="每增加" value="increase" />
|
||||
<el-option label="每减少" value="decrease" />
|
||||
</el-select>
|
||||
<el-input
|
||||
:model-value="option.changeValue"
|
||||
inputmode="decimal"
|
||||
@input="value => handleOptionDecimalInput(option, 'changeValue', value)"
|
||||
>
|
||||
<template #append>
|
||||
<el-select v-model="option.changeUnit" class="option-unit-select">
|
||||
<el-option
|
||||
v-for="unit in scoreUnitOptions"
|
||||
:key="unit"
|
||||
:label="unit"
|
||||
:value="unit"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select v-model="option.scoreType" class="option-score-type">
|
||||
<el-option label="加" value="add" />
|
||||
<el-option label="减" value="subtract" />
|
||||
</el-select>
|
||||
<div class="option-score">
|
||||
<el-input
|
||||
:model-value="option.score"
|
||||
inputmode="decimal"
|
||||
@input="value => handleOptionDecimalInput(option, 'score', value)"
|
||||
>
|
||||
<template #append>分</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-input v-model="option.optionName" maxlength="100" />
|
||||
<div class="option-score">
|
||||
<el-input-number v-model="option.score" :min="1" :precision="0" :step="1" :controls="false" />
|
||||
<span class="score-unit">分</span>
|
||||
<el-input
|
||||
:model-value="option.score"
|
||||
inputmode="decimal"
|
||||
@input="value => handleOptionDecimalInput(option, 'score', value)"
|
||||
>
|
||||
<template #append>分</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
<el-link
|
||||
type="danger"
|
||||
class="option-delete"
|
||||
@@ -244,10 +326,8 @@
|
||||
删除
|
||||
</el-link>
|
||||
</div>
|
||||
<div class="option-add">
|
||||
<el-link type="primary" v-if="!readonly" @click="addOption">
|
||||
+添加选项
|
||||
</el-link>
|
||||
<div class="option-add" v-if="itemForm.optionType !== 'score'">
|
||||
<el-link type="primary" v-if="!readonly" @click="addOption"> +添加选项 </el-link>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
@@ -267,7 +347,13 @@
|
||||
:close-on-press-escape="false"
|
||||
>
|
||||
<section-card title="评估标准设置">
|
||||
<el-form :model="standardForm" label-position="right" label-width="auto" :disabled="readonly" class="standard-form archive-form">
|
||||
<el-form
|
||||
:model="standardForm"
|
||||
label-position="right"
|
||||
label-width="auto"
|
||||
:disabled="readonly"
|
||||
class="standard-form archive-form"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="信用等级" required>
|
||||
@@ -413,6 +499,7 @@ export default {
|
||||
label: item,
|
||||
value: item,
|
||||
})),
|
||||
scoreUnitOptions: ['%', '件', '次', '项', '天'],
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
@@ -536,7 +623,19 @@ export default {
|
||||
score: 1,
|
||||
scoreDescription: '',
|
||||
optionDescription: '',
|
||||
options: [{ optionName: '', score: 1 }],
|
||||
optionType: 'option',
|
||||
baseValue: '',
|
||||
options: [this.emptyOption()],
|
||||
};
|
||||
},
|
||||
emptyOption() {
|
||||
return {
|
||||
optionName: '',
|
||||
score: 1,
|
||||
changeType: 'increase',
|
||||
changeValue: '',
|
||||
changeUnit: '%',
|
||||
scoreType: 'add',
|
||||
};
|
||||
},
|
||||
emptyStandard() {
|
||||
@@ -559,14 +658,20 @@ export default {
|
||||
...category,
|
||||
items: (category.items || []).map(item => ({
|
||||
...item,
|
||||
optionType: this.normalizeOptionType(item.optionType),
|
||||
options:
|
||||
item.options && item.options.length ? item.options : [{ optionName: '', score: 1 }],
|
||||
item.options && item.options.length
|
||||
? item.options.map(option => this.normalizeOption(option))
|
||||
: [this.emptyOption()],
|
||||
})),
|
||||
};
|
||||
});
|
||||
return {
|
||||
...detail,
|
||||
categories: categories.map(category => map[category.categoryCode] || category),
|
||||
categories: categories.map(category => ({
|
||||
...(map[category.categoryCode] || category),
|
||||
categoryName: category.categoryName,
|
||||
})),
|
||||
standards: detail.standards || [],
|
||||
};
|
||||
},
|
||||
@@ -596,10 +701,84 @@ export default {
|
||||
openItem(row, index = -1) {
|
||||
this.currentItemIndex = index;
|
||||
this.itemForm = row
|
||||
? { ...this.emptyItem(), ...JSON.parse(JSON.stringify(row)) }
|
||||
? this.normalizeItem({ ...this.emptyItem(), ...JSON.parse(JSON.stringify(row)) })
|
||||
: this.emptyItem();
|
||||
this.itemBox = true;
|
||||
},
|
||||
normalizeOptionType(value) {
|
||||
return value === 'score' || value === 2 || String(value) === 'score' ? 'score' : 'option';
|
||||
},
|
||||
normalizeItem(item = {}) {
|
||||
return {
|
||||
...this.emptyItem(),
|
||||
...item,
|
||||
optionType: this.normalizeOptionType(item.optionType),
|
||||
options:
|
||||
item.options && item.options.length
|
||||
? item.options.map(option => this.normalizeOption(option))
|
||||
: [this.emptyOption()],
|
||||
};
|
||||
},
|
||||
normalizeOption(option = {}) {
|
||||
const normalized = { ...this.emptyOption(), ...option };
|
||||
return {
|
||||
...normalized,
|
||||
changeType:
|
||||
normalized.changeType === 'decrease' ||
|
||||
normalized.changeType === '每减少' ||
|
||||
normalized.changeType === 2
|
||||
? 'decrease'
|
||||
: 'increase',
|
||||
scoreType:
|
||||
normalized.scoreType === 'subtract' ||
|
||||
normalized.scoreType === '减' ||
|
||||
normalized.scoreType === 2
|
||||
? 'subtract'
|
||||
: 'add',
|
||||
};
|
||||
},
|
||||
handleOptionTypeChange(value) {
|
||||
this.itemForm.optionType = this.normalizeOptionType(value);
|
||||
this.itemForm.options = (this.itemForm.options || []).map(option =>
|
||||
this.normalizeOption(option)
|
||||
);
|
||||
},
|
||||
handleBaseValueInput(value) {
|
||||
const source = String(value ?? '').replace(/[^\d.-]/g, '');
|
||||
const negative = source.startsWith('-');
|
||||
const unsigned = source.replace(/-/g, '');
|
||||
const [integer = '', ...decimalParts] = unsigned.split('.');
|
||||
const decimal = decimalParts.join('').slice(0, 10);
|
||||
this.itemForm.baseValue = `${negative ? '-' : ''}${integer}${decimalParts.length ? `.${decimal}` : ''}`;
|
||||
},
|
||||
handleOptionDecimalInput(option, field, value) {
|
||||
option[field] = this.normalizeDecimalInput(value);
|
||||
},
|
||||
normalizeDecimalInput(value) {
|
||||
const source = String(value ?? '').replace(/[^\d.]/g, '');
|
||||
const [integer = '', ...decimalParts] = source.split('.');
|
||||
const decimal = decimalParts.join('').slice(0, 2);
|
||||
return decimalParts.length ? `${integer}.${decimal}` : integer;
|
||||
},
|
||||
toScoreValue(value) {
|
||||
const number = Number(value);
|
||||
return Number.isFinite(number) ? number.toFixed(2) : value;
|
||||
},
|
||||
prepareSubmitConfig(config) {
|
||||
const payload = JSON.parse(JSON.stringify(config || {}));
|
||||
(payload.categories || []).forEach(category => {
|
||||
(category.items || []).forEach(item => {
|
||||
item.score = this.toScoreValue(item.score);
|
||||
(item.options || []).forEach(option => {
|
||||
option.score = this.toScoreValue(option.score);
|
||||
if (this.normalizeOptionType(item.optionType) === 'score') {
|
||||
option.changeValue = this.toScoreValue(option.changeValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
return payload;
|
||||
},
|
||||
hasDuplicateItemName(itemName, currentIndex = -1) {
|
||||
const name = String(itemName || '').trim();
|
||||
return this.currentCategory.items.some(
|
||||
@@ -623,14 +802,32 @@ export default {
|
||||
this.$message.warning('请输入分值');
|
||||
return;
|
||||
}
|
||||
if (!this.isPositiveInteger(this.itemForm.score)) {
|
||||
this.$message.warning('分值只能输入正整数');
|
||||
return;
|
||||
}
|
||||
if (!this.itemForm.options.length) {
|
||||
this.$message.warning('至少添加1条档位选项');
|
||||
return;
|
||||
}
|
||||
if (this.itemForm.optionType === 'score') {
|
||||
if (this.itemForm.options.length !== 1) {
|
||||
this.$message.warning('分值类型只能配置1条阶梯配置');
|
||||
return;
|
||||
}
|
||||
if (!this.isAnyNumber(this.itemForm.baseValue)) {
|
||||
this.$message.warning('请输入基准数值');
|
||||
return;
|
||||
}
|
||||
const invalidScoreOption = this.itemForm.options.some(
|
||||
option =>
|
||||
!option.changeType ||
|
||||
!this.isPositiveDecimal(option.changeValue) ||
|
||||
!option.changeUnit ||
|
||||
!option.scoreType ||
|
||||
!this.isPositiveDecimal(option.score)
|
||||
);
|
||||
if (invalidScoreOption) {
|
||||
this.$message.warning('请完整填写基础分值,并确保数值为正数且最多两位小数');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const invalidOption = this.itemForm.options.some(
|
||||
option =>
|
||||
!String(option.optionName || '').trim() ||
|
||||
@@ -642,18 +839,18 @@ export default {
|
||||
this.$message.warning('请完整填写档位选项');
|
||||
return;
|
||||
}
|
||||
if (this.itemForm.options.some(option => !this.isPositiveInteger(option.score))) {
|
||||
this.$message.warning('选项分数只能输入正整数');
|
||||
return;
|
||||
}
|
||||
const item = JSON.parse(JSON.stringify(this.itemForm));
|
||||
item.itemName = String(item.itemName || '').trim();
|
||||
item.optionType = this.normalizeOptionType(item.optionType);
|
||||
item.baseValue = item.optionType === 'score' ? String(item.baseValue).trim() : null;
|
||||
item.options = item.options.map(option => ({
|
||||
...option,
|
||||
optionName: String(option.optionName || '').trim(),
|
||||
score: Number(option.score),
|
||||
score: this.toScoreValue(option.score),
|
||||
...(item.optionType === 'score' ? { changeValue: this.toScoreValue(option.changeValue) } : {}),
|
||||
}));
|
||||
item.score = Number(item.score);
|
||||
item.score = this.toScoreValue(item.score);
|
||||
if (this.currentItemIndex >= 0) {
|
||||
this.currentCategory.items.splice(this.currentItemIndex, 1, item);
|
||||
} else {
|
||||
@@ -669,7 +866,7 @@ export default {
|
||||
this.currentCategory.items.splice(index, 1);
|
||||
},
|
||||
addOption() {
|
||||
this.itemForm.options.push({ optionName: '', score: 1 });
|
||||
this.itemForm.options.push(this.emptyOption());
|
||||
},
|
||||
removeOption(index) {
|
||||
this.itemForm.options.splice(index, 1);
|
||||
@@ -788,8 +985,20 @@ export default {
|
||||
isBlankValue(value) {
|
||||
return value === undefined || value === null || value === '';
|
||||
},
|
||||
isPositiveInteger(value) {
|
||||
return /^\d+$/.test(String(value)) && Number(value) > 0;
|
||||
isPositiveDecimal(value) {
|
||||
const number = Number(value);
|
||||
console.log(
|
||||
value,
|
||||
Number.isFinite(number),
|
||||
number,
|
||||
Math.abs(number * 100 - Math.round(number * 100))
|
||||
);
|
||||
if (!Number.isFinite(number) || number <= 0) return false;
|
||||
return Math.abs(number * 100 - Math.round(number * 100)) < 1e-8;
|
||||
},
|
||||
isAnyNumber(value) {
|
||||
const text = String(value ?? '').trim();
|
||||
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(text) && Number.isFinite(Number(text));
|
||||
},
|
||||
hasRangeOverlap(list, lowerProp, upperProp) {
|
||||
const ranges = list
|
||||
@@ -822,18 +1031,33 @@ export default {
|
||||
return false;
|
||||
}
|
||||
for (const item of category.items) {
|
||||
if (!this.isPositiveInteger(item.score)) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的分值只能为正整数`);
|
||||
return false;
|
||||
}
|
||||
if (!item.options || item.options.length === 0) {
|
||||
this.$message.warning(`${item.itemName}至少存在1条档位选项`);
|
||||
return false;
|
||||
}
|
||||
if (item.options.some(option => !this.isPositiveInteger(option.score))) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的选项分数只能为正整数`);
|
||||
if (this.normalizeOptionType(item.optionType) === 'score') {
|
||||
if (item.options.length !== 1) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的分值类型只能配置1条阶梯配置`);
|
||||
return false;
|
||||
}
|
||||
if (!this.isAnyNumber(item.baseValue)) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的基准数值不能为空且必须为数字`);
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
item.options.some(
|
||||
option =>
|
||||
!option.changeType ||
|
||||
!this.isPositiveDecimal(option.changeValue) ||
|
||||
!this.scoreUnitOptions.includes(option.changeUnit) ||
|
||||
!option.scoreType ||
|
||||
!this.isPositiveDecimal(option.score)
|
||||
)
|
||||
) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的基础分值配置不完整`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const creditLevels = this.configForm.standards
|
||||
@@ -862,14 +1086,33 @@ export default {
|
||||
this.$message.warning('发布前请完整填写评分项目名称');
|
||||
return false;
|
||||
}
|
||||
if (!this.isPositiveInteger(item.score)) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的分值只能为正整数`);
|
||||
return false;
|
||||
}
|
||||
if (!item.options || item.options.length === 0) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}至少配置1个档位选项`);
|
||||
return false;
|
||||
}
|
||||
if (this.normalizeOptionType(item.optionType) === 'score') {
|
||||
if (item.options.length !== 1) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的分值类型只能配置1条阶梯配置`);
|
||||
return false;
|
||||
}
|
||||
if (!this.isAnyNumber(item.baseValue)) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的基准数值不能为空且必须为数字`);
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
item.options.some(
|
||||
option =>
|
||||
!option.changeType ||
|
||||
!this.isPositiveDecimal(option.changeValue) ||
|
||||
!this.scoreUnitOptions.includes(option.changeUnit) ||
|
||||
!option.scoreType ||
|
||||
!this.isPositiveDecimal(option.score)
|
||||
)
|
||||
) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的基础分值配置不完整`);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const invalidOption = item.options.some(
|
||||
option => !String(option.optionName || '').trim() || this.isBlankValue(option.score)
|
||||
);
|
||||
@@ -877,9 +1120,6 @@ export default {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的档位选项未填写完整`);
|
||||
return false;
|
||||
}
|
||||
if (item.options.some(option => !this.isPositiveInteger(option.score))) {
|
||||
this.$message.warning(`${item.itemName || '评分项目'}的选项分数只能为正整数`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -938,7 +1178,7 @@ export default {
|
||||
saveConfig() {
|
||||
if (!this.validateConfig()) return;
|
||||
submit({
|
||||
...this.configForm,
|
||||
...this.prepareSubmitConfig(this.configForm),
|
||||
status: 3,
|
||||
}).then(() => {
|
||||
this.configBox = false;
|
||||
@@ -1157,6 +1397,31 @@ export default {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.option-row--score {
|
||||
grid-template-columns: 150px minmax(220px, 1fr) 110px 180px 74px;
|
||||
gap: 16px;
|
||||
|
||||
.option-score {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.option-change-type,
|
||||
.option-score-type {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.option-unit-select {
|
||||
width: 78px;
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border: 0;
|
||||
border-left: 1px solid #dcdfe6;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.option-score {
|
||||
position: relative;
|
||||
|
||||
@@ -1278,5 +1543,4 @@ export default {
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1210,6 +1210,17 @@
|
||||
<el-table-column label="评分标准" min-width="430">
|
||||
<template #default="{ row: detail }">
|
||||
<div class="score-standard-cell">
|
||||
<template v-if="isScoreTypeDetail(detail)">
|
||||
<el-input
|
||||
:model-value="detail.scoreInput"
|
||||
inputmode="decimal"
|
||||
:disabled="readonly"
|
||||
@input="value => handleScoreValueInput(detail, value)"
|
||||
>
|
||||
<template #append>{{ getScoreRule(detail)?.changeUnit || '' }}</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="score-standard-cell__label">请选择:</div>
|
||||
<el-select
|
||||
v-model="detail.selectedOption"
|
||||
@@ -1224,6 +1235,7 @@
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -2154,8 +2166,8 @@ export default {
|
||||
const scoreDetails = this.normalizeChangeFieldValue(score.details);
|
||||
const details = (Array.isArray(scoreDetails) ? scoreDetails : [])
|
||||
.map(detail => {
|
||||
const category =
|
||||
detail.categoryName || categoryNames[this.getScoreDetailCategoryCode(detail)] || '';
|
||||
const categoryCode = this.getScoreDetailCategoryCode(detail);
|
||||
const category = categoryNames[categoryCode] || detail.categoryName || '';
|
||||
const itemName = detail.itemName || '评分项目';
|
||||
const option = detail.selectedOption || detail.scoreDescription || '';
|
||||
const points = [
|
||||
@@ -3537,7 +3549,10 @@ export default {
|
||||
quantificationId: score.quantificationId ? String(score.quantificationId) : '',
|
||||
tempApplyCreditLimit: this.normalizeOptionalAmount(score.tempApplyCreditLimit),
|
||||
attachments: score.attachments || this.parseAttachments(score.proofAttachments),
|
||||
details: score.details || [],
|
||||
details: (score.details || []).map(detail => ({
|
||||
...detail,
|
||||
scoreInput: this.normalizeScoreInputValue(detail.scoreInput),
|
||||
})),
|
||||
};
|
||||
},
|
||||
normalizeOptionalAmount(value) {
|
||||
@@ -3836,6 +3851,7 @@ export default {
|
||||
...item,
|
||||
categoryCode: category.categoryCode,
|
||||
categoryName: category.categoryName,
|
||||
scoreInput: this.normalizeScoreInputValue(item.scoreInput),
|
||||
optionsJson:
|
||||
item.optionsJson ||
|
||||
JSON.stringify(
|
||||
@@ -3843,6 +3859,10 @@ export default {
|
||||
label: option.label || option.optionName || option.value,
|
||||
value: option.value || option.optionName || option.label,
|
||||
score: option.score,
|
||||
changeType: option.changeType,
|
||||
changeValue: option.changeValue,
|
||||
changeUnit: option.changeUnit,
|
||||
scoreType: option.scoreType,
|
||||
}))
|
||||
),
|
||||
}))
|
||||
@@ -3862,9 +3882,16 @@ export default {
|
||||
...detail,
|
||||
categoryCode: detail.categoryCode || category?.categoryCode || '',
|
||||
categoryName: detail.categoryName || category?.categoryName || '',
|
||||
scoreInput: this.normalizeScoreInputValue(detail.scoreInput),
|
||||
};
|
||||
});
|
||||
},
|
||||
normalizeScoreInputValue(value) {
|
||||
if (value === undefined || value === null || value === '' || value === -1 || value === '-1') {
|
||||
return '';
|
||||
}
|
||||
return String(value);
|
||||
},
|
||||
getScoreDetailCategoryCode(detail = {}) {
|
||||
const rawCode = String(
|
||||
detail.categoryCode ||
|
||||
@@ -3916,12 +3943,24 @@ export default {
|
||||
parseScoreOptions(value) {
|
||||
if (!value) return [];
|
||||
const normalize = list =>
|
||||
list.map(item => ({
|
||||
list.map(item => {
|
||||
const isScoreOption = item.changeType || item.changeValue || item.changeUnit;
|
||||
const changeLabel = item.changeType === 'decrease' ? '每减少' : '每增加';
|
||||
const scoreLabel = item.scoreType === 'subtract' ? '减' : '加';
|
||||
const generatedLabel = isScoreOption
|
||||
? `${changeLabel}${item.changeValue || ''}${item.changeUnit || ''}${scoreLabel}${item.score || ''}分`
|
||||
: '';
|
||||
const label = item.label || item.optionName || item.value || generatedLabel;
|
||||
return {
|
||||
...item,
|
||||
label: item.label || item.optionName || item.value,
|
||||
value: item.value || item.optionName || item.label,
|
||||
score: item.score,
|
||||
}));
|
||||
label,
|
||||
value: item.value || item.optionName || item.label || generatedLabel,
|
||||
score:
|
||||
item.scoreType === 'subtract' && item.score !== undefined
|
||||
? -Math.abs(Number(item.score))
|
||||
: item.score,
|
||||
};
|
||||
});
|
||||
if (Array.isArray(value)) return normalize(value);
|
||||
try {
|
||||
const options = JSON.parse(value);
|
||||
@@ -3930,6 +3969,50 @@ export default {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
isScoreTypeDetail(detail = {}) {
|
||||
return String(detail.optionType || '').toLowerCase() === 'score';
|
||||
},
|
||||
getScoreRule(detail = {}) {
|
||||
return this.parseScoreOptions(detail.optionsJson)[0] || null;
|
||||
},
|
||||
handleScoreValueInput(detail, value) {
|
||||
const raw = String(value ?? '')
|
||||
.replace(/[^\d.-]/g, '')
|
||||
.replace(/(?!^)-/g, '')
|
||||
.replace(/(\..*)\./g, '$1');
|
||||
const sign = raw.startsWith('-') ? '-' : '';
|
||||
const unsigned = raw.replace(/^-/, '');
|
||||
const hasDecimal = unsigned.includes('.');
|
||||
const [integerPart, decimalPart = ''] = unsigned.split('.');
|
||||
const normalized = `${sign}${integerPart}${hasDecimal ? `.${decimalPart.slice(0, 2)}` : ''}`;
|
||||
detail.scoreInput = normalized;
|
||||
const rule = this.getScoreRule(detail);
|
||||
if (!normalized || normalized === '-' || normalized === '.') {
|
||||
detail.selfScore = '';
|
||||
this.calculateScore(this.currentScore);
|
||||
return;
|
||||
}
|
||||
const base = Number(detail.baseValue);
|
||||
const input = Number(normalized);
|
||||
if (!rule || !Number.isFinite(base) || !Number.isFinite(input)) {
|
||||
detail.selfScore = '';
|
||||
this.calculateScore(this.currentScore);
|
||||
return;
|
||||
}
|
||||
const increase = rule.changeType !== 'decrease';
|
||||
const valid = increase ? input >= base : input <= base;
|
||||
if (!valid) {
|
||||
detail.selfScore = '';
|
||||
this.$message.warning(`输入值${increase ? '不能小于' : '不能大于'}基准数值${base}`);
|
||||
this.calculateScore(this.currentScore);
|
||||
return;
|
||||
}
|
||||
const distance = increase ? input - base : base - input;
|
||||
const stepScore = Math.abs(Number(rule.score || 0));
|
||||
const signedStep = rule.scoreType === 'subtract' ? -stepScore : stepScore;
|
||||
detail.selfScore = Number((Number(detail.score || 0) + distance * signedStep).toFixed(2));
|
||||
this.calculateScore(this.currentScore);
|
||||
},
|
||||
scoreOptionChange(detail, optionValue) {
|
||||
const option = this.parseScoreOptions(detail.optionsJson).find(
|
||||
item => item.value === optionValue
|
||||
@@ -4076,9 +4159,13 @@ export default {
|
||||
return score;
|
||||
},
|
||||
hasIncompleteBasicScoreDetail(details = []) {
|
||||
return this.getScoreCategoryDetailsByList(details, 'basic').some(
|
||||
item => !item.selectedOption
|
||||
);
|
||||
return this.getScoreCategoryDetailsByList(details, 'basic').some(item => {
|
||||
if (this.isScoreTypeDetail(item)) {
|
||||
const input = String(item.scoreInput ?? '').trim();
|
||||
return !input || !Number.isFinite(Number(input)) || item.selfScore === '';
|
||||
}
|
||||
return !item.selectedOption;
|
||||
});
|
||||
},
|
||||
finishScore(score) {
|
||||
if (!score.details || !score.details.length) {
|
||||
@@ -4086,7 +4173,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
if (this.hasIncompleteBasicScoreDetail(score.details)) {
|
||||
this.$message.warning('请完整选择基础得分项评分明细选项');
|
||||
this.$message.warning('请完整填写基础得分项评分明细');
|
||||
return;
|
||||
}
|
||||
this.calculateScore(score);
|
||||
@@ -4148,6 +4235,17 @@ export default {
|
||||
this.$message.warning('当前评分量化表未配置评分项目');
|
||||
return false;
|
||||
}
|
||||
const invalidScoreInput = this.currentScore.details.find(item => {
|
||||
if (!this.isScoreTypeDetail(item)) return false;
|
||||
const input = String(item.scoreInput ?? '').trim();
|
||||
return input !== '' && item.selfScore === '';
|
||||
});
|
||||
if (invalidScoreInput) {
|
||||
this.$message.warning(
|
||||
`${invalidScoreInput.itemName || '评分项目'}的输入值不符合基准数值限制,请重新填写`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
const overMaxReviewScore = this.currentScore.details.find(item => {
|
||||
if (
|
||||
item.reviewScore === undefined ||
|
||||
@@ -4169,7 +4267,7 @@ export default {
|
||||
return false;
|
||||
}
|
||||
if (requireComplete && this.hasIncompleteBasicScoreDetail(this.currentScore.details)) {
|
||||
this.$message.warning('请完整选择基础得分项评分明细选项');
|
||||
this.$message.warning('请完整填写基础得分项评分明细');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user