diff --git a/src/api/oa/crm/crmQuoteInfo/types.ts b/src/api/oa/crm/crmQuoteInfo/types.ts index b85bf92..5f1bcb6 100644 --- a/src/api/oa/crm/crmQuoteInfo/types.ts +++ b/src/api/oa/crm/crmQuoteInfo/types.ts @@ -130,7 +130,7 @@ export interface CrmQuoteInfoVO { customerContactEmail: string; /** - * 供货方联系人ID + * 供货方ID */ supplierContactId: string | number; @@ -174,6 +174,11 @@ export interface CrmQuoteInfoVO { */ flowStatus: string; + /** + * 供应商名称 + */ + supplierName: string; + /** * 备注 */ @@ -318,7 +323,7 @@ export interface CrmQuoteInfoForm extends BaseEntity { customerContactEmail?: string; /** - * 供货方联系人ID + * 供货方ID */ supplierContactId?: string | number; @@ -372,6 +377,11 @@ export interface CrmQuoteInfoForm extends BaseEntity { */ itemsBo?: CrmQuoteMaterialForm[]; + /** + * 供应商名称 + */ + supplierName?: string; + } export interface CrmQuoteInfoQuery extends PageQuery { @@ -502,7 +512,7 @@ export interface CrmQuoteInfoQuery extends PageQuery { customerContactEmail?: string; /** - * 供货方联系人ID + * 供货方ID */ supplierContactId?: string | number; @@ -550,6 +560,12 @@ export interface CrmQuoteInfoQuery extends PageQuery { * 日期范围参数 */ params?: any; + + /** + * 供应商名称 + */ + supplierName?: string; + } diff --git a/src/api/oa/crm/crmSupplierInfo/types.ts b/src/api/oa/crm/crmSupplierInfo/types.ts index 1d0f481..7c58139 100644 --- a/src/api/oa/crm/crmSupplierInfo/types.ts +++ b/src/api/oa/crm/crmSupplierInfo/types.ts @@ -267,6 +267,11 @@ export interface CrmSupplierInfoForm extends BaseEntity { */ activeFlag?: string; + /** + * 归属人员名称 + */ + ownerName?: string; + } export interface CrmSupplierInfoQuery extends PageQuery { @@ -395,6 +400,11 @@ export interface CrmSupplierInfoQuery extends PageQuery { * 日期范围参数 */ params?: any; + + /** + * 归属人员名称 + */ + ownerName?: string; } diff --git a/src/views/oa/crm/crmQuoteInfo/edit.vue b/src/views/oa/crm/crmQuoteInfo/edit.vue index 40183b9..24e7817 100644 --- a/src/views/oa/crm/crmQuoteInfo/edit.vue +++ b/src/views/oa/crm/crmQuoteInfo/edit.vue @@ -6,7 +6,7 @@
添加报价单基本信息
- + - - - + + + 计划内 + 计划外 + + + + + + + + + + + + @@ -241,61 +325,44 @@
报价明细表格
- 新增物料 + 新增物料
- - - - + + + + + - + + - + - + - + - + + - - - - - - - - - @@ -331,10 +398,13 @@ import { CrmQuoteInfoForm } from '@/api/oa/crm/crmQuoteInfo/types'; import type { CrmQuoteMaterialForm } from '@/api/oa/crm/crmQuoteMaterial/types'; import { getBaseMaterialInfoList } from '@/api/oa/base/materialInfo'; import { getCrmCustomerContactList } from '@/api/oa/crm/customerContact'; +import { getCrmSupplierInfoList } from '@/api/oa/crm/crmSupplierInfo'; import { getRuleGenerateCode } from '@/api/system/codeRule'; +import { getBaseUnitInfoList } from '@/api/oa/base/unitInfo'; +import SaleMaterialSelect from '@/components/SaleMaterialSelect/index.vue'; const { proxy } = getCurrentInstance() as ComponentInternalInstance; -const { business_direction, currency_type, quote_category, contract_type } = toRefs(proxy?.useDict('business_direction', 'currency_type', 'quote_category', 'contract_type')); +const { business_direction, currency_type, quote_category, contract_type, plan_flag } = toRefs(proxy?.useDict('business_direction', 'currency_type', 'quote_category', 'contract_type', 'plan_flag')); const router = useRouter(); const route = useRoute(); @@ -382,7 +452,118 @@ const rules = { // 下拉数据 const materialList = ref([]); const customerContactList = ref([]); -const supplierContactList = ref([]); +const supplierList = ref([]); +// 供应商计划标识:1计划内,2计划外 +const supplierPlanFlag = ref('1'); + +// 单位下拉数据 +const unitInfoList = ref([]); +const getUnitInfoListSelect = async () => { + const res = await getBaseUnitInfoList(null); + unitInfoList.value = res.data || []; +}; + +// 物料编辑弹窗与表单 +const materialDialog = reactive({ visible: false, title: '' }); +const materialFormRef = ref(); +const initMaterialFormData: CrmQuoteMaterialForm & { planFlag?: string } = { + quoteMaterialId: undefined, + planFlag: '2', // 1计划内,2计划外 + quoteId: undefined, + productName: undefined, + specificationDescription: undefined, + materialId: undefined, + relationMaterialId: undefined, + amount: undefined, + unitId: undefined, + unitName: undefined, + beforePrice: undefined, + taxRate: undefined, + includingPrice: undefined, + subtotal: undefined, + remark: undefined, + activeFlag: '1' +}; +const materialForm = ref({ ...initMaterialFormData }); +const materialRules = { + productName: [{ required: true, message: '产品名称不能为空', trigger: 'blur' }], + amount: [{ required: true, message: '数量不能为空', trigger: 'blur' }], + taxRate: [{ required: true, message: '税率不能为空', trigger: 'blur' }] +}; +const saleMaterialSelectRef = ref>(); +const openSaleMaterialSelect = () => saleMaterialSelectRef.value?.open(); +const saleMaterialSelectCallBack = (data: any) => { + const list = data || []; + if (list.length) { + const m = list[0]; + materialForm.value.materialId = m.materialId; + materialForm.value.relationMaterialId = m.relationMaterialId; + materialForm.value.productName = m.saleMaterialName || m.materialName; + if (m.unitName) materialForm.value.unitName = m.unitName; + } +}; +const resetMaterialForm = () => { + materialForm.value = { ...initMaterialFormData }; + materialFormRef.value?.resetFields(); +}; +const cancelMaterial = () => { + resetMaterialForm(); + materialDialog.visible = false; +}; +const calculateBeforePrice = () => { + const tax = Number(materialForm.value.taxRate); + const including = Number(materialForm.value.includingPrice); + if (!isNaN(tax) && !isNaN(including)) { + const divisor = 1 + tax / 100; + if (divisor > 0) { + materialForm.value.beforePrice = Number((including / divisor).toFixed(2)); + } + } + calculateSubtotal(); +}; +const calculateSubtotal = () => { + const amount = Number(materialForm.value.amount); + const including = Number(materialForm.value.includingPrice); + if (!isNaN(amount) && !isNaN(including)) { + materialForm.value.subtotal = Number((amount * including).toFixed(2)); + } +}; +const handleAddMaterial = () => { + resetMaterialForm(); + materialForm.value.quoteId = form.quoteId as any; + materialDialog.visible = true; + materialDialog.title = '新增报价物料'; +}; +const handleEditMaterial = (row: CrmQuoteMaterialForm) => { + resetMaterialForm(); + materialForm.value = { ...(row as any), planFlag: (row as any).materialId ? '1' : '2' }; + materialDialog.visible = true; + materialDialog.title = '编辑报价物料'; +}; +const handleDeleteMaterial = async (row: CrmQuoteMaterialForm) => { + await proxy?.$modal.confirm('是否确认删除该报价物料?'); + const idx = materialRows.value.findIndex((x: any) => x.quoteMaterialId === (row as any).quoteMaterialId); + if (idx !== -1) materialRows.value.splice(idx, 1); + else { + const i2 = materialRows.value.indexOf(row); + if (i2 !== -1) materialRows.value.splice(i2, 1); + } + proxy?.$modal.msgSuccess('删除成功'); +}; +const submitMaterialForm = () => { + materialFormRef.value?.validate((valid: boolean) => { + if (!valid) return; + if ((materialForm.value as any).quoteMaterialId) { + const idx = materialRows.value.findIndex((x: any) => x.quoteMaterialId === (materialForm.value as any).quoteMaterialId); + if (idx !== -1) materialRows.value[idx] = { ...materialForm.value } as any; + } else { + const newItem = { ...materialForm.value, quoteMaterialId: Date.now() } as any; + materialRows.value.push(newItem); + } + proxy?.$modal.msgSuccess('操作成功'); + materialDialog.visible = false; + }); +}; // 物料行 const materialRows = ref([]); @@ -409,7 +590,20 @@ const getSummary = (param: any) => { }; const addMaterialRow = () => { - materialRows.value.push({ amount: 0, beforePrice: 0, taxRate: Number(form.taxRate || 0), includingPrice: 0, subtotal: 0 } as CrmQuoteMaterialForm); + // 默认支持非标:预留自填名称与规格;单位可手填 + materialRows.value.push({ + materialId: undefined, + unitId: undefined, + unitName: '', + productName: '', + specificationDescription: '', + amount: 0, + beforePrice: 0, + taxRate: Number(form.taxRate || 0), + includingPrice: 0, + subtotal: 0, + remark: '' + } as CrmQuoteMaterialForm); }; const removeRow = (idx: number) => materialRows.value.splice(idx, 1); // 工具:数值化与保留两位小数 @@ -477,14 +671,32 @@ const onCustomerContactChanged = (id: any) => { form.customerContactPhone = c?.phoneNumber || ''; form.customerContactEmail = c?.email || ''; }; -const onSupplierContactChanged = (id: any) => { - const c = supplierContactList.value.find((x: any) => x.contactId === id); - form.supplierContactName = c?.contactName || ''; - form.supplierContactPhone = c?.phoneNumber || ''; - form.supplierContactEmail = c?.email || ''; +// 供应商计划标识变化处理 +const onSupplierPlanFlagChanged = (flag: string) => { + supplierPlanFlag.value = flag; + // 切换计划标识时清空供应商选择 + form.supplierContactId = undefined; + form.supplierContactName = ''; + form.supplierContactPhone = ''; + form.supplierContactEmail = ''; +}; +// 供应商选择变化处理(计划内供应商) +const onSupplierChanged = (supplierId: any) => { + const supplier = supplierList.value.find((x: any) => x.supplierId === supplierId); + if (supplier) { + // 从供应商信息中带出联系人、电话、邮箱(可编辑) + form.supplierContactName = supplier.contactPerson || ''; + form.supplierContactPhone = supplier.contactPhone || supplier.contactMobile || ''; + form.supplierContactEmail = supplier.contactEmail || ''; + } }; const onMaterialChange = (row: any) => { - // 可扩展:根据选中物料带出单位等 + // 根据选中物料带出单位与名称(若有),提升录入效率 + const m = materialList.value.find((x: any) => x.materialId === row.materialId); + if (m) { + if (m.unitName) row.unitName = m.unitName; + if (!row.productName && m.materialName) row.productName = m.materialName; + } }; // 生成报价单编号(codeRuleCode=1004) @@ -553,7 +765,10 @@ onMounted(async () => { materialList.value = materialRes.data || []; const contactRes = await getCrmCustomerContactList({}); customerContactList.value = contactRes.data || []; - supplierContactList.value = contactRes.data || []; + // 加载供应商列表(计划内供应商) + const supplierRes = await getCrmSupplierInfoList({}); + supplierList.value = supplierRes.data || []; + await getUnitInfoListSelect(); // 编辑场景 const id = route.query.id || route.params.id; @@ -569,8 +784,19 @@ onMounted(async () => { if (!form.customerContactPhone || !form.customerContactEmail || !form.customerContactName) { onCustomerContactChanged(form.customerContactId); } - if (!form.supplierContactPhone || !form.supplierContactEmail || !form.supplierContactName) { - onSupplierContactChanged(form.supplierContactId); + // 供应商信息回填:判断是否为计划内供应商 + if (form.supplierContactId) { + const supplier = supplierList.value.find((x: any) => x.supplierId === form.supplierContactId); + if (supplier) { + // 计划内供应商 + supplierPlanFlag.value = '1'; + if (!form.supplierContactPhone || !form.supplierContactEmail || !form.supplierContactName) { + onSupplierChanged(form.supplierContactId); + } + } else { + // 计划外供应商 + supplierPlanFlag.value = '2'; + } } // 仅使用后端VO内联返回的 itemsVo,前端不再单独请求子表接口 const inlineItems = (res.data as any)?.itemsVo; @@ -581,8 +807,11 @@ onMounted(async () => { quoteId: r.quoteId, itemNo: r.itemNo, materialId: r.materialId, + relationMaterialId: r.relationMaterialId, unitId: r.unitId, unitName: r.unitName, + productName: r.productName, + specificationDescription: r.specificationDescription, amount: Number(r.amount ?? 0), beforePrice: Number(r.beforePrice ?? 0), taxRate: Number(r.taxRate ?? (form.taxRate ?? 0)), diff --git a/src/views/oa/crm/crmQuoteInfo/index.vue b/src/views/oa/crm/crmQuoteInfo/index.vue index de0bea8..19535b7 100644 --- a/src/views/oa/crm/crmQuoteInfo/index.vue +++ b/src/views/oa/crm/crmQuoteInfo/index.vue @@ -104,8 +104,8 @@ - - + + @@ -159,6 +159,9 @@ 导出 + + 模板导出 +
@@ -223,7 +226,7 @@ - + @@ -255,6 +258,9 @@ + + + @@ -388,8 +394,8 @@ - - + + @@ -445,9 +451,11 @@