feat(crm):调整项目计划编辑页字段与逻辑,优化报价单编辑页布局与功能

- 移除关联合同选择字段,替换为项目编号自动显示
- 删除回款比例自动计算回款金额功能
- 移除合同列表相关 API 调用与数据处理逻辑
- 更新项目选择变更处理逻辑,同步展示项目编号- 清理无用的合同总价相关变量与监听逻辑
- 简化表单重置逻辑,移除合同相关状态清除

- 调整基本信息区域结构,使用 el-divider 分区替代卡片标题
- 合并客户方与供货方信息在同一卡片内展示,提升页面紧凑性
- 附件与备注区域合并为一个分区展示
- 报价明细表格区域结构调整,新增物料按钮位置优化- 含税总价展示样式增强,增加颜色标识与边框分隔- 移除冗余的卡片包裹结构,统一表单验证逻辑
- 优化页面整体视觉层次与信息密度
dev
zangch@mesnac.com 1 month ago
parent 6100cfca42
commit ba5b5e3478

@ -1,10 +1,9 @@
<template>
<div class="p-2">
<!-- 统一表单包裹所有分区便于整体验证 -->
<el-form ref="quoteFormRef" :model="form" :rules="rules" label-width="120px" :disabled="isView">
<el-card shadow="never">
<div style="margin-bottom: 12px; text-align: center; font-weight: bold; font-size: 18px">添加报价单基本信息</div>
<div class="basic-center">
<!-- 统一表单包裹所有分区便于整体验证 -->
<el-form ref="quoteFormRef" :model="form" :rules="rules" label-width="120px" :disabled="isView">
<el-divider content-position="left">基本信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报价单编号" prop="quoteCode">
@ -140,8 +139,6 @@
</el-form-item>
</el-col>
</el-row>
</div>
</el-card>
<!-- 报价物料编辑对话框 -->
<el-dialog :title="materialDialog.title" v-model="materialDialog.visible" width="800px" append-to-body>
<el-form ref="materialFormRef" :model="materialForm" :rules="materialRules" label-width="120px">
@ -218,115 +215,86 @@
<!-- 销售物料选择 -->
<SaleMaterialSelect ref="saleMaterialSelectRef" :multiple="false" @confirm-call-back="saleMaterialSelectCallBack" />
<!-- 客户方/供货方信息左右并列对称布局 -->
<el-row :gutter="20" style="margin-top: 20px">
<!-- 对齐合同编辑页单卡片内分区展示 -->
<el-divider content-position="left">客户方信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-card shadow="never">
<template #header>
<div style="text-align: left; font-weight: bold; font-size: 18px">客户方信息</div>
</template>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="客户联系人" prop="customerContactId">
<el-select v-model="form.customerContactId" filterable placeholder="请选择客户联系人" @change="onCustomerContactChanged">
<el-option v-for="c in customerContactList" :key="c.contactId" :label="c.contactName + ' - ' + (c.phoneNumber||'')" :value="c.contactId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="客户联系电话" prop="customerContactPhone">
<el-input v-model="form.customerContactPhone" placeholder="客户联系电话" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="客户邮箱" prop="customerContactEmail">
<el-input v-model="form.customerContactEmail" placeholder="客户邮箱" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<el-form-item label="客户联系人" prop="customerContactId">
<el-select v-model="form.customerContactId" filterable placeholder="请选择客户联系人" @change="onCustomerContactChanged">
<el-option v-for="c in customerContactList" :key="c.contactId" :label="c.contactName + ' - ' + (c.phoneNumber||'')" :value="c.contactId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-card shadow="never">
<template #header>
<div style="text-align: left; font-weight: bold; font-size: 18px">供货方信息</div>
</template>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="计划标识" prop="supplierPlanFlag">
<el-radio-group v-model="supplierPlanFlag" @change="onSupplierPlanFlagChanged">
<el-radio value="1">计划内</el-radio>
<el-radio value="2">计划外</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24" v-if="supplierPlanFlag === '1'">
<el-form-item label="供应商" prop="supplierContactId">
<el-select v-model="form.supplierContactId" filterable placeholder="请选择供应商" @change="onSupplierChanged">
<el-option v-for="s in supplierList" :key="s.supplierId" :label="s.supplierName" :value="s.supplierId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="供货方联系人" prop="supplierContactName">
<el-input v-model="form.supplierContactName" placeholder="供货方联系人" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="供货方联系电话" prop="supplierContactPhone">
<el-input v-model="form.supplierContactPhone" placeholder="供货方联系电话" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="供货方邮箱" prop="supplierContactEmail">
<el-input v-model="form.supplierContactEmail" placeholder="供货方邮箱" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<el-form-item label="客户联系电话" prop="customerContactPhone">
<el-input v-model="form.customerContactPhone" placeholder="客户联系电话" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户邮箱" prop="customerContactEmail">
<el-input v-model="form.customerContactEmail" placeholder="客户邮箱" />
</el-form-item>
</el-col>
</el-row>
<!-- 附件独立分区样式参考合同编辑页 -->
<el-card shadow="never" style="margin-top: 20px">
<template #header>
<div style="text-align: left; font-weight: bold; font-size: 18px">附件</div>
</template>
<el-row :gutter="20">
<el-col :span="24">
<!-- 与合同页对齐采用附件表单项与上传按钮 -->
<el-form-item label="附件">
<el-button type="primary" plain icon="Upload" @click="handleFile" :disabled="isView">上传附件</el-button>
</el-form-item>
<el-divider content-position="left">供货方信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="计划标识" prop="supplierPlanFlag">
<el-radio-group v-model="supplierPlanFlag" @change="onSupplierPlanFlagChanged">
<el-radio value="1">计划内</el-radio>
<el-radio value="2">计划外</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="supplierPlanFlag === '1'">
<el-form-item label="供应商" prop="supplierContactId">
<el-select v-model="form.supplierContactId" filterable placeholder="请选择供应商" @change="onSupplierChanged">
<el-option v-for="s in supplierList" :key="s.supplierId" :label="s.supplierName" :value="s.supplierId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供货方联系人" prop="supplierContactName">
<el-input v-model="form.supplierContactName" placeholder="供货方联系人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供货方联系电话" prop="supplierContactPhone">
<el-input v-model="form.supplierContactPhone" placeholder="供货方联系电话" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供货方邮箱" prop="supplierContactEmail">
<el-input v-model="form.supplierContactEmail" placeholder="供货方邮箱" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">附件与备注</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="附件">
<el-button type="primary" plain icon="Upload" @click="handleFile" :disabled="isView">上传附件</el-button>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 报价物料管理 -->
<el-divider content-position="left">报价明细</el-divider>
<el-row :gutter="10" class="mb-3" v-if="!isView">
<el-col :span="1.5">
<el-button type="primary" icon="Plus" @click="handleAddMaterial"></el-button>
</el-col>
</el-row>
</el-card>
<!-- 备注独立分区 -->
<el-card shadow="never" style="margin-top: 20px">
<template #header>
<div style="text-align: left; font-weight: bold; font-size: 18px">备注</div>
</template>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<!-- 统一表单结束 -->
</el-form>
<!-- 报价物料管理 -->
<el-card shadow="never" style="margin-top: 20px">
<template #header>
<div style="text-align: left; font-weight: bold; font-size: 18px">报价明细表格</div>
</template>
<div style="margin-bottom: 12px">
<el-button type="primary" icon="Plus" @click="handleAddMaterial" :disabled="isView">新增物料</el-button>
</div>
<el-table :data="materialRows" border show-summary :summary-method="getSummary">
<el-table-column label="产品名称" align="center" prop="productName" min-width="160" />
<el-table-column label="规格描述" align="center" prop="specificationDescription" min-width="160" />
@ -367,8 +335,8 @@
</el-table-column>
</el-table>
<div style="margin-top: 12px; text-align: right">
<span style="margin-right: 16px">含税总价{{ totalIncludingTax.toFixed(2) }}</span>
<div style="margin-top: 16px; padding-top: 12px; border-top: 1px solid #ebeef5; text-align: right">
<span style="margin-right: 20px; font-weight: bold; font-size: 14px">含税总价<span style="color: #f56c6c">{{ totalIncludingTax.toFixed(2) }}</span></span>
<el-button v-if="!isView" type="primary" :loading="buttonLoading" @click="submitForm"> </el-button>
<el-button @click="goBack"> </el-button>
</div>

@ -63,10 +63,8 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="关联合同" prop="contractId">
<el-select v-model="form.contractId" placeholder="请选择合同" filterable clearable :disabled="!isBasicEditable">
<el-option v-for="item in contractInfoList" :key="item.contractId" :label="item.contractName" :value="item.contractId"/>
</el-select>
<el-form-item label="项目编号">
<el-input v-model="selectedProjectCode" placeholder="选择项目后自动显示" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
@ -124,7 +122,7 @@
</el-table-column>
<el-table-column label="回款比例(%)" width="120" align="center">
<template #default="scope">
<el-input-number v-model="scope.row.repaymentRate" :min="0" :max="100" :precision="2" controls-position="right" style="width: 100%" :disabled="!isBasicEditable" @change="calculateRepaymentAmount(scope.row)"/>
<el-input-number v-model="scope.row.repaymentRate" :min="0" :max="100" :precision="2" controls-position="right" style="width: 100%" :disabled="!isBasicEditable"/>
</template>
</el-table-column>
<el-table-column label="预计回款金额" width="140" align="center">
@ -176,7 +174,6 @@ import { getErpProjectPlan, addErpProjectPlan, updateErpProjectPlan, projectPlan
import { ErpProjectPlanForm } from '@/api/oa/erp/erpProjectPlan/types';
import { listUser } from '@/api/system/user';
import { getErpProjectInfoList } from '@/api/oa/erp/projectInfo';
import { getErpContractInfoList } from '@/api/oa/erp/contractInfo';
import SubmitVerify from '@/components/Process/submitVerify.vue';
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
import { useUserStore } from '@/store/modules/user';
@ -289,8 +286,7 @@ const submitLoading = ref(false);
const currentAction = ref<'draft' | 'submit' | null>(null);
const projectInfoList = ref<any[]>([]);
const userList = ref<any[]>([]);
const contractInfoList = ref<any[]>([]);
const contractTotalPrice = ref<number>(0);
const selectedProjectCode = ref<string>(''); //
const baseDataLoaded = ref(false);
const createEmptyForm = (): ErpProjectPlanForm => ({
@ -319,7 +315,7 @@ const notifyListRefresh = () => {
const resetForm = () => {
form.value = createEmptyForm();
contractTotalPrice.value = 0;
selectedProjectCode.value = '';
};
/** 获取项目列表 */
@ -334,17 +330,11 @@ const getUserList = async () => {
userList.value = res.rows;
};
/** 获取合同列表 */
const getContractInfoList = async () => {
const res = await getErpContractInfoList({});
contractInfoList.value = res.data;
};
const initBaseData = async () => {
if (baseDataLoaded.value) {
return;
}
await Promise.all([getProjectInfoList(), getUserList(), getContractInfoList()]);
await Promise.all([getProjectInfoList(), getUserList()]);
baseDataLoaded.value = true;
};
@ -380,26 +370,22 @@ const handleDeleteStage = (index: number) => {
form.value.planStageList?.splice(index, 1);
};
/** 处理项目选择变化,自动填充项目经理和部门负责人 */
/** 处理项目选择变化,自动填充项目经理、部门负责人和项目编号 */
const handleProjectChange = (projectId: number) => {
if (!projectId) {
form.value.managerId = undefined;
form.value.chargeId = undefined;
selectedProjectCode.value = '';
return;
}
const project = projectInfoList.value.find(p => p.projectId === projectId);
if (project) {
form.value.managerId = project.managerId;
form.value.chargeId = project.chargeId;
selectedProjectCode.value = project.projectCode || '';
}
};
/** 根据回款比例计算回款金额 */
const calculateRepaymentAmount = (row: any) => {
if (row.repaymentRate && contractTotalPrice.value > 0) {
row.repaymentAmount = parseFloat((contractTotalPrice.value * row.repaymentRate / 100).toFixed(2));
}
};
/** 根据回款时间与延期天数生成应收款日期 */
const recalcReceivableDate = (row: any) => {
@ -421,17 +407,6 @@ const recalcReceivableDate = (row: any) => {
row.receivableDate = proxy?.parseTime ? proxy.parseTime(target, '{y}-{m}-{d}') : target.toISOString().slice(0, 10);
};
/** 监听合同变化,更新合同总价 */
watch(() => form.value.contractId, (newContractId) => {
if (newContractId) {
const contract = contractInfoList.value.find(c => c.contractId === newContractId);
if (contract) {
contractTotalPrice.value = contract.totalPrice || 0;
}
} else {
contractTotalPrice.value = 0;
}
});
/** 提交表单 */
const submitForm = async (status = 'draft') => {
@ -587,16 +562,6 @@ const loadFormData = async () => {
if (!form.value.planStageList) {
form.value.planStageList = [];
}
if (form.value.contractId) {
const contract = contractInfoList.value.find(c => c.contractId === form.value.contractId);
if (contract) {
contractTotalPrice.value = contract.totalPrice || 0;
} else {
contractTotalPrice.value = 0;
}
} else {
contractTotalPrice.value = 0;
}
} else {
resetForm();
form.value.flowStatus = 'draft';

Loading…
Cancel
Save