1、调整收付款
2、调整基础配置 3、调整结算
This commit is contained in:
@@ -10,6 +10,18 @@ export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get'
|
||||
export const getContractOptions = keyword =>
|
||||
request({ url: `${baseUrl}/contract-options`, method: 'get', params: { keyword } });
|
||||
|
||||
export const getContractList = (current, size, params) =>
|
||||
request({
|
||||
url: '/blade-transport/contract-manage/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
current,
|
||||
size,
|
||||
approvalStatuses: 'approved,change_approved',
|
||||
...params,
|
||||
},
|
||||
});
|
||||
|
||||
export const getFeeOptions = () => request({ url: `${baseUrl}/fee-options`, method: 'get' });
|
||||
|
||||
export const getCandidateDetails = (current, size, params) =>
|
||||
|
||||
@@ -138,4 +138,11 @@ export const generatePreviewColumns = [
|
||||
{ label: '货物名称', prop: 'cargoName', minWidth: 140 },
|
||||
{ label: '货物类型', prop: 'cargoType', minWidth: 140 },
|
||||
{ label: '规格', prop: 'specification', minWidth: 140 },
|
||||
{ label: '型号', prop: 'model', minWidth: 120 },
|
||||
{ label: '计费要素', prop: 'billingFactor', minWidth: 130 },
|
||||
{ label: '计费类型', prop: 'billingType', minWidth: 130 },
|
||||
{ label: '运输量', prop: 'transportQuantityText', minWidth: 120 },
|
||||
{ label: '运费计算单位', prop: 'priceUnit', minWidth: 130 },
|
||||
{ label: '运输单价', prop: 'unitPrice', minWidth: 120 },
|
||||
{ label: '里程(KM)', prop: 'mileage', minWidth: 120 },
|
||||
];
|
||||
|
||||
+49
-19
@@ -35,7 +35,6 @@
|
||||
v-model="form.feeCategory"
|
||||
class="fee-item-form-control"
|
||||
clearable
|
||||
:disabled="dialogType !== 'add'"
|
||||
filterable
|
||||
placeholder="请选择费用类型"
|
||||
@change="handleFeeCategoryChange"
|
||||
@@ -43,7 +42,7 @@
|
||||
<el-option
|
||||
v-for="item in feeCategoryOptions"
|
||||
:key="item.id || item.dictKey"
|
||||
:label="item.dictValue"
|
||||
:label="`${item.dictValue}/${item.dictKey}`"
|
||||
:value="item.dictKey"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -54,7 +53,6 @@
|
||||
:maxlength="feeItemCodeMaxlength"
|
||||
class="fee-item-form-control"
|
||||
clearable
|
||||
:disabled="dialogType !== 'add'"
|
||||
placeholder="请输入费用项代码"
|
||||
@change="handleFeeItemCodeChange"
|
||||
>
|
||||
@@ -339,31 +337,63 @@ export default {
|
||||
values.englishName = this.getFeeItemCodeSuffix(values.englishName, values.feeCategory);
|
||||
return values;
|
||||
},
|
||||
validateUnique(row) {
|
||||
const rowId = String(row.id || '');
|
||||
const hasDuplicate = (params, prop) => {
|
||||
if (!row[prop]) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
return getList(1, 100, params).then(res => {
|
||||
const records = res.data.data.records || [];
|
||||
return records.some(
|
||||
item =>
|
||||
String(item[prop] || '').trim() === String(row[prop]).trim() &&
|
||||
String(item.id || '') !== rowId
|
||||
);
|
||||
});
|
||||
};
|
||||
return Promise.all([
|
||||
hasDuplicate({ name: row.name }, 'name'),
|
||||
hasDuplicate({ englishName: row.englishName }, 'englishName'),
|
||||
]).then(([nameExists, codeExists]) => {
|
||||
if (nameExists) {
|
||||
return Promise.reject(new Error('该费用项已存在'));
|
||||
}
|
||||
if (codeExists) {
|
||||
return Promise.reject(new Error('该费用项代码已存在'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
},
|
||||
handleSubmitError(error, loading) {
|
||||
const uniqueMessages = ['该费用项已存在', '该费用项代码已存在'];
|
||||
if (uniqueMessages.includes(error.message)) {
|
||||
this.$message.warning(error.message);
|
||||
}
|
||||
window.console.log(error);
|
||||
loading();
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
submit(this.normalizeRow(row)).then(
|
||||
() => {
|
||||
const submitRow = this.normalizeRow(row);
|
||||
this.validateUnique(submitRow)
|
||||
.then(() => submit(submitRow))
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({ type: 'success', message: '操作成功!' });
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => this.handleSubmitError(error, loading));
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
submit(this.normalizeRow(row)).then(
|
||||
() => {
|
||||
const submitRow = this.normalizeRow(row);
|
||||
this.validateUnique(submitRow)
|
||||
.then(() => submit(submitRow))
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({ type: 'success', message: '操作成功!' });
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => this.handleSubmitError(error, loading));
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
|
||||
@@ -110,7 +110,9 @@
|
||||
maxlength="24"
|
||||
placeholder="请输入码头标识"
|
||||
@input="handleTerminalCodeChange"
|
||||
/>
|
||||
>
|
||||
<template v-if="form.parentCode" #prepend>{{ form.parentCode }}</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #menu="{ row, index }">
|
||||
|
||||
@@ -358,7 +358,10 @@ export default {
|
||||
formslot: true,
|
||||
minWidth: 130,
|
||||
overHidden: false,
|
||||
rules: [{ validator: validateLongitude, trigger: 'blur' }],
|
||||
rules: [
|
||||
{ required: true, message: '请输入经度', trigger: 'blur' },
|
||||
{ validator: validateLongitude, trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '纬度',
|
||||
@@ -366,7 +369,10 @@ export default {
|
||||
formslot: true,
|
||||
minWidth: 130,
|
||||
overHidden: false,
|
||||
rules: [{ validator: validateLatitude, trigger: 'blur' }],
|
||||
rules: [
|
||||
{ required: true, message: '请输入纬度', trigger: 'blur' },
|
||||
{ validator: validateLatitude, trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '行政区划编号',
|
||||
@@ -661,14 +667,14 @@ export default {
|
||||
return row;
|
||||
},
|
||||
validateCoordinateFields(row) {
|
||||
const longitudeMessage = getCoordinateValidationMessage(row.longitude, 'longitude');
|
||||
const longitudeMessage = getCoordinateValidationMessage(row.longitude, 'longitude', true);
|
||||
if (longitudeMessage) {
|
||||
this.$message.warning('经度范围不正确');
|
||||
this.$message.warning(longitudeMessage);
|
||||
return false;
|
||||
}
|
||||
const latitudeMessage = getCoordinateValidationMessage(row.latitude, 'latitude');
|
||||
const latitudeMessage = getCoordinateValidationMessage(row.latitude, 'latitude', true);
|
||||
if (latitudeMessage) {
|
||||
this.$message.warning('纬度范围不正确');
|
||||
this.$message.warning(latitudeMessage);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -18,25 +18,22 @@
|
||||
<el-row :gutter="24">
|
||||
<el-col v-for="field in formFields" :key="field.prop" :span="field.span || 6">
|
||||
<el-form-item :label="field.label" :prop="field.prop">
|
||||
<el-select
|
||||
<el-input
|
||||
v-if="field.type === 'contract'"
|
||||
v-model="form.contractId"
|
||||
filterable
|
||||
remote
|
||||
clearable
|
||||
:remote-method="loadContractOptions"
|
||||
:loading="contractLoading"
|
||||
v-model="form.contractName"
|
||||
readonly
|
||||
:disabled="!editable || details.length > 0"
|
||||
placeholder="请选择合同"
|
||||
@change="handleContractChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="`${item.contractName}(${item.contractNo || '-'})`"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<template #append>
|
||||
<el-button
|
||||
:disabled="!editable || details.length > 0"
|
||||
@click="openContractDialog"
|
||||
>
|
||||
选择
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-date-picker
|
||||
v-else-if="field.type === 'date'"
|
||||
v-model="form[field.prop]"
|
||||
@@ -126,6 +123,9 @@
|
||||
<el-input-number
|
||||
v-else-if="editable && column.prop === 'adjustAmount'"
|
||||
v-model="row.adjustAmount"
|
||||
:class="{
|
||||
'pre-settlement-editor__negative-amount': Number(row.adjustAmount || 0) < 0,
|
||||
}"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
@change="recalculateSummaryRow(row)"
|
||||
@@ -136,7 +136,13 @@
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
/>
|
||||
<span v-else-if="isSummaryMoney(column.prop)">
|
||||
<span
|
||||
v-else-if="isSummaryMoney(column.prop)"
|
||||
:class="{
|
||||
'pre-settlement-editor__negative-amount':
|
||||
column.prop === 'adjustAmount' && Number(row.adjustAmount || 0) < 0,
|
||||
}"
|
||||
>
|
||||
{{ formatMoney(row[column.prop], form.currency) }}
|
||||
</span>
|
||||
<span v-else-if="column.prop === 'feeType'">
|
||||
@@ -393,7 +399,9 @@
|
||||
|
||||
<template v-if="!pageMode" #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button v-if="editable" type="primary" plain :loading="saving" @click="saveDraft(false)">保存</el-button>
|
||||
<el-button v-if="editable" type="primary" plain :loading="saving" @click="saveDraft(false)"
|
||||
>保存</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="editable && hasPermission('pre_settlement_submit')"
|
||||
type="primary"
|
||||
@@ -405,7 +413,9 @@
|
||||
</template>
|
||||
<div v-if="pageMode" class="pre-settlement-editor__page-actions">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button v-if="editable" type="primary" plain :loading="saving" @click="saveDraft(false)">保存</el-button>
|
||||
<el-button v-if="editable" type="primary" plain :loading="saving" @click="saveDraft(false)"
|
||||
>保存</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="editable && hasPermission('pre_settlement_submit')"
|
||||
type="primary"
|
||||
@@ -492,6 +502,164 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="contractDialog.visible"
|
||||
title="选择合同"
|
||||
width="92%"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
class="pre-settlement-contract-dialog"
|
||||
>
|
||||
<el-form
|
||||
:model="contractDialog.query"
|
||||
inline
|
||||
label-position="right"
|
||||
label-width="auto"
|
||||
class="pre-settlement-editor__contract-filter"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="合同编号">
|
||||
<el-input
|
||||
v-model="contractDialog.query.contractNo"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadContractRows"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称">
|
||||
<el-input
|
||||
v-model="contractDialog.query.contractName"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadContractRows"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属项目">
|
||||
<el-input
|
||||
v-model="contractDialog.query.projectName"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadContractRows"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属组织">
|
||||
<el-input
|
||||
v-model="contractDialog.query.organizationName"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadContractRows"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同类别">
|
||||
<el-select v-model="contractDialog.query.contractCategory" clearable placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in contractCategoryOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="签约类型">
|
||||
<el-select v-model="contractDialog.query.signType" clearable placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in signTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="生效类型">
|
||||
<el-select v-model="contractDialog.query.effectiveType" clearable placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in effectiveTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同阶段">
|
||||
<el-select v-model="contractDialog.query.contractStage" clearable placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in contractStageOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="contractDialog.expanded" label="审核状态">
|
||||
<el-select v-model="contractDialog.query.approvalStatus" clearable placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in contractApprovalStatusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="pre-settlement-editor__contract-filter-actions">
|
||||
<el-button type="primary" @click="searchContractRows">查询</el-button>
|
||||
<el-button @click="resetContractQuery">重置</el-button>
|
||||
<el-button text @click="contractDialog.expanded = !contractDialog.expanded">
|
||||
{{ contractDialog.expanded ? '收起' : '展开' }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table
|
||||
v-loading="contractDialog.loading"
|
||||
:data="contractDialog.rows"
|
||||
border
|
||||
highlight-current-row
|
||||
@current-change="contractDialog.current = $event"
|
||||
@row-dblclick="selectContract"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column
|
||||
v-for="column in contractSelectionColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:min-width="column.minWidth"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="column.prop === 'organizationName'">{{
|
||||
row.organizationName || row.deptName || '-'
|
||||
}}</span>
|
||||
<span v-else-if="column.prop === 'contractCategory'">{{
|
||||
contractCategoryName(row.contractCategory)
|
||||
}}</span>
|
||||
<span v-else-if="column.prop === 'signType'">{{ signTypeName(row.signType) }}</span>
|
||||
<span v-else>{{ displayValue(row[column.prop]) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click.stop="selectContract(row)">选择</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pre-settlement-editor__pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="contractDialog.page.current"
|
||||
v-model:page-size="contractDialog.page.size"
|
||||
:total="contractDialog.page.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@current-change="loadContractRows"
|
||||
@size-change="handleContractSizeChange"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="contractDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="selectContract(contractDialog.current)">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="adjustDialog.visible"
|
||||
title="结算明细调整"
|
||||
@@ -613,7 +781,7 @@ import { mapGetters } from 'vuex';
|
||||
import {
|
||||
adjustDetail,
|
||||
getCandidateDetails,
|
||||
getContractOptions,
|
||||
getContractList,
|
||||
getDetail,
|
||||
getDetailFees,
|
||||
getFeeOptions,
|
||||
@@ -627,6 +795,13 @@ import {
|
||||
preSettlementFormFields,
|
||||
preSettlementFormRules,
|
||||
} from '@/option/settlement/preSettlementForm';
|
||||
import {
|
||||
contractApprovalStatusOptions,
|
||||
contractCategoryOptions,
|
||||
contractStageOptions,
|
||||
effectiveTypeOptions,
|
||||
signTypeOptions,
|
||||
} from '@/option/business/common';
|
||||
import {
|
||||
advanceColumns,
|
||||
candidateDetailColumns,
|
||||
@@ -675,8 +850,45 @@ export default {
|
||||
advanceTableColumns: advanceColumns,
|
||||
changeTableColumns: changeRecordColumns,
|
||||
candidateColumns: candidateDetailColumns,
|
||||
contractLoading: false,
|
||||
contractOptions: [],
|
||||
contractCategoryOptions,
|
||||
signTypeOptions,
|
||||
effectiveTypeOptions,
|
||||
contractStageOptions,
|
||||
contractApprovalStatusOptions,
|
||||
contractSelectionColumns: [
|
||||
{ prop: 'contractNo', label: '合同编号', minWidth: 180 },
|
||||
{ prop: 'contractName', label: '合同名称', minWidth: 220 },
|
||||
{ prop: 'projectName', label: '所属项目', minWidth: 170 },
|
||||
{ prop: 'organizationName', label: '所属组织', minWidth: 170 },
|
||||
{ prop: 'contractCategory', label: '合同类别', minWidth: 130 },
|
||||
{ prop: 'signType', label: '签约类型', minWidth: 120 },
|
||||
{ prop: 'partyA', label: '甲方', minWidth: 170 },
|
||||
{ prop: 'partyB', label: '乙方', minWidth: 170 },
|
||||
{ prop: 'startDate', label: '开始日期', minWidth: 130 },
|
||||
{ prop: 'endDate', label: '结束日期', minWidth: 130 },
|
||||
{ prop: 'temporaryStartDate', label: '临时效力起', minWidth: 130 },
|
||||
{ prop: 'temporaryEndDate', label: '临时效力止', minWidth: 130 },
|
||||
],
|
||||
contractDialog: {
|
||||
visible: false,
|
||||
loading: false,
|
||||
expanded: false,
|
||||
rows: [],
|
||||
current: null,
|
||||
query: {
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
projectName: '',
|
||||
organizationName: '',
|
||||
contractCategory: '',
|
||||
signType: '',
|
||||
effectiveType: '',
|
||||
contractStage: '',
|
||||
approvalStatus: '',
|
||||
},
|
||||
page: { current: 1, size: 10, total: 0 },
|
||||
},
|
||||
feeOptions: [],
|
||||
feeCategoryOptions: [],
|
||||
transportTypeOptions: [],
|
||||
@@ -857,7 +1069,6 @@ export default {
|
||||
},
|
||||
async initialize() {
|
||||
this.resetEditor();
|
||||
await this.loadContractOptions('');
|
||||
await this.loadFeeOptions();
|
||||
await this.loadFeeCategoryOptions();
|
||||
if (this.pageMode) await this.loadTransportTypeOptions();
|
||||
@@ -935,6 +1146,12 @@ export default {
|
||||
this.changeRecords = [];
|
||||
this.attachments = [];
|
||||
this.selectedAttachmentRows = [];
|
||||
this.contractOptions = [];
|
||||
this.contractDialog.visible = false;
|
||||
this.contractDialog.expanded = false;
|
||||
this.contractDialog.rows = [];
|
||||
this.contractDialog.current = null;
|
||||
this.contractDialog.page = { current: 1, size: 10, total: 0 };
|
||||
this.$nextTick(() => this.$refs.formRef?.clearValidate());
|
||||
},
|
||||
async loadDetail() {
|
||||
@@ -969,15 +1186,85 @@ export default {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async loadContractOptions(keyword = '') {
|
||||
this.contractLoading = true;
|
||||
openContractDialog() {
|
||||
if (!this.editable || this.details.length > 0) return;
|
||||
this.contractDialog.visible = true;
|
||||
this.contractDialog.expanded = false;
|
||||
this.contractDialog.current = null;
|
||||
this.contractDialog.page.current = 1;
|
||||
this.loadContractRows();
|
||||
},
|
||||
async loadContractRows() {
|
||||
this.contractDialog.loading = true;
|
||||
try {
|
||||
const { data } = await getContractOptions(keyword);
|
||||
this.contractOptions = data?.data || [];
|
||||
const { data } = await getContractList(
|
||||
this.contractDialog.page.current,
|
||||
this.contractDialog.page.size,
|
||||
{ ...this.contractDialog.query }
|
||||
);
|
||||
const page = data?.data || {};
|
||||
this.contractDialog.rows = page.records || [];
|
||||
this.contractDialog.page.total = Number(page.total || 0);
|
||||
} finally {
|
||||
this.contractLoading = false;
|
||||
this.contractDialog.loading = false;
|
||||
}
|
||||
},
|
||||
searchContractRows() {
|
||||
this.contractDialog.page.current = 1;
|
||||
this.loadContractRows();
|
||||
},
|
||||
resetContractQuery() {
|
||||
this.contractDialog.query = {
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
projectName: '',
|
||||
organizationName: '',
|
||||
contractCategory: '',
|
||||
signType: '',
|
||||
effectiveType: '',
|
||||
contractStage: '',
|
||||
approvalStatus: '',
|
||||
};
|
||||
this.searchContractRows();
|
||||
},
|
||||
handleContractSizeChange() {
|
||||
this.contractDialog.page.current = 1;
|
||||
this.loadContractRows();
|
||||
},
|
||||
selectContract(row) {
|
||||
if (!row) {
|
||||
this.$message.warning('请选择合同');
|
||||
return;
|
||||
}
|
||||
const contract = {
|
||||
...row,
|
||||
deptId: row.deptId || row.organizationId,
|
||||
deptName: row.deptName || row.organizationName,
|
||||
partyA: row.partyA || row.payerName,
|
||||
partyB: row.partyB || row.payeeName,
|
||||
settlementType:
|
||||
row.settlementType || (row.contractCategory === '客户合同' ? 'receivable' : 'payable'),
|
||||
};
|
||||
const index = this.contractOptions.findIndex(item => String(item.id) === String(contract.id));
|
||||
if (index >= 0) this.contractOptions.splice(index, 1, contract);
|
||||
else this.contractOptions.push(contract);
|
||||
this.handleContractChange(contract.id);
|
||||
this.contractDialog.visible = false;
|
||||
this.contractDialog.current = null;
|
||||
this.$refs.formRef?.clearValidate('contractId');
|
||||
},
|
||||
contractCategoryName(value) {
|
||||
return (
|
||||
this.contractCategoryOptions.find(item => String(item.value) === String(value))?.label ||
|
||||
this.displayValue(value)
|
||||
);
|
||||
},
|
||||
signTypeName(value) {
|
||||
return (
|
||||
this.signTypeOptions.find(item => String(item.value) === String(value))?.label ||
|
||||
this.displayValue(value)
|
||||
);
|
||||
},
|
||||
async loadFeeOptions() {
|
||||
const { data } = await getFeeOptions();
|
||||
this.feeOptions = data?.data || [];
|
||||
@@ -993,6 +1280,7 @@ export default {
|
||||
handleContractChange(id) {
|
||||
const contract = this.contractOptions.find(item => String(item.id) === String(id));
|
||||
if (!contract) {
|
||||
this.form.contractId = '';
|
||||
this.form.contractNo = '';
|
||||
this.form.contractName = '';
|
||||
this.form.projectId = '';
|
||||
@@ -1004,6 +1292,7 @@ export default {
|
||||
this.summaryFees = [];
|
||||
return;
|
||||
}
|
||||
this.form.contractId = contract.id;
|
||||
this.form.contractNo = contract.contractNo;
|
||||
this.form.contractName = contract.contractName;
|
||||
this.form.projectId = contract.projectId;
|
||||
@@ -1166,9 +1455,7 @@ export default {
|
||||
this.details.forEach(row => {
|
||||
const feeItems = this.parseFeeItems(row.feeItemsJson || row.feeItems);
|
||||
const feeItemEntries = Object.entries(feeItems);
|
||||
feeItemEntries.forEach(([feeItem, amount]) =>
|
||||
appendSummary(feeItem, amount, row.feeType)
|
||||
);
|
||||
feeItemEntries.forEach(([feeItem, amount]) => appendSummary(feeItem, amount, row.feeType));
|
||||
|
||||
let knownAmount = feeItemEntries.reduce(
|
||||
(total, [, amount]) => total + Number(amount || 0),
|
||||
@@ -1186,11 +1473,7 @@ export default {
|
||||
}
|
||||
|
||||
const totalAmount = Number(
|
||||
row.settlementAmountTax ??
|
||||
row.totalAmount ??
|
||||
row.afterAmount ??
|
||||
row.settlementAmount ??
|
||||
0
|
||||
row.settlementAmountTax ?? row.totalAmount ?? row.afterAmount ?? row.settlementAmount ?? 0
|
||||
);
|
||||
const residualAmount = Number((totalAmount - knownAmount).toFixed(2));
|
||||
if (Math.abs(residualAmount) >= 0.005) {
|
||||
@@ -1621,6 +1904,39 @@ export default {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
&__contract-filter {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 8px 24px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
:deep(.el-form-item) {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:deep(.el-input),
|
||||
:deep(.el-select) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__contract-filter-actions {
|
||||
grid-column: 1 / -1;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
&__attachment-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1649,6 +1965,14 @@ export default {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__negative-amount {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
:deep(.pre-settlement-editor__negative-amount .el-input__inner) {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
&__pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="变更记录" name="change">
|
||||
<el-table v-loading="changeDialog.loading" :data="changeRows" border>
|
||||
<el-table v-loading="latestChangeLoading" :data="latestChangeRows" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column
|
||||
v-for="column in changeRecordColumns"
|
||||
@@ -161,17 +161,17 @@
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="操作" width="120" fixed="right" align="center">
|
||||
<template #default>
|
||||
<el-link type="primary" @click="openChangeRecordsDialog">查看详情</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="settlement-detail-page__pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="changePage.current"
|
||||
v-model:page-size="changePage.size"
|
||||
:total="changePage.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@current-change="loadChangeRecords"
|
||||
@size-change="handleChangeSizeChange"
|
||||
/>
|
||||
<div
|
||||
v-if="!latestChangeLoading && !latestChangeRows.length"
|
||||
class="settlement-detail-page__empty"
|
||||
>
|
||||
暂无变更记录
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -182,6 +182,37 @@
|
||||
</section>
|
||||
</teleport>
|
||||
|
||||
<el-dialog
|
||||
v-model="changeRecordsDialog.visible"
|
||||
title="变更记录详情"
|
||||
width="88%"
|
||||
append-to-body
|
||||
>
|
||||
<el-table v-loading="changeRecordsDialog.loading" :data="changeRows" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column
|
||||
v-for="column in changeRecordColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:min-width="column.minWidth"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
</el-table>
|
||||
<div class="settlement-detail-page__pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="changePage.current"
|
||||
v-model:page-size="changePage.size"
|
||||
:total="changePage.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@current-change="loadChangeRecords"
|
||||
@size-change="handleChangeSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<teleport to="body">
|
||||
<section
|
||||
v-if="adjustDialog.visible"
|
||||
@@ -365,19 +396,12 @@
|
||||
inputmode="decimal"
|
||||
@input="value => handleAdjustFeeItemInput(row, column.feeItemName, value)"
|
||||
/>
|
||||
<el-input
|
||||
v-else-if="column.prop === 'remark'"
|
||||
v-model="row.remark"
|
||||
clearable
|
||||
maxlength="200"
|
||||
placeholder="请输入备注"
|
||||
/>
|
||||
<el-input
|
||||
v-else-if="column.prop === 'changeReason'"
|
||||
v-model="row.changeReason"
|
||||
clearable
|
||||
maxlength="300"
|
||||
placeholder="请输入变更原因"
|
||||
placeholder="请输入调整原因"
|
||||
/>
|
||||
<span v-else-if="column.prop === 'adjustAmountText'">
|
||||
{{ fixedTwoDecimals(row.adjustAmount) }}
|
||||
@@ -545,22 +569,16 @@
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="运单合同" required>
|
||||
<el-select
|
||||
v-model="generateQuery.contractId"
|
||||
<el-input
|
||||
:model-value="generateContractName"
|
||||
class="settlement-detail-page__generate-select"
|
||||
filterable
|
||||
clearable
|
||||
:loading="contractLoading"
|
||||
readonly
|
||||
placeholder="请选择合同"
|
||||
@change="handleGenerateContractChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<template #append>
|
||||
<el-button @click="openGenerateContractDialog">选择</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="计费方案" required>
|
||||
<el-select
|
||||
@@ -673,6 +691,180 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="generateContractDialog.visible"
|
||||
title="选择合同"
|
||||
width="92%"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
class="settlement-detail-page__contract-dialog"
|
||||
>
|
||||
<el-form
|
||||
:model="generateContractDialog.query"
|
||||
label-position="right"
|
||||
label-width="auto"
|
||||
class="settlement-detail-page__contract-filter"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="合同编号">
|
||||
<el-input
|
||||
v-model="generateContractDialog.query.contractNo"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadGenerateContracts"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称">
|
||||
<el-input
|
||||
v-model="generateContractDialog.query.contractName"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadGenerateContracts"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属项目">
|
||||
<el-input
|
||||
v-model="generateContractDialog.query.projectName"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadGenerateContracts"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属组织">
|
||||
<el-input
|
||||
v-model="generateContractDialog.query.organizationName"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@keyup.enter="loadGenerateContracts"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同类别">
|
||||
<el-select :model-value="generateContractCategory" disabled placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in contractCategoryOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="签约类型">
|
||||
<el-select v-model="generateContractDialog.query.signType" clearable placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in signTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="生效类型">
|
||||
<el-select
|
||||
v-model="generateContractDialog.query.effectiveType"
|
||||
clearable
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in effectiveTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同阶段">
|
||||
<el-select
|
||||
v-model="generateContractDialog.query.contractStage"
|
||||
clearable
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in contractStageOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="generateContractDialog.expanded" label="审核状态">
|
||||
<el-select
|
||||
v-model="generateContractDialog.query.approvalStatus"
|
||||
clearable
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in contractApprovalStatusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="settlement-detail-page__contract-filter-actions">
|
||||
<el-button type="primary" @click="searchGenerateContracts">查询</el-button>
|
||||
<el-button @click="resetGenerateContractQuery">重置</el-button>
|
||||
<el-button
|
||||
text
|
||||
@click="generateContractDialog.expanded = !generateContractDialog.expanded"
|
||||
>
|
||||
{{ generateContractDialog.expanded ? '收起' : '展开' }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table
|
||||
v-loading="generateContractDialog.loading"
|
||||
:data="generateContractDialog.rows"
|
||||
border
|
||||
highlight-current-row
|
||||
@current-change="generateContractDialog.current = $event"
|
||||
@row-dblclick="selectGenerateContract"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column
|
||||
v-for="column in contractSelectionColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:min-width="column.minWidth"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="column.prop === 'organizationName'">{{
|
||||
row.organizationName || row.deptName || '-'
|
||||
}}</span>
|
||||
<span v-else-if="column.prop === 'contractCategory'">{{
|
||||
contractCategoryName(row.contractCategory)
|
||||
}}</span>
|
||||
<span v-else-if="column.prop === 'signType'">{{ signTypeName(row.signType) }}</span>
|
||||
<span v-else>{{ displayValue(row[column.prop]) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click.stop="selectGenerateContract(row)">选择</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="settlement-detail-page__pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="generateContractDialog.page.current"
|
||||
v-model:page-size="generateContractDialog.page.size"
|
||||
:total="generateContractDialog.page.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@current-change="loadGenerateContracts"
|
||||
@size-change="handleGenerateContractSizeChange"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="generateContractDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="selectGenerateContract(generateContractDialog.current)">
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
@@ -698,6 +890,28 @@ import { exportBlob } from '@/api/common';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import { createSettlementTransfer } from '@/utils/settlement-transfer';
|
||||
import {
|
||||
contractApprovalStatusOptions,
|
||||
contractCategoryOptions,
|
||||
contractStageOptions,
|
||||
effectiveTypeOptions,
|
||||
signTypeOptions,
|
||||
} from '@/option/business/common';
|
||||
|
||||
const contractSelectionColumns = [
|
||||
{ prop: 'contractNo', label: '合同编号', minWidth: 180 },
|
||||
{ prop: 'contractName', label: '合同名称', minWidth: 220 },
|
||||
{ prop: 'projectName', label: '所属项目', minWidth: 170 },
|
||||
{ prop: 'organizationName', label: '所属组织', minWidth: 170 },
|
||||
{ prop: 'contractCategory', label: '合同类别', minWidth: 130 },
|
||||
{ prop: 'signType', label: '签约类型', minWidth: 120 },
|
||||
{ prop: 'partyA', label: '甲方', minWidth: 170 },
|
||||
{ prop: 'partyB', label: '乙方', minWidth: 170 },
|
||||
{ prop: 'startDate', label: '开始日期', minWidth: 130 },
|
||||
{ prop: 'endDate', label: '结束日期', minWidth: 130 },
|
||||
{ prop: 'temporaryStartDate', label: '临时效力起', minWidth: 130 },
|
||||
{ prop: 'temporaryEndDate', label: '临时效力止', minWidth: 130 },
|
||||
];
|
||||
|
||||
const ADJUST_BILLING_ELEMENTS = [
|
||||
'按重量',
|
||||
@@ -777,15 +991,22 @@ export default {
|
||||
priceUnitRequest: null,
|
||||
changeRows: [],
|
||||
changePage: { current: 1, size: 10, total: 0 },
|
||||
changeDialog: { loading: false },
|
||||
latestChangeRows: [],
|
||||
latestChangeLoading: false,
|
||||
changeRecordsDialog: { visible: false, loading: false },
|
||||
updateFeeDialog: { visible: false, submitting: false, row: null },
|
||||
updateFeeForm: { contractId: '', billingPlanId: '' },
|
||||
updateFeeRules: {
|
||||
contractId: [{ required: true, message: '请选择更新范围', trigger: 'change' }],
|
||||
},
|
||||
contractOptions: [],
|
||||
contractLoading: false,
|
||||
updateContractOptions: [],
|
||||
contractCategoryOptions,
|
||||
signTypeOptions,
|
||||
effectiveTypeOptions,
|
||||
contractStageOptions,
|
||||
contractApprovalStatusOptions,
|
||||
contractSelectionColumns,
|
||||
transportTypeOptions: [],
|
||||
billingPlanOptions: [],
|
||||
transferDialog: { visible: false, loading: false, submitting: false },
|
||||
@@ -796,6 +1017,25 @@ export default {
|
||||
transferPage: { current: 1, size: 10, total: 0 },
|
||||
generateDialog: { visible: false, loading: false },
|
||||
generateQuery: {},
|
||||
generateContractDialog: {
|
||||
visible: false,
|
||||
loading: false,
|
||||
expanded: false,
|
||||
rows: [],
|
||||
current: null,
|
||||
query: {
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
projectName: '',
|
||||
organizationName: '',
|
||||
contractCategory: '',
|
||||
signType: '',
|
||||
effectiveType: '',
|
||||
contractStage: '',
|
||||
approvalStatus: '',
|
||||
},
|
||||
page: { current: 1, size: 10, total: 0 },
|
||||
},
|
||||
generateRows: [],
|
||||
generateSelection: [],
|
||||
generatePage: { current: 1, size: 10, total: 0 },
|
||||
@@ -805,6 +1045,30 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
generateContractName() {
|
||||
const contract = this.contractOptions.find(
|
||||
item => String(item.id) === String(this.generateQuery.contractId)
|
||||
);
|
||||
return contract?.contractName || '';
|
||||
},
|
||||
generateContractCategory() {
|
||||
return this.settlementType === 'payable' ? '承运商合同' : '客户合同';
|
||||
},
|
||||
contractCategoryName(value) {
|
||||
return (
|
||||
this.contractCategoryOptions.find(item => String(item.value) === String(value))?.label ||
|
||||
this.formatCell(value)
|
||||
);
|
||||
},
|
||||
signTypeName(value) {
|
||||
return (
|
||||
this.signTypeOptions.find(item => String(item.value) === String(value))?.label ||
|
||||
this.formatCell(value)
|
||||
);
|
||||
},
|
||||
displayValue(value) {
|
||||
return this.formatCell(value);
|
||||
},
|
||||
settlementTypeLabel() {
|
||||
if (this.settlementType === 'receivable') return '应收';
|
||||
if (this.settlementType === 'payable') return '应付';
|
||||
@@ -830,14 +1094,31 @@ export default {
|
||||
column => this.settlementType !== 'receivable' || column.prop !== 'preSettlementNo'
|
||||
);
|
||||
const totalIndex = columns.findIndex(column => column.prop === 'totalAmountText');
|
||||
const dynamicColumns = this.tableFeeItemNames.map((name, index) => ({
|
||||
label: name,
|
||||
prop: `tableFeeItem${index}`,
|
||||
feeItemName: name,
|
||||
dynamic: true,
|
||||
minWidth: 130,
|
||||
align: 'right',
|
||||
}));
|
||||
const dynamicColumns = this.isPayable
|
||||
? [
|
||||
{
|
||||
label: '运输费',
|
||||
prop: 'tableFreightAmount',
|
||||
feeSummaryType: 'freight',
|
||||
minWidth: 130,
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
label: '其他费用',
|
||||
prop: 'tableOtherFeeAmount',
|
||||
feeSummaryType: 'other',
|
||||
minWidth: 130,
|
||||
align: 'right',
|
||||
},
|
||||
]
|
||||
: this.tableFeeItemNames.map((name, index) => ({
|
||||
label: name,
|
||||
prop: `tableFeeItem${index}`,
|
||||
feeItemName: name,
|
||||
dynamic: true,
|
||||
minWidth: 130,
|
||||
align: 'right',
|
||||
}));
|
||||
if (totalIndex < 0) return [...columns, ...dynamicColumns];
|
||||
columns.splice(totalIndex, 0, ...dynamicColumns);
|
||||
return columns;
|
||||
@@ -846,12 +1127,14 @@ export default {
|
||||
return [...generatePreviewColumns, ...this.dynamicFeeColumns, ...feeDetailTailColumns];
|
||||
},
|
||||
adjustFeeColumns() {
|
||||
return [
|
||||
...feeDetailBaseColumns,
|
||||
...this.adjustDynamicFeeColumns,
|
||||
...feeDetailTailColumns,
|
||||
{ label: '变更原因', prop: 'changeReason', minWidth: 220 },
|
||||
];
|
||||
const tailColumns = feeDetailTailColumns.filter(column => column.prop !== 'remark');
|
||||
const afterAmountIndex = tailColumns.findIndex(column => column.prop === 'afterAmountText');
|
||||
tailColumns.splice(afterAmountIndex + 1, 0, {
|
||||
label: '调整原因',
|
||||
prop: 'changeReason',
|
||||
minWidth: 220,
|
||||
});
|
||||
return [...feeDetailBaseColumns, ...this.adjustDynamicFeeColumns, ...tailColumns];
|
||||
},
|
||||
transportCargoTypeOptions() {
|
||||
return this.cargoTypeOptions.filter(item => item.children?.length);
|
||||
@@ -1114,6 +1397,12 @@ export default {
|
||||
formatColumnValue(row, column) {
|
||||
if (column.prop === 'transportType') return this.transportTypeLabel(row[column.prop]);
|
||||
if (column.prop === 'transportQuantity') return this.fixedTwoDecimals(row[column.prop]);
|
||||
if (column.feeSummaryType) {
|
||||
return this.money(
|
||||
this.summarizeTableFee(row, column.feeSummaryType),
|
||||
row.currency || 'RMB'
|
||||
);
|
||||
}
|
||||
if (column.dynamic) {
|
||||
return this.money(
|
||||
this.normalizeFeeItems(row.feeItems)[column.feeItemName],
|
||||
@@ -1137,25 +1426,80 @@ export default {
|
||||
const res = await api.getList(this.page.current, this.page.size, params);
|
||||
const data = this.unwrapPage(res);
|
||||
this.rows = (data.records || []).map(this.decorateRow);
|
||||
this.tableFeeItemNames = this.collectFeeItemNames(this.rows);
|
||||
this.tableFeeItemNames = this.isPayable ? [] : this.collectFeeItemNames(this.rows);
|
||||
this.page.total = data.total || 0;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async loadContracts() {
|
||||
const contractCategory = this.settlementType === 'payable' ? '承运商合同' : '客户合同';
|
||||
this.contractLoading = true;
|
||||
openGenerateContractDialog() {
|
||||
this.generateContractDialog.visible = true;
|
||||
this.generateContractDialog.expanded = false;
|
||||
this.generateContractDialog.current = null;
|
||||
this.generateContractDialog.page.current = 1;
|
||||
this.loadGenerateContracts();
|
||||
},
|
||||
async loadGenerateContracts() {
|
||||
this.generateContractDialog.loading = true;
|
||||
try {
|
||||
const res = await getContractList(1, 999, {
|
||||
contractCategory,
|
||||
});
|
||||
const res = await getContractList(
|
||||
this.generateContractDialog.page.current,
|
||||
this.generateContractDialog.page.size,
|
||||
{
|
||||
...this.generateContractDialog.query,
|
||||
contractCategory: this.generateContractCategory,
|
||||
approvalStatuses: 'approved,change_approved',
|
||||
}
|
||||
);
|
||||
const data = this.unwrapPage(res);
|
||||
this.contractOptions = data.records || [];
|
||||
this.generateContractDialog.rows = data.records || [];
|
||||
this.generateContractDialog.page.total = Number(data.total || 0);
|
||||
} finally {
|
||||
this.contractLoading = false;
|
||||
this.generateContractDialog.loading = false;
|
||||
}
|
||||
},
|
||||
searchGenerateContracts() {
|
||||
this.generateContractDialog.page.current = 1;
|
||||
this.loadGenerateContracts();
|
||||
},
|
||||
resetGenerateContractQuery() {
|
||||
this.generateContractDialog.query = {
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
projectName: '',
|
||||
organizationName: '',
|
||||
contractCategory: '',
|
||||
signType: '',
|
||||
effectiveType: '',
|
||||
contractStage: '',
|
||||
approvalStatus: '',
|
||||
};
|
||||
this.searchGenerateContracts();
|
||||
},
|
||||
handleGenerateContractSizeChange() {
|
||||
this.generateContractDialog.page.current = 1;
|
||||
this.loadGenerateContracts();
|
||||
},
|
||||
selectGenerateContract(row) {
|
||||
if (!row) {
|
||||
this.$message.warning('请选择合同');
|
||||
return;
|
||||
}
|
||||
const contract = {
|
||||
...row,
|
||||
deptId: row.deptId || row.organizationId,
|
||||
deptName: row.deptName || row.organizationName,
|
||||
partyA: row.partyA || row.payerName,
|
||||
partyB: row.partyB || row.payeeName,
|
||||
};
|
||||
const index = this.contractOptions.findIndex(item => String(item.id) === String(contract.id));
|
||||
if (index >= 0) this.contractOptions.splice(index, 1, contract);
|
||||
else this.contractOptions.push(contract);
|
||||
this.generateQuery.contractId = contract.id;
|
||||
this.handleGenerateContractChange(contract.id);
|
||||
this.generateContractDialog.visible = false;
|
||||
this.generateContractDialog.current = null;
|
||||
},
|
||||
handleSearch() {
|
||||
this.page.current = 1;
|
||||
this.loadTable();
|
||||
@@ -1177,6 +1521,7 @@ export default {
|
||||
closeDetailPanel() {
|
||||
this.detailDialog.visible = false;
|
||||
this.detailDialog.row = null;
|
||||
this.changeRecordsDialog.visible = false;
|
||||
},
|
||||
closeAdjustPanel() {
|
||||
this.clearAdjustCalculations();
|
||||
@@ -1525,11 +1870,31 @@ export default {
|
||||
}
|
||||
},
|
||||
handleDetailTabChange(name) {
|
||||
if (name === 'change') this.loadChangeRecords();
|
||||
if (name === 'change') this.loadLatestChangeRecord();
|
||||
},
|
||||
async loadLatestChangeRecord() {
|
||||
if (!this.detailDialog.row) return;
|
||||
this.latestChangeLoading = true;
|
||||
this.latestChangeRows = [];
|
||||
try {
|
||||
const res = await api.getChangeRecords(1, 1, {
|
||||
detailId: this.detailDialog.row.id,
|
||||
});
|
||||
const data = this.unwrapPage(res);
|
||||
this.latestChangeRows = (data.records || []).slice(0, 1);
|
||||
} finally {
|
||||
this.latestChangeLoading = false;
|
||||
}
|
||||
},
|
||||
openChangeRecordsDialog() {
|
||||
if (!this.detailDialog.row) return;
|
||||
this.changeRecordsDialog.visible = true;
|
||||
this.changePage.current = 1;
|
||||
this.loadChangeRecords();
|
||||
},
|
||||
async loadChangeRecords() {
|
||||
if (!this.detailDialog.row) return;
|
||||
this.changeDialog.loading = true;
|
||||
this.changeRecordsDialog.loading = true;
|
||||
try {
|
||||
const res = await api.getChangeRecords(this.changePage.current, this.changePage.size, {
|
||||
detailId: this.detailDialog.row.id,
|
||||
@@ -1538,7 +1903,7 @@ export default {
|
||||
this.changeRows = data.records || [];
|
||||
this.changePage.total = data.total || 0;
|
||||
} finally {
|
||||
this.changeDialog.loading = false;
|
||||
this.changeRecordsDialog.loading = false;
|
||||
}
|
||||
},
|
||||
handleChangeSizeChange() {
|
||||
@@ -1792,11 +2157,26 @@ export default {
|
||||
this.generateDialog.visible = true;
|
||||
this.generateQuery = {};
|
||||
this.contractOptions = [];
|
||||
this.generateContractDialog.query = {
|
||||
contractNo: '',
|
||||
contractName: '',
|
||||
projectName: '',
|
||||
organizationName: '',
|
||||
contractCategory: '',
|
||||
signType: '',
|
||||
effectiveType: '',
|
||||
contractStage: '',
|
||||
approvalStatus: '',
|
||||
};
|
||||
this.generateContractDialog.visible = false;
|
||||
this.generateContractDialog.expanded = false;
|
||||
this.generateContractDialog.rows = [];
|
||||
this.generateContractDialog.current = null;
|
||||
this.generateContractDialog.page = { current: 1, size: 10, total: 0 };
|
||||
this.billingPlanOptions = [];
|
||||
this.generateRows = [];
|
||||
this.generateSelection = [];
|
||||
this.generatePage = { current: 1, size: 10, total: 0 };
|
||||
this.loadContracts();
|
||||
},
|
||||
handleGenerateContractChange(contractId) {
|
||||
const options = this.syncBillingPlanOptions(contractId);
|
||||
@@ -1911,6 +2291,7 @@ export default {
|
||||
row.vehicleNumber ||
|
||||
sourceWaybill?.vehicleNo ||
|
||||
'',
|
||||
transportQuantityText: row.transportQuantityText ?? row.transportQuantity ?? '',
|
||||
...dynamic,
|
||||
};
|
||||
});
|
||||
@@ -2032,6 +2413,16 @@ export default {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
summarizeTableFee(row, summaryType) {
|
||||
const feeItemEntries = Object.entries(this.normalizeFeeItems(row.feeItems));
|
||||
const matchedEntries = feeItemEntries.filter(([name]) =>
|
||||
summaryType === 'freight' ? this.isFreightFeeItem(name) : !this.isFreightFeeItem(name)
|
||||
);
|
||||
if (matchedEntries.length) {
|
||||
return matchedEntries.reduce((total, [, amount]) => total + Number(amount || 0), 0);
|
||||
}
|
||||
return summaryType === 'freight' ? row.freightAmount : row.otherFeeAmount;
|
||||
},
|
||||
money(value, currency) {
|
||||
if (value === null || value === undefined || value === '') return '-';
|
||||
return `${Number(value).toFixed(2)} ${currency}`;
|
||||
@@ -2160,6 +2551,12 @@ export default {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.settlement-detail-page__empty {
|
||||
padding: 24px 0;
|
||||
color: #909399;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.settlement-detail-page__dialog-form {
|
||||
padding: 16px 20px;
|
||||
background: #fff;
|
||||
@@ -2212,6 +2609,39 @@ export default {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.settlement-detail-page__contract-filter {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 8px 24px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
:deep(.el-form-item) {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:deep(.el-input),
|
||||
:deep(.el-select) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.settlement-detail-page__contract-filter-actions {
|
||||
grid-column: 1 / -1;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.settlement-detail-page__transfer-form {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 12px 4px;
|
||||
|
||||
Reference in New Issue
Block a user