fix(oa-board): wrap timeout followup exports

This commit is contained in:
jingchuan 2026-07-17 18:28:02 +08:00
parent bb3445fdd1
commit b0a7ec9591

View File

@ -82,6 +82,41 @@ function applyTimeoutCellStyle(worksheet: ExcelJS.Worksheet) {
})
}
function applyTimeoutFollowupExportStyle(worksheet: ExcelJS.Worksheet) {
const followupHeaders = new Set([
'超时跟进状态',
'超时原因',
'解决措施',
'超时跟进人',
'预计完成日期',
'最近跟进时间',
])
const followupColumns: number[] = []
for (let column = 1; column <= worksheet.columnCount; column += 1) {
if (followupHeaders.has(worksheet.getRow(1).getCell(column).text)) {
followupColumns.push(column)
}
}
for (let rowNumber = 2; rowNumber <= worksheet.rowCount; rowNumber += 1) {
const row = worksheet.getRow(rowNumber)
let lineCount = 1
followupColumns.forEach((column) => {
const cell = row.getCell(column)
cell.alignment = { vertical: 'top', wrapText: true }
if (typeof cell.value === 'string') {
lineCount = Math.max(lineCount, cell.value.split(/\r?\n/).length)
}
})
if (lineCount > 1) {
row.height = Math.max(20, lineCount * 18)
}
}
}
type TimelineMetricMap = Record<
string,
{
@ -145,6 +180,13 @@ const TIMING_DETAIL_DEFINITIONS: TimingDetailDefinition[] = [
{ header: '实际-运营上架', metricKey: 'listing', valueType: 'actual' },
]
const TIMEOUT_FOLLOWUP_STAGE_ORDER = new Map(
Array.from(new Set(TIMING_DETAIL_DEFINITIONS.map((item) => item.metricKey))).map((stageKey, index) => [
stageKey,
index,
]),
)
function formatDayValue(value: number | null | undefined) {
if (value === null || value === undefined || Number.isNaN(value)) return ''
return value
@ -198,14 +240,15 @@ function formatTimeoutFollowupStatus(status: OaBoardTimeoutFollowupDTO['status']
}
function buildTimeoutFollowupExportValues(followups: OaBoardTimeoutFollowupDTO[]) {
const records = [...followups].sort((left, right) => left.stageLabel.localeCompare(right.stageLabel, 'zh-CN'))
const records = [...followups].sort((left, right) => {
const leftOrder = TIMEOUT_FOLLOWUP_STAGE_ORDER.get(left.stageKey) ?? Number.MAX_SAFE_INTEGER
const rightOrder = TIMEOUT_FOLLOWUP_STAGE_ORDER.get(right.stageKey) ?? Number.MAX_SAFE_INTEGER
if (leftOrder !== rightOrder) return leftOrder - rightOrder
return left.stageLabel.localeCompare(right.stageLabel, 'zh-CN')
})
const joinByStage = (value: (record: OaBoardTimeoutFollowupDTO) => string | null) =>
records
.map((record) => {
const text = value(record)
return text ? `${record.stageLabel}:${text}` : ''
})
.filter(Boolean)
.map((record) => `${record.stageLabel}:${value(record)?.trim() || '-'}`)
.join('\n')
return {
@ -216,7 +259,9 @@ function buildTimeoutFollowupExportValues(followups: OaBoardTimeoutFollowupDTO[]
timeoutActionPlan: joinByStage((record) => record.actionPlan),
timeoutFollowUpOwner: joinByStage((record) => record.followUpOwner),
timeoutExpectedResolveDate: joinByStage((record) => record.expectedResolveDate),
timeoutLastFollowedAt: joinByStage((record) => record.updatedAt?.replace('T', ' ').slice(0, 16) ?? null),
timeoutLastFollowedAt: joinByStage((record) =>
(record.lastFollowedAt ?? record.updatedAt)?.replace('T', ' ').slice(0, 16) ?? null,
),
}
}
@ -463,6 +508,7 @@ export async function GET(request: NextRequest) {
applyHeaderStyle(overview)
applyHeaderStyle(detail)
applyTimeoutCellStyle(detail)
applyTimeoutFollowupExportStyle(detail)
const buffer = await workbook.xlsx.writeBuffer()
const fileName = `oa-board-${nowStamp()}.xlsx`