diff --git a/backend/src/main/java/com/unis/crm/service/impl/ExpansionServiceImpl.java b/backend/src/main/java/com/unis/crm/service/impl/ExpansionServiceImpl.java index 741e42b0..5d219f4a 100644 --- a/backend/src/main/java/com/unis/crm/service/impl/ExpansionServiceImpl.java +++ b/backend/src/main/java/com/unis/crm/service/impl/ExpansionServiceImpl.java @@ -475,7 +475,7 @@ public class ExpansionServiceImpl implements ExpansionService { request.setCertificationLevel(normalizeRequiredText(request.getCertificationLevel(), "请选择认证级别")); request.setOfficeAddress(normalizeRequiredText(request.getOfficeAddress(), "请填写办公地址")); request.setChannelIndustry(normalizeRequiredText(request.getChannelIndustry(), "请选择聚焦行业")); - request.setAnnualRevenue(requirePositiveAmount(request.getAnnualRevenue(), "请填写年营收")); + request.setAnnualRevenue(requirePositiveAmount(request.getAnnualRevenue(), "请填写年度营业额(万元)")); request.setStaffSize(requirePositiveInteger(request.getStaffSize(), "请填写人员规模")); if (request.getContactEstablishedDate() == null) { throw new BusinessException("请选择建立联系时间"); @@ -504,7 +504,7 @@ public class ExpansionServiceImpl implements ExpansionService { request.setCertificationLevel(normalizeRequiredText(request.getCertificationLevel(), "请选择认证级别")); request.setOfficeAddress(normalizeRequiredText(request.getOfficeAddress(), "请填写办公地址")); request.setChannelIndustry(normalizeRequiredText(request.getChannelIndustry(), "请选择聚焦行业")); - request.setAnnualRevenue(requirePositiveAmount(request.getAnnualRevenue(), "请填写年营收")); + request.setAnnualRevenue(requirePositiveAmount(request.getAnnualRevenue(), "请填写年度营业额(万元)")); request.setStaffSize(requirePositiveInteger(request.getStaffSize(), "请填写人员规模")); if (request.getContactEstablishedDate() == null) { throw new BusinessException("请选择建立联系时间"); diff --git a/backend/src/main/resources/mapper/expansion/ExpansionMapper.xml b/backend/src/main/resources/mapper/expansion/ExpansionMapper.xml index a266ba65..933b059a 100644 --- a/backend/src/main/resources/mapper/expansion/ExpansionMapper.xml +++ b/backend/src/main/resources/mapper/expansion/ExpansionMapper.xml @@ -151,11 +151,10 @@ coalesce(c.channel_industry, c.industry, '') as channelIndustryCode, coalesce(c.channel_industry, c.industry, '无') as channelIndustry, coalesce(c.certification_level, '无') as certificationLevel, - coalesce(cast(c.annual_revenue as varchar), '') as annualRevenue, + coalesce(trim(to_char(c.annual_revenue, 'FM999999990.##')), '') as annualRevenue, case when c.annual_revenue is null then '无' - when c.annual_revenue >= 10000 then trim(to_char(c.annual_revenue / 10000.0, 'FM999999990.##')) || '万' - else trim(to_char(c.annual_revenue, 'FM999999990.##')) + else trim(to_char(c.annual_revenue, 'FM999999990.##')) || '万元' end as revenue, coalesce(c.staff_size, 0) as size, coalesce(primary_contact.contact_name, c.contact_name, '无') as primaryContactName, diff --git a/frontend/src/pages/Expansion.tsx b/frontend/src/pages/Expansion.tsx index ba1ac2d2..a34a28bd 100644 --- a/frontend/src/pages/Expansion.tsx +++ b/frontend/src/pages/Expansion.tsx @@ -77,6 +77,8 @@ function createEmptyChannelContact(): ChannelExpansionContact { }; } +const CHANNEL_REVENUE_LABEL = "年度营业额(万元)"; + const defaultSalesForm: CreateSalesExpansionPayload = { employeeNo: "", candidateName: "", @@ -303,6 +305,18 @@ function formatExportFollowUps(followUps?: ExpansionFollowUp[]) { .join("\n\n"); } +function formatExportProjectCell(project?: { opportunityCode?: string; opportunityName?: string; amount?: number | null }) { + if (!project) { + return ""; + } + const lines = [ + normalizeExportText(project.opportunityCode) ? `编码:${normalizeExportText(project.opportunityCode)}` : "", + normalizeExportText(project.opportunityName) ? `项目名称:${normalizeExportText(project.opportunityName)}` : "", + project.amount === null || project.amount === undefined ? "" : `金额:${formatAmount(Number(project.amount))}`, + ].filter(Boolean); + return lines.join("\n"); +} + function formatExportFilenameTime(date = new Date()) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); @@ -342,7 +356,7 @@ function buildSalesExportHeaders(items: SalesExpansionItem[]) { ]; for (let index = 0; index < maxProjects; index += 1) { - headers.push(`项目${index + 1}编码`, `项目${index + 1}名称`, `项目${index + 1}金额`); + headers.push(`项目${index + 1}`); } headers.push("创建人", "更新修改时间"); @@ -370,11 +384,7 @@ function buildSalesExportData(items: SalesExpansionItem[]) { for (let index = 0; index < maxProjects; index += 1) { const project = item.relatedProjects?.[index]; - row.push( - normalizeExportText(project?.opportunityCode), - normalizeExportText(project?.opportunityName), - project?.amount === null || project?.amount === undefined ? "" : formatAmount(Number(project.amount)), - ); + row.push(formatExportProjectCell(project)); } row.push( @@ -401,14 +411,14 @@ function buildChannelExportHeaders(items: ChannelExpansionItem[]) { "新华三内部属性", "合作意向", "建立联系时间", - "营收规模", + CHANNEL_REVENUE_LABEL, "人员规模", "以前是否做过云桌面项目", "跟进项目金额", ]; for (let index = 0; index < maxProjects; index += 1) { - headers.push(`项目${index + 1}编码`, `项目${index + 1}名称`, `项目${index + 1}金额`); + headers.push(`项目${index + 1}`); } for (let index = 0; index < maxContacts; index += 1) { @@ -446,11 +456,7 @@ function buildChannelExportData(items: ChannelExpansionItem[]) { for (let index = 0; index < maxProjects; index += 1) { const project = item.relatedProjects?.[index]; - row.push( - normalizeExportText(project?.opportunityCode), - normalizeExportText(project?.opportunityName), - project?.amount === null || project?.amount === undefined ? "" : formatAmount(Number(project.amount)), - ); + row.push(formatExportProjectCell(project)); } for (let index = 0; index < maxContacts; index += 1) { @@ -529,7 +535,7 @@ function validateChannelForm(form: CreateChannelExpansionPayload, channelOtherOp errors.channelIndustry = "请选择聚焦行业"; } if (!form.annualRevenue || form.annualRevenue <= 0) { - errors.annualRevenue = "请填写年营收"; + errors.annualRevenue = `请填写${CHANNEL_REVENUE_LABEL}`; } if (!form.staffSize || form.staffSize <= 0) { errors.staffSize = "请填写人员规模"; @@ -1622,6 +1628,9 @@ export default function Expansion() { worksheet.views = [{ state: "frozen", ySplit: 1 }]; const followUpColumnIndex = headers.indexOf("跟进记录") + 1; + const projectColumnIndexes = headers + .map((header, index) => (header.startsWith("项目") ? index + 1 : -1)) + .filter((index) => index > 0); worksheet.getRow(1).height = 24; worksheet.getRow(1).font = { bold: true }; worksheet.getRow(1).alignment = { vertical: "middle", horizontal: "center" }; @@ -1632,8 +1641,8 @@ export default function Expansion() { column.width = 42; } else if (header.includes("办公地址") || header.includes("备注")) { column.width = 24; - } else if (header.includes("项目") && header.includes("名称")) { - column.width = 24; + } else if (header.startsWith("项目")) { + column.width = 26; } else if (header.includes("渠道属性") || header.includes("内部属性") || header.includes("聚焦行业")) { column.width = 18; } else { @@ -1652,13 +1661,18 @@ export default function Expansion() { cell.alignment = { vertical: "top", horizontal: rowNumber === 1 ? "center" : "left", - wrapText: headers[columnNumber - 1] === "跟进记录", + wrapText: headers[columnNumber - 1] === "跟进记录" || headers[columnNumber - 1].startsWith("项目"), }; }); if (rowNumber > 1 && followUpColumnIndex > 0) { - const followUpText = normalizeExportText(row.getCell(followUpColumnIndex).value as string | null | undefined); - const lineCount = followUpText ? followUpText.split("\n").length : 1; - row.height = Math.max(22, lineCount * 16); + const followUpText = row.getCell(followUpColumnIndex).value as string | null | undefined; + const followUpLineCount = typeof followUpText === "string" && followUpText ? followUpText.split("\n").length : 1; + const projectLineCount = projectColumnIndexes.reduce((max, columnIndex) => { + const projectText = row.getCell(columnIndex).value as string | null | undefined; + const lineCount = typeof projectText === "string" && projectText ? projectText.split("\n").length : 1; + return Math.max(max, lineCount); + }, 1); + row.height = Math.max(22, Math.max(followUpLineCount, projectLineCount) * 16); } }); @@ -1919,8 +1933,16 @@ export default function Expansion() { {fieldErrors?.certificationLevel ?

{fieldErrors.certificationLevel}

: null}