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}