组件外
// ============ 组件外:类型补充 ============ type CommonBuilderParams = { visibleCols: ColConfig[]; hasData: boolean; leftFixedKey?: string[]; rightFixedKey?: string[]; currentMonthKey?: string[]; CURRENT_MONTH: string; dataSource: ProposalData[]; renderOperation: CommonBuilderParams['renderOperation']; // 你原来的类型 calcTextWidth: (v: string) => number; monthLabel: (v: string) => string; matchColumnFilter: (v: unknown, keys: React.Key[]) => boolean; layout: 'period' | 'item'; // 新增 };
const buildStaticCol = (params: { col: ColConfig; fixed: 'left' | 'right' | undefined; common: CommonBuilderParams; }) => { const { col, fixed, common } = params; const { hasData, dataSource, calcTextWidth } = common; const dataIndex = col.dataIndex as keyof ProposalData; const headerWidth = calcTextWidth(col.title); const dataWidth = dataSource.reduce( (max, row) => Math.max(max, calcTextWidth(String(row[dataIndex] ?? ''))), 0 ); const colWidth = Math.max(headerWidth, dataWidth) + 56; return { title: col.title, dataIndex: col.dataIndex, key: col.key, width: colWidth, ...(fixed ? { fixed } : {}), onCell: () => ({ style: { whiteSpace: 'nowrap' } }), onHeaderCell: () => ({ style: { whiteSpace: 'nowrap' } }), sorter: hasData ? (a: ProposalData, b: ProposalData) => localeCompareJa(String(a[dataIndex] ?? ''), String(b[dataIndex] ?? '')) : (false as const), ...(hasData ? { filterDropdown: (props: FilterDropdownProps) => ( <VirtualFilterDropdown {...props} filters={generateColumnFilters(dataSource, dataIndex)} /> ), onFilter: (value: React.Key | boolean, record: ProposalData) => matchColumnFilter(record[dataIndex], [value as React.Key]), } : {}), }; };
// ============ 组件外:buildMonthChildCol ============
const buildMonthChildCol = (params: {
col: ColConfig;
m: string;
isCurrent: boolean;
common: CommonBuilderParams;
extraWidth?: number;
}) => {
const { col, m, isCurrent, common, extraWidth = 0 } = params;
const { hasData, dataSource, calcTextWidth, rightFixedKey, layout } = common;
const monthKey = `${col.key}__${m}`;
const isNumeric = col.numeric;
const headerWidth = calcTextWidth(col.title);
const dataWidth = dataSource.reduce(
(max, row) => Math.max(max, calcTextWidth(String(row.monthly?.[monthKey] ?? ''))),
0
);
const colWidth = Math.max(headerWidth, dataWidth) + 40 + extraWidth;
const isRightFixed = !!rightFixedKey?.includes(col.key);
const displayTitle =
layout === 'period'
? col.title
: <MonthHeaderLabel m={m} isCurrent={isCurrent} monthLabel={common.monthLabel} />;
return {
title: displayTitle,
key: monthKey,
dataIndex: ['monthly', monthKey],
width: colWidth,
fixed: isRightFixed ? ('right' as const) : undefined,
align: isNumeric ? ('right' as const) : undefined,
onCell: () => ({
style: {
whiteSpace: 'nowrap' as const,
...(isNumeric ? { textAlign: 'right' as const } : {}),
...(isCurrent ? { backgroundColor: '#fafcff' } : {}),
},
}),
onHeaderCell: () => ({
style: { whiteSpace: 'nowrap' as const, ...(isCurrent ? { backgroundColor: 