修复业务模块bug

This commit is contained in:
2026-08-14 02:49:46 +08:00
parent eceac8b31f
commit 6e012d766c
7 changed files with 1825 additions and 238 deletions
+100 -10
View File
@@ -49,6 +49,16 @@ const parseJsonObject = value => {
const parseProcessNodes = value => {
const result = parseJsonArray(value);
if (result.length) return result;
if (typeof value === 'string' && value.trim()) {
try {
const parsed = JSON.parse(value);
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
return Array.isArray(parsed.nodes) ? parsed.nodes : [];
}
} catch (error) {
return [];
}
}
if (!value || typeof value !== 'object' || Array.isArray(value)) return [];
return Array.isArray(value.nodes) ? value.nodes : [];
};
@@ -62,6 +72,75 @@ const requiresDriverAcceptConfirmation = processJson =>
node.confirmDriver === true
);
const getProcessConfigNodes = row => {
const sources = [
row.processJson,
row.processConfigJson,
row.projectProcessJson,
row.processConfig,
row.projectProcessConfig,
];
return sources.flatMap(source => {
const nodes = parseProcessNodes(source);
if (nodes.length || !source || typeof source !== 'object' || Array.isArray(source)) {
return nodes;
}
const configuredNodes = parseProcessNodes(source.nodeConfigJson);
const includedNodes = String(source.includedNodes || '')
.split(',')
.map(item => item.trim())
.filter(Boolean);
return configuredNodes.filter(
node =>
!includedNodes.length ||
includedNodes.includes(node.name) ||
includedNodes.includes(node.key)
);
});
};
const hasAcceptProcessNode = row =>
getProcessConfigNodes(row).some(
node => node.enabled !== false && (node.key === 'accept' || node.name === '接单')
);
const hasDriverAcceptRecord = row => {
const recordValues = [
row.driverAcceptTime,
row.driverAcceptedTime,
row.acceptTime,
row.driverAcceptId,
row.driverAcceptedBy,
row.acceptUserId,
row.acceptUserName,
];
if (recordValues.some(value => value !== null && value !== undefined && value !== '')) {
return true;
}
const statusValues = [
row.driverAcceptStatus,
row.driverAccepted,
row.driverAccept,
row.accepted,
row.isAccepted,
row.acceptStatus,
];
return statusValues.some(value => {
if (value === true) return true;
if (value === false || value === null || value === undefined || value === '') return false;
return ['1', 'true', 'accepted', 'confirmed', 'success', '已接单', '已确认'].includes(
String(value).toLowerCase()
);
});
};
const isInProgressStatus = (row, defaultText) =>
['processing', 'running', 'in_progress', 'inProgress'].includes(
String(row.businessStatus || row.status || row.waybillStatus || '')
) ||
String(defaultText || '').includes('进行中') ||
String(row.businessStatusName || row.statusName || '').includes('进行中');
const getFirstValue = (row, props) => {
const prop = props.find(item => !isEmpty(row[item]));
return prop ? row[prop] : '';
@@ -222,6 +301,14 @@ export const config = {
statusProp: 'businessStatus',
statusTextProp: 'businessStatusName',
formatStatus(row, prop, defaultText) {
if (
prop === 'businessStatus' &&
hasAcceptProcessNode(row) &&
isInProgressStatus(row, defaultText) &&
!hasDriverAcceptRecord(row)
) {
return '待执行';
}
if (
prop === 'businessStatus' &&
row.businessStatus === 'pending' &&
@@ -538,6 +625,19 @@ export const option = {
viewDisplay: false,
display: false,
},
{
label: '关联单号',
prop: 'relationNo',
search: true,
searchOrder: 2,
span: 6,
order: 820,
minWidth: 140,
hide: false,
addDisplay: true,
editDisplay: true,
viewDisplay: true,
},
{
label: '预计发货日期',
prop: 'estimatedStartTime',
@@ -684,16 +784,6 @@ export const option = {
editDisplay: false,
viewDisplay: false,
},
{
label: '关联单号',
prop: 'relationNo',
search: true,
searchOrder: 2,
span: 6,
order: 820,
minWidth: 140,
hide: true,
},
{
label: '货物信息',
prop: 'goodsJson',
File diff suppressed because it is too large Load Diff
@@ -39,7 +39,7 @@
</el-form>
<div class="waybill-import-create__form-actions"><el-button @click="createVisible = false">关闭</el-button><el-button @click="saveDraft">保存草稿</el-button><el-button type="primary" @click="confirmImport">确认导入</el-button></div>
</section>
<section class="waybill-import-create__detail-panel" v-if="rows.length"><div class="waybill-import-create__detail-head"><div class="dialog-section-title">导入数据明细</div><el-button type="danger" plain :disabled="!rowSelection.length" @click="removeSelectedRows">批量删除</el-button></div><el-tabs v-model="previewTab"><el-tab-pane :label="`运单数(${rows.length}`" name="all" /><el-tab-pane :label="`疑似重复(${duplicateRows.length}`" name="duplicate" /></el-tabs><el-table :data="previewRows" border max-height="440" @selection-change="rowSelection = $event"><el-table-column type="selection" width="55" /><el-table-column type="index" label="序号" width="65" /><el-table-column v-for="column in detailColumns" :key="column.prop" :prop="column.prop" :label="column.label" :min-width="column.minWidth || 150" show-overflow-tooltip><template #default="{ row }"><template v-if="row._editing"><el-select v-if="column.editor === 'transportType'" v-model="row.transportType" clearable filterable placeholder="请选择"><el-option v-for="item in transportTypeOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select><el-select v-else-if="column.editor === 'driver'" v-model="row.driverName" clearable filterable placeholder="请选择" @change="value => handleEditorChange(column, row, value)"><el-option v-for="item in driverOptions" :key="item.id || item.driverName || item.name" :label="item.driverName || item.name" :value="item.driverName || item.name" /></el-select><el-cascader v-else-if="column.editor === 'cargoType'" :model-value="resolveCargoTypePath(row)" :options="cargoTypeOptions" :props="{ label: 'cargoName', value: 'id', children: 'children', emitPath: true }" clearable filterable placeholder="请选择" @change="value => handleEditorChange(column, row, value)" /><el-select v-else-if="column.editor === 'cargoName'" v-model="row.cargoName" clearable filterable placeholder="请选择" @visible-change="visible => visible && loadCommonCargoOptions(row)" @change="value => handleEditorChange(column, row, value)"><el-option v-for="item in getCommonCargoOptions(row)" :key="item.id || item.cargoName || item.name" :label="formatCargoTypeLabel(item)" :value="formatCargoTypeLabel(item)" /></el-select><el-date-picker v-else-if="column.editor === 'datetime'" v-model="row[column.prop]" type="datetime" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择" /><el-input v-else-if="column.editor === 'textarea'" v-model="row[column.prop]" type="textarea" :autosize="{ minRows: 1, maxRows: 3 }" :placeholder="`请输入${column.label}`" /><el-input v-else-if="column.editor === 'number'" :model-value="row[column.prop]" inputmode="decimal" :placeholder="`请输入${column.label}`" @input="value => updateEditorValue(column, row, value)" /><el-input v-else v-model="row[column.prop]" :placeholder="`请输入${column.label}`" /></template><span v-else>{{ formatCell(row, column) }}</span></template></el-table-column><el-table-column label="操作" width="180" fixed="right"><template #default="{ row }"><template v-if="row._editing"><el-link type="primary" @click="saveRow(row)">保存</el-link><el-link type="primary" @click="cancelRow(row)">取消</el-link></template><template v-else><el-link type="primary" @click="editRow(row)">编辑</el-link><el-link type="danger" @click="deleteRow(row)">删除</el-link></template></template></el-table-column></el-table></section>
<section class="waybill-import-create__detail-panel" v-if="rows.length"><div class="waybill-import-create__detail-head"><div class="dialog-section-title">导入数据明细</div><el-button type="danger" plain :disabled="!rowSelection.length" @click="removeSelectedRows">批量删除</el-button></div><el-tabs v-model="previewTab"><el-tab-pane :label="`运单数(${rows.length}`" name="all" /><el-tab-pane :label="`疑似重复(${duplicateRows.length}`" name="duplicate" /></el-tabs><el-table :data="previewRows" border max-height="440" @selection-change="rowSelection = $event"><el-table-column type="selection" width="55" /><el-table-column type="index" label="序号" width="65" /><el-table-column v-for="column in detailColumns" :key="column.prop" :prop="column.prop" :label="column.label" :min-width="column.minWidth || 150" show-overflow-tooltip><template #default="{ row }"><template v-if="row._editing"><el-select v-if="column.editor === 'transportType'" v-model="row.transportType" clearable filterable placeholder="请选择"><el-option v-for="item in transportTypeOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select><el-select v-else-if="column.editor === 'driver'" v-model="row.driverName" clearable filterable placeholder="请选择" @change="value => handleEditorChange(column, row, value)"><el-option v-for="item in driverOptions" :key="item.id || item.driverName || item.name" :label="item.driverName || item.name" :value="item.driverName || item.name" /></el-select><el-cascader v-else-if="column.editor === 'cargoType'" :model-value="resolveCargoTypePath(row)" :options="cargoTypeOptions" :props="{ label: 'cargoName', value: 'id', children: 'children', emitPath: true }" clearable filterable placeholder="请选择" @change="value => handleEditorChange(column, row, value)" /><el-select v-else-if="column.editor === 'cargoName'" v-model="row.cargoName" clearable filterable placeholder="请选择" @visible-change="visible => visible && loadCommonCargoOptions(row)" @change="value => handleEditorChange(column, row, value)"><el-option v-for="item in getCommonCargoOptions(row)" :key="item.id || item.cargoName || item.name" :label="formatCargoTypeLabel(item)" :value="formatCargoTypeLabel(item)" /></el-select><el-date-picker v-else-if="column.editor === 'date'" v-model="row[column.prop]" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD" placeholder="请选择" /><el-input v-else-if="column.editor === 'textarea'" v-model="row[column.prop]" type="textarea" :autosize="{ minRows: 1, maxRows: 3 }" :placeholder="`请输入${column.label}`" /><el-input v-else-if="column.editor === 'number'" :model-value="row[column.prop]" inputmode="decimal" :placeholder="`请输入${column.label}`" @input="value => updateEditorValue(column, row, value)" /><el-input v-else v-model="row[column.prop]" :placeholder="`请输入${column.label}`" /></template><span v-else>{{ formatCell(row, column) }}</span></template></el-table-column><el-table-column label="操作" width="180" fixed="right"><template #default="{ row }"><template v-if="row._editing"><el-link type="primary" @click="saveRow(row)">保存</el-link><el-link type="primary" @click="cancelRow(row)">取消</el-link></template><template v-else><el-link type="primary" @click="editRow(row)">编辑</el-link><el-link type="danger" @click="deleteRow(row)">删除</el-link></template></template></el-table-column></el-table></section>
</el-dialog>
</template>
@@ -84,8 +84,8 @@ const detailColumns = [
{ prop: 'arrivalAddress', label: '到货地址', editor: 'textarea', minWidth: 260 },
{ prop: 'arrivalContact', label: '收货联系人', editor: 'input', minWidth: 140 },
{ prop: 'arrivalPhone', label: '收货联系人电话', editor: 'input', minWidth: 160 },
{ prop: 'startDate', label: '开始时间', editor: 'datetime', minWidth: 190 },
{ prop: 'endDate', label: '结束时间', editor: 'datetime', minWidth: 190 },
{ prop: 'startDate', label: '开始时间', editor: 'date', minWidth: 150 },
{ prop: 'endDate', label: '结束时间', editor: 'date', minWidth: 150 },
{ prop: 'unitPrice', label: '单价', editor: 'number', minWidth: 130 },
{ prop: 'freight', label: '运费', editor: 'number', minWidth: 130 },
{ prop: 'otherFeeTotal', label: '其他费用合计', editor: 'number', minWidth: 150 },
@@ -256,9 +256,17 @@ const fileChange = async (file, list) => {
const XLSX = await import('xlsx');
const workbook = XLSX.read(await file.raw.arrayBuffer(), { type: 'array', cellDates: true });
const source = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], { defval: '' }).map(item => Object.fromEntries(Object.entries(item).map(([key, value]) => [key.replace(/^\*/, ''), value])));
const keyMap = { '原始单号': 'originalNo', '车牌号/航班号/船号/班列号': 'vehicleNo', '司机/船长': 'driverName', '运输类型': 'transportType', '货物名称': 'cargoName', '货物类型': 'cargoType', '重量': 'quantity', '发货地址': 'departureAddress', '发货联系人': 'departureContact', '发货联系人电话': 'departurePhone', '到货地址': 'arrivalAddress', '收货联系人': 'arrivalContact', '收货联系人电话': 'arrivalPhone', '开始时间': 'startDate', '结束时间': 'endDate', '单价': 'unitPrice', '运费': 'freight', '其他费用合计': 'otherFeeTotal', '运费合计': 'freightTotal', '备注': 'remark' };
const keyMap = { originalNo: ['原始单号'], vehicleNo: ['车牌号/航班号/船号/班列号'], driverName: ['司机/船长'], transportType: ['运输类型'], cargoName: ['货物名称'], cargoType: ['货物类型'], quantity: ['重量'], departureAddress: ['发货地址'], departureContact: ['发货联系人'], departurePhone: ['发货联系人电话'], arrivalAddress: ['到货地址'], arrivalContact: ['到货联系人', '收货联系人'], arrivalPhone: ['收货联系人电话'], startDate: ['开始时间'], endDate: ['结束时间'], unitPrice: ['单价'], freight: ['运费'], otherFeeTotal: ['其他费用合计'], freightTotal: ['运费合计'], remark: ['备注'] };
const normalizeImportDate = value => {
if (value instanceof Date && !Number.isNaN(value.getTime())) {
const pad = number => String(number).padStart(2, '0');
return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
}
const text = String(value ?? '').trim();
return text.slice(0, 10);
};
const count = new Map();
rows.value = source.map((item, index) => { const row = { _key: `${Date.now()}-${index}`, batchNo: '', ...item }; Object.entries(keyMap).forEach(([label, key]) => { row[key] = item[label] ?? item[key] ?? ''; }); const duplicateKey = JSON.stringify(Object.values(keyMap).map(key => row[key])); count.set(duplicateKey, (count.get(duplicateKey) || 0) + 1); row._duplicateKey = duplicateKey; return row; });
rows.value = source.map((item, index) => { const row = { _key: `${Date.now()}-${index}`, batchNo: '', ...item }; Object.entries(keyMap).forEach(([key, labels]) => { row[key] = labels.map(label => item[label]).find(value => String(value ?? '').trim()) ?? item[key] ?? ''; }); row.startDate = normalizeImportDate(row.startDate); row.endDate = normalizeImportDate(row.endDate); const duplicateKey = JSON.stringify(Object.keys(keyMap).map(key => row[key])); count.set(duplicateKey, (count.get(duplicateKey) || 0) + 1); row._duplicateKey = duplicateKey; return row; });
rows.value.forEach(row => { row._duplicate = count.get(row._duplicateKey) > 1; });
};
const fileRemove = () => { files.value = []; form.file = null; };
+106 -20
View File
@@ -263,7 +263,19 @@
<el-table-column label="配载子单号" prop="loadingSubNos" min-width="220">
<template #default="{ row }">
<span class="loading-manage-page__sub-nos">
{{ splitText(row.loadingSubNos).join('') || '-' }}
<template v-if="splitText(row.loadingSubNos).length">
<el-link
v-for="(waybill, index) in splitText(row.loadingSubNos)"
:key="`${waybill}-${index}`"
type="primary"
class="loading-manage-page__sub-no-link"
@click="openWaybillDetail({ waybillNo: waybill, id: findWaybillId(row, waybill) })"
>
{{ waybill }}
<template v-if="index < splitText(row.loadingSubNos).length - 1">,</template>
</el-link>
</template>
<span v-else>-</span>
</span>
</template>
</el-table-column>
@@ -285,17 +297,23 @@
min-width="180"
>
<template #default="{ row }">
<div class="loading-manage-page__address-cell">{{ formatRouteAddress(row, 'departure') }}</div>
<el-tooltip :content="formatFullRouteAddress(row, 'departure')" placement="top">
<div class="loading-manage-page__address-cell">{{ formatRouteAddress(row, 'departure') }}</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="途经地" prop="transitAddress" min-width="190">
<template #default="{ row }">
<div class="loading-manage-page__address-cell">{{ formatRouteAddress(row, 'transit') }}</div>
<el-tooltip :content="formatFullRouteAddress(row, 'transit')" placement="top">
<div class="loading-manage-page__address-cell">{{ formatRouteAddress(row, 'transit') }}</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="到货地" prop="arrivalAddress" min-width="180">
<template #default="{ row }">
<div class="loading-manage-page__address-cell">{{ formatRouteAddress(row, 'arrival') }}</div>
<el-tooltip :content="formatFullRouteAddress(row, 'arrival')" placement="top">
<div class="loading-manage-page__address-cell">{{ formatRouteAddress(row, 'arrival') }}</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="承运商" prop="carrierName" min-width="160" show-overflow-tooltip />
@@ -1259,8 +1277,42 @@ export default {
.map(item => item.trim())
.filter(Boolean);
},
findWaybillId(row, waybillNo) {
const rows = this.splitText(row.loadingSubNos);
const index = rows.findIndex(item => item === waybillNo);
const linkedRows = this.parseJsonArray(row.waybillList || row.waybillRows || row.waybills);
if (linkedRows[index]?.id || linkedRows[index]?.waybillId) {
return linkedRows[index].id || linkedRows[index].waybillId;
}
const ids = this.parseJsonArray(row.waybillIdsJson);
return ids[index] || '';
},
async openWaybillDetail(row = {}) {
let id = row.id || row.waybillId || '';
if (!id && row.waybillNo) {
try {
const res = await getWaybillList(1, 1, { waybillNo: row.waybillNo });
const page = unwrapPage(res);
id = page.records?.[0]?.id || page[0]?.id || '';
} catch (error) {
id = '';
}
}
if (!id) {
ElMessage.info('当前子运单暂无详情数据');
return;
}
this.$router.push({ path: '/business/waybill-manage', query: { detailId: id } });
},
formatRouteAddress(row, type) {
const prefix = type === 'departure' ? 'departure' : type === 'arrival' ? 'arrival' : 'transit';
if (type !== 'transit') {
const address = row[`${prefix}Address`];
const region = this.routeProvinceName(row, prefix);
const district = row[`${prefix}DistrictName`];
const source = this.mergeRouteAddressParts(region, district, address);
return this.formatProvinceCityDistrict(source) || '-';
}
const values = [
row[`${prefix}RegionName`],
row[`${prefix}DistrictName`],
@@ -1268,24 +1320,50 @@ export default {
]
.filter(Boolean)
.flatMap(value => this.splitText(value))
.map(value => this.formatCityDistrict(value))
.map(value => this.formatProvinceCityDistrict(value))
.filter(Boolean);
return [...new Set(values)].join(',') || '-';
},
formatCityDistrict(value) {
formatFullRouteAddress(row, type) {
const prefix = type === 'departure' ? 'departure' : type === 'arrival' ? 'arrival' : 'transit';
if (type !== 'transit') {
const address = row[`${prefix}Address`];
const region = this.routeProvinceName(row, prefix);
const district = row[`${prefix}DistrictName`];
return this.mergeRouteAddressParts(region, district, address) || '-';
}
const values = [row.transitRegionName, row.transitDistrictName, row.transitAddress]
.filter(Boolean)
.flatMap(value => this.splitText(value));
return [...new Set(values)].join('') || '-';
},
mergeRouteAddressParts(region, district, address) {
const values = [region, district, address].map(value => String(value || '').trim()).filter(Boolean);
if (!values.length) return '';
return values.reduce((result, value) => {
if (!result) return value;
if (result.includes(value) || value.includes(result)) return result.length >= value.length ? result : value;
return `${result}${value}`;
}, '');
},
routeProvinceName(row, prefix) {
return [
row[`${prefix}ProvinceName`],
row[`${prefix}Province`],
row[`${prefix}RegionName`],
row[`${prefix}Region`],
row[`${prefix}Name`],
row[`${prefix}AdministrativeRegionName`],
row[`${prefix}AddressRegionName`],
].find(value => String(value || '').trim()) || '';
},
formatProvinceCityDistrict(value) {
const text = String(value || '').trim();
if (!text) return '';
const cityIndex = text.indexOf('市');
const provinceIndex = Math.max(text.lastIndexOf('省', cityIndex), text.lastIndexOf('自治区', cityIndex));
const cityStart = provinceIndex > -1 ? provinceIndex + 1 : 0;
const districtStart = cityIndex > -1 ? cityIndex + 1 : cityStart;
const districtMatch = text
.slice(districtStart)
.match(/(?:自治县|自治旗|林区|矿区|新区|开发区|区|县|旗)/);
if (districtMatch) {
return text.slice(cityStart, districtStart + districtMatch.index + districtMatch[0].length);
}
return cityIndex > -1 ? text.slice(cityStart, cityIndex + 1) : text;
const districtMatch = text.match(/(?:自治县|自治旗|林区|矿区|新区|开发区|区|县|旗)/);
if (districtMatch) return text.slice(0, districtMatch.index + districtMatch[0].length);
const cityMatch = text.match(/市/);
return cityMatch ? text.slice(0, cityMatch.index + 1) : text;
},
rowActions(row) {
const status = row.businessStatus;
@@ -2125,9 +2203,17 @@ export default {
.loading-manage-page__sub-nos {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 20px;
white-space: normal;
overflow-wrap: anywhere;
word-break: break-word;
}
.loading-manage-page__sub-no-link {
display: inline;
white-space: normal;
line-height: 20px;
text-align: left;
}
.loading-manage-page__address-cell {
+7 -2
View File
@@ -376,8 +376,13 @@ export default {
: 0;
},
async download() {
const blob = await api.exportList(this.query);
const url = URL.createObjectURL(new Blob([blob.data || blob]));
const response = await api.exportList(this.query);
const blob = response.data || response;
if (!(blob instanceof Blob) || !blob.size) {
this.$message.error('导出失败,未生成有效文件');
return;
}
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = '总单运单明细.xlsx';
@@ -218,11 +218,11 @@
<el-input v-model="itemForm.itemName" maxlength="20" />
</el-form-item>
<el-form-item label="分值" required>
<el-input-number v-model="itemForm.score" :min="0" :precision="2" :controls="false" />
<el-input-number v-model="itemForm.score" :min="1" :precision="0" :step="1" :controls="false" />
</el-form-item>
</div>
<el-form-item label="得分说明">
<el-input v-model="itemForm.scoreDescription" maxlength="300" />
<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" />
@@ -232,7 +232,7 @@
<div class="option-row" v-for="(option, index) in itemForm.options" :key="index">
<el-input v-model="option.optionName" maxlength="100" />
<div class="option-score">
<el-input-number v-model="option.score" :min="0" :precision="2" :controls="false" />
<el-input-number v-model="option.score" :min="1" :precision="0" :step="1" :controls="false" />
<span class="score-unit"></span>
</div>
<el-link
@@ -534,10 +534,10 @@ export default {
emptyItem() {
return {
itemName: '',
score: 0,
score: 1,
scoreDescription: '',
optionDescription: '',
options: [{ optionName: '', score: 0 }],
options: [{ optionName: '', score: 1 }],
};
},
emptyStandard() {
@@ -561,7 +561,7 @@ export default {
items: (category.items || []).map(item => ({
...item,
options:
item.options && item.options.length ? item.options : [{ optionName: '', score: 0 }],
item.options && item.options.length ? item.options : [{ optionName: '', score: 1 }],
})),
};
});
@@ -624,6 +624,10 @@ 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;
@@ -639,12 +643,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.options = item.options.map(option => ({
...option,
optionName: String(option.optionName || '').trim(),
score: Number(option.score),
}));
item.score = Number(item.score);
if (this.currentItemIndex >= 0) {
this.currentCategory.items.splice(this.currentItemIndex, 1, item);
} else {
@@ -660,7 +670,7 @@ export default {
this.currentCategory.items.splice(index, 1);
},
addOption() {
this.itemForm.options.push({ optionName: '', score: 0 });
this.itemForm.options.push({ optionName: '', score: 1 });
},
removeOption(index) {
this.itemForm.options.splice(index, 1);
@@ -779,6 +789,9 @@ export default {
isBlankValue(value) {
return value === undefined || value === null || value === '';
},
isPositiveInteger(value) {
return /^\d+$/.test(String(value)) && Number(value) > 0;
},
hasRangeOverlap(list, lowerProp, upperProp) {
const ranges = list
.map(item => ({
@@ -810,10 +823,18 @@ 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 || '评分项目'}的选项分数只能为正整数`);
return false;
}
}
}
const creditLevels = this.configForm.standards
@@ -842,6 +863,10 @@ 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;
@@ -853,6 +878,10 @@ 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;
}
}
}
@@ -1103,6 +1132,10 @@ export default {
text-align: center;
}
:deep(.score-description-input .el-input__inner) {
text-align: left;
}
&__top {
display: grid;
grid-template-columns: 360px 360px;
+30 -11
View File
@@ -564,9 +564,9 @@
<section-card title="客商材料">
<template #extra>
<div v-if="!readonly" class="section-actions">
<div class="section-actions">
<el-button icon="el-icon-download" @click="downloadAttachments">批量下载</el-button>
<el-button type="primary" icon="el-icon-upload" @click="addAttachment">
<el-button v-if="!readonly" type="primary" icon="el-icon-upload" @click="addAttachment">
OCR上传识别
</el-button>
</div>
@@ -1860,7 +1860,7 @@ export default {
const page = this.changeRecordPage;
getChangeRecordList(this.archiveForm.id, page.currentPage, page.pageSize).then(res => {
const data = res.data.data || {};
page.records = data.records || [];
page.records = this.replaceNegativeOneWithBlank(data.records || []);
page.total = Number(data.total || 0);
page.currentPage = Number(data.current || page.currentPage);
});
@@ -1883,10 +1883,11 @@ export default {
return (this.changeRecordPage.currentPage - 1) * this.changeRecordPage.pageSize + index + 1;
},
formatChangeData(row, column, value) {
if (!value) return '-';
if (!value || value === '-1') return '';
try {
return Object.entries(JSON.parse(value))
.map(([field, fieldValue]) => `${field}${fieldValue ?? '-'}`)
const data = this.replaceNegativeOneWithBlank(JSON.parse(value));
return Object.entries(data)
.map(([field, fieldValue]) => `${field}${fieldValue ?? ''}`)
.join('');
} catch (error) {
return value;
@@ -2866,6 +2867,19 @@ export default {
handleQualificationSelectionChange(rows) {
this.selectedQualificationFiles = rows || [];
},
replaceNegativeOneWithBlank(value) {
if (value === -1 || value === '-1') return '';
if (Array.isArray(value)) {
return value.map(item => this.replaceNegativeOneWithBlank(item));
}
if (value && typeof value === 'object') {
return Object.keys(value).reduce((result, key) => {
result[key] = this.replaceNegativeOneWithBlank(value[key]);
return result;
}, {});
}
return value;
},
normalizeDetail(detail) {
const businessScope = this.splitValue(detail.businessScope);
const registeredDetailAddress =
@@ -2970,12 +2984,15 @@ export default {
this.resetChangeRecordPage();
if (row && row.id) {
getDetail(row.id).then(res => {
this.archiveForm = this.normalizeDetail(res.data.data);
const archive = this.normalizeDetail(res.data.data);
this.archiveForm = readonly ? this.replaceNegativeOneWithBlank(archive) : archive;
this.originalAccessType = this.archiveForm.accessType || '';
this.qualificationFiles = this.parseAttachments(
this.archiveForm.qualificationAttachments
);
const qualificationFiles = this.parseAttachments(this.archiveForm.qualificationAttachments);
this.qualificationFiles = readonly
? this.replaceNegativeOneWithBlank(qualificationFiles)
: qualificationFiles;
this.qualificationUploadFiles = [];
this.selectedQualificationFiles = [];
this.archiveBox = true;
this.loadChangeRecords();
});
@@ -3516,7 +3533,9 @@ export default {
this.handleScoreCurrentChange(1);
},
formatScoreValue(value) {
return value === undefined || value === null || value === '' ? '' : value;
return value === undefined || value === null || value === '' || value === -1 || value === '-1'
? ''
: value;
},
rowDel(row) {
this.$confirm('仅草稿状态客商可删除,确定删除该数据?', {