|
|
|
|
@ -10,6 +10,22 @@
|
|
|
|
|
>
|
|
|
|
|
本合同由合同内容变更生成,激活后将继承原合同关联项目并作废原合同;下方关联项目已预填原合同项目。
|
|
|
|
|
</el-alert>
|
|
|
|
|
<el-alert
|
|
|
|
|
v-if="partyACustomerValidate && !partyACustomerValidate.valid"
|
|
|
|
|
type="warning"
|
|
|
|
|
:closable="false"
|
|
|
|
|
show-icon
|
|
|
|
|
style="margin-bottom: 12px"
|
|
|
|
|
>
|
|
|
|
|
<template #default>
|
|
|
|
|
<span>
|
|
|
|
|
合同甲方客户【{{ partyACustomerValidate.customerName || '—' }}】信息不完整,缺少:{{ partyACustomerMissingText }}。订单激活前请先完善客户信息。
|
|
|
|
|
</span>
|
|
|
|
|
<el-button v-if="!isFormDisabled" type="primary" link style="margin-left: 8px" @click="openPartyACustomerDialog">
|
|
|
|
|
维护客户信息
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-alert>
|
|
|
|
|
<el-card shadow="never" style="margin-top: 0">
|
|
|
|
|
<approvalButton
|
|
|
|
|
@submitForm="submitForm"
|
|
|
|
|
@ -438,6 +454,41 @@
|
|
|
|
|
@confirm-call-back="projectSelectCallback"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<!-- 维护甲方客户信息 -->
|
|
|
|
|
<el-dialog
|
|
|
|
|
v-model="partyACustomerDialog.visible"
|
|
|
|
|
title="维护甲方客户信息"
|
|
|
|
|
width="640px"
|
|
|
|
|
append-to-body
|
|
|
|
|
destroy-on-close
|
|
|
|
|
>
|
|
|
|
|
<el-form ref="partyACustomerFormRef" :model="partyACustomerForm" :rules="partyACustomerRules" label-width="100px">
|
|
|
|
|
<el-form-item label="客户名称">
|
|
|
|
|
<el-input v-model="partyACustomerForm.customerName" disabled />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="税号" prop="taxNumber">
|
|
|
|
|
<el-input v-model="partyACustomerForm.taxNumber" placeholder="请输入税号" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="开户银行" prop="bankAccountOpening">
|
|
|
|
|
<el-input v-model="partyACustomerForm.bankAccountOpening" placeholder="请输入开户银行" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="银行账号" prop="bankNumber">
|
|
|
|
|
<el-input v-model="partyACustomerForm.bankNumber" placeholder="请输入银行账号" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="开票附件" prop="ossId">
|
|
|
|
|
<FileUpload
|
|
|
|
|
v-model="partyACustomerOssIdString"
|
|
|
|
|
:limit="5"
|
|
|
|
|
:fileType="['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'pdf', 'zip', 'rar', 'jpg', 'jpeg', 'png']"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form>
|
|
|
|
|
<template #footer>
|
|
|
|
|
<el-button type="primary" :loading="partyACustomerDialog.loading" @click="submitPartyACustomerForm">保 存</el-button>
|
|
|
|
|
<el-button @click="partyACustomerDialog.visible = false">取 消</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
<!-- 提交审批组件 -->
|
|
|
|
|
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
|
|
|
|
<!-- 审批记录 -->
|
|
|
|
|
@ -450,7 +501,8 @@ import { ref, reactive, computed, toRefs, getCurrentInstance, onMounted, nextTic
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
|
|
import type { ComponentInternalInstance } from 'vue';
|
|
|
|
|
import { getErpProjectInfoList, getProjectInfo } from '@/api/oa/erp/projectInfo';
|
|
|
|
|
import { saveContractOrder, updateContractOrder, submitContractOrderAndFlowStart } from '@/api/oa/erp/contractOrder';
|
|
|
|
|
import { saveContractOrder, updateContractOrder, submitContractOrderAndFlowStart, validPartyACustomerForOrderActivate } from '@/api/oa/erp/contractOrder';
|
|
|
|
|
import type { PartyACustomerValidateVO } from '@/api/oa/erp/contractOrder/types';
|
|
|
|
|
import { ProjectInfoForm, ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
|
|
|
|
|
import { getErpProjectContractsList } from '@/api/oa/erp/projectContracts';
|
|
|
|
|
import { ProjectContractsVO } from '@/api/oa/erp/projectContracts/types';
|
|
|
|
|
@ -470,7 +522,8 @@ import type { FormInstance } from 'element-plus';
|
|
|
|
|
import { getErpProjectPlanStageList, listErpProjectPlanStage } from '@/api/oa/erp/erpProjectPlanStage';
|
|
|
|
|
import { ErpProjectPlanStageForm, ErpProjectPlanStageQuery } from '@/api/oa/erp/erpProjectPlanStage/types';
|
|
|
|
|
import { listContractInfo, getContractInfo } from '@/api/oa/erp/contractInfo';
|
|
|
|
|
import { getCrmCustomerInfoList } from '@/api/oa/crm/customerInfo';
|
|
|
|
|
import { getCrmCustomerInfoList, getCustomerInfo, updateCustomerInfo } from '@/api/oa/crm/customerInfo';
|
|
|
|
|
import type { CustomerInfoForm } from '@/api/oa/crm/customerInfo/types';
|
|
|
|
|
import { getBasePaymentStageList } from '@/api/oa/base/paymentStage';
|
|
|
|
|
import { PaymentStageVO } from '@/api/oa/base/paymentStage/types';
|
|
|
|
|
import { getInfo } from '@/api/login';
|
|
|
|
|
@ -953,6 +1006,110 @@ const REPAYMENT_RATE_EPSILON = 0.01;
|
|
|
|
|
/** 是否禁用表单(查看/审批模式) */
|
|
|
|
|
const isFormDisabled = computed(() => routeParams.value.type === 'view' || routeParams.value.type === 'approval');
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// 甲方客户信息校验与维护
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
const partyACustomerValidate = ref<PartyACustomerValidateVO | null>(null);
|
|
|
|
|
const partyACustomerFormRef = ref<FormInstance>();
|
|
|
|
|
const partyACustomerFullData = ref<CustomerInfoForm | null>(null);
|
|
|
|
|
const partyACustomerDialog = reactive({
|
|
|
|
|
visible: false,
|
|
|
|
|
loading: false
|
|
|
|
|
});
|
|
|
|
|
const partyACustomerForm = reactive({
|
|
|
|
|
customerName: '',
|
|
|
|
|
taxNumber: '',
|
|
|
|
|
bankAccountOpening: '',
|
|
|
|
|
bankNumber: '',
|
|
|
|
|
ossId: undefined as string | number | undefined
|
|
|
|
|
});
|
|
|
|
|
const partyACustomerRules = {
|
|
|
|
|
taxNumber: [{ required: true, message: '税号不能为空', trigger: 'blur' }],
|
|
|
|
|
bankAccountOpening: [{ required: true, message: '开户银行不能为空', trigger: 'blur' }],
|
|
|
|
|
bankNumber: [{ required: true, message: '银行账号不能为空', trigger: 'blur' }],
|
|
|
|
|
ossId: [{ required: true, message: '请上传开票附件', trigger: 'change' }]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const partyACustomerOssIdString = computed({
|
|
|
|
|
get() {
|
|
|
|
|
const v = partyACustomerForm.ossId;
|
|
|
|
|
return v === undefined || v === null ? '' : String(v);
|
|
|
|
|
},
|
|
|
|
|
set(val: string) {
|
|
|
|
|
partyACustomerForm.ossId = val || undefined;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const partyACustomerMissingText = computed(() => {
|
|
|
|
|
const result = partyACustomerValidate.value;
|
|
|
|
|
if (!result) return '';
|
|
|
|
|
const labels: string[] = [];
|
|
|
|
|
if (result.ossIdMissing) labels.push('附件');
|
|
|
|
|
if (result.taxNumberMissing) labels.push('税号');
|
|
|
|
|
if (result.bankAccountOpeningMissing) labels.push('开户银行');
|
|
|
|
|
if (result.bankNumberMissing) labels.push('银行账号');
|
|
|
|
|
return labels.join('、') || '—';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const checkPartyACustomerForOrderActivate = async () => {
|
|
|
|
|
const contractId = form.value.contractId || routeParams.value.contractId;
|
|
|
|
|
if (!contractId) {
|
|
|
|
|
partyACustomerValidate.value = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
const res = await validPartyACustomerForOrderActivate(contractId);
|
|
|
|
|
partyACustomerValidate.value = res.data;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('校验甲方客户信息失败:', error);
|
|
|
|
|
partyACustomerValidate.value = null;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openPartyACustomerDialog = async () => {
|
|
|
|
|
const customerId = partyACustomerValidate.value?.oneCustomerId;
|
|
|
|
|
if (!customerId) {
|
|
|
|
|
proxy?.$modal.msgWarning('未获取到甲方客户信息');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
const res = await getCustomerInfo(customerId);
|
|
|
|
|
partyACustomerFullData.value = { ...(res.data || {}) };
|
|
|
|
|
partyACustomerForm.customerName = res.data?.customerName || '';
|
|
|
|
|
partyACustomerForm.taxNumber = res.data?.taxNumber || '';
|
|
|
|
|
partyACustomerForm.bankAccountOpening = res.data?.bankAccountOpening || '';
|
|
|
|
|
partyACustomerForm.bankNumber = res.data?.bankNumber || '';
|
|
|
|
|
partyACustomerForm.ossId = res.data?.ossId;
|
|
|
|
|
partyACustomerDialog.visible = true;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('加载客户信息失败:', error);
|
|
|
|
|
proxy?.$modal.msgError('加载客户信息失败');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const submitPartyACustomerForm = () => {
|
|
|
|
|
partyACustomerFormRef.value?.validate(async (valid: boolean) => {
|
|
|
|
|
if (!valid || !partyACustomerFullData.value?.customerId) return;
|
|
|
|
|
partyACustomerDialog.loading = true;
|
|
|
|
|
try {
|
|
|
|
|
await updateCustomerInfo({
|
|
|
|
|
...partyACustomerFullData.value,
|
|
|
|
|
taxNumber: partyACustomerForm.taxNumber,
|
|
|
|
|
bankAccountOpening: partyACustomerForm.bankAccountOpening,
|
|
|
|
|
bankNumber: partyACustomerForm.bankNumber,
|
|
|
|
|
ossId: partyACustomerForm.ossId
|
|
|
|
|
});
|
|
|
|
|
proxy?.$modal.msgSuccess('客户信息保存成功');
|
|
|
|
|
partyACustomerDialog.visible = false;
|
|
|
|
|
await checkPartyACustomerForOrderActivate();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('保存客户信息失败:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
partyACustomerDialog.loading = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 附件 ID 与字符串双向转换(供 FileUpload 使用) */
|
|
|
|
|
const ossIdString = computed({
|
|
|
|
|
get() {
|
|
|
|
|
@ -1022,6 +1179,10 @@ function isRepaymentRateTotalValid(): boolean {
|
|
|
|
|
const submitForm = (status: string, mode: boolean) => {
|
|
|
|
|
projectInfoFormRef.value?.validate(async (valid: boolean) => {
|
|
|
|
|
if (!valid) return;
|
|
|
|
|
if (!isFormDisabled.value && partyACustomerValidate.value && !partyACustomerValidate.value.valid) {
|
|
|
|
|
proxy?.$modal.msgWarning('请先完善合同甲方客户信息(附件、税号、开户银行、银行账号)');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!isRepaymentRateTotalValid()) {
|
|
|
|
|
proxy?.$modal.msgWarning('回款信息预计回款比例之和必须为100%');
|
|
|
|
|
return;
|
|
|
|
|
@ -1254,6 +1415,7 @@ onMounted(async () => {
|
|
|
|
|
console.error('获取合同信息失败:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
await checkPartyACustomerForOrderActivate();
|
|
|
|
|
proxy?.$modal.closeLoading();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|