From 2df4dfd66f4574cca95a0e1373f3833ddb2ec3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=9F=E6=9E=97=E9=93=96?= Date: Sat, 7 Nov 2026 14:17:00 +0800 Subject: [PATCH] fix(salary): show and freeze nickname as first column --- .../PerformanceSalaryDetails.test.tsx | 10 ++++++++++ lib/__tests__/performance-salary-export.test.ts | 5 +++++ lib/__tests__/performance-salary-templates.test.ts | 4 +++- lib/performance-salary-templates.ts | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/components/department-dashboard/PerformanceSalaryDetails.test.tsx b/components/department-dashboard/PerformanceSalaryDetails.test.tsx index 0d579a02..d85a4308 100644 --- a/components/department-dashboard/PerformanceSalaryDetails.test.tsx +++ b/components/department-dashboard/PerformanceSalaryDetails.test.tsx @@ -44,6 +44,9 @@ test('管理岗无人时展示保存方案完整表头与5行真空白,不伪 const table = within(region).getByRole('table') const headings = within(within(table).getAllByRole('row')[1]).getAllByRole('columnheader') expect(headings.map(cell => cell.textContent)).toEqual(data.positionGroups[0].template.columns.map(column => column.label)) + expect(headings[0]).toHaveTextContent('花名') + expect(headings[0]).toHaveClass('sticky', 'left-0') + expect(headings[1]).toHaveTextContent('姓名') expect(headings.some(cell => cell.textContent?.includes('积分'))).toBe(false) expect(headings.filter(cell => cell.textContent === '绩效系数')).toHaveLength(1) expect(headings.filter(cell => /考核得分/.test(cell.textContent || '')).map(cell => cell.textContent?.match(/综合占比(\d+)%/)?.[1])).toEqual(['40', '10', '16', '12', '12', '10']) @@ -71,6 +74,8 @@ test('管理岗出现真实人员后只展示真实行,保留缺分和薪资 expect(screen.getByText('2500.00')).toBeInTheDocument() const headers = within(within(table).getAllByRole('row')[1]).getAllByRole('columnheader') const cells = within(within(table).getAllByRole('row')[2]).getAllByRole('cell') + expect(cells[0]).toHaveTextContent('——') + expect(cells[1]).toHaveTextContent('测试主管') for (const label of ['绩效系数', '2026年10月合计总薪资']) expect(cells[headers.findIndex(header => header.textContent === label)]).toHaveTextContent('——') }) @@ -93,6 +98,11 @@ test('展示真实人员、精确金额、缺失值、来源提示及内部横 expect(await screen.findByText('测试姓名')).toBeInTheDocument() expect(within(screen.getAllByRole('row')[1]).getAllByRole('columnheader')).toHaveLength(26) expect(screen.getAllByRole('row')).toHaveLength(3) + const cells = screen.getAllByRole('cell') + expect(cells[0]).toHaveTextContent('测试花名') + expect(cells[0]).toHaveClass('sticky', 'left-0') + expect(cells[1]).toHaveTextContent('测试姓名') + expect(cells[1]).not.toHaveClass('sticky') expect(screen.getByText('1000.01')).toBeInTheDocument() expect(screen.getAllByRole('cell').filter(cell => cell.textContent === '——').length).toBeGreaterThan(0) expect(screen.getByText('数据月份:2026年10月;市场验证考核月份:2026年9月')).toBeInTheDocument() diff --git a/lib/__tests__/performance-salary-export.test.ts b/lib/__tests__/performance-salary-export.test.ts index 96cbaa7a..68aadb06 100644 --- a/lib/__tests__/performance-salary-export.test.ts +++ b/lib/__tests__/performance-salary-export.test.ts @@ -22,6 +22,8 @@ test('导出后重新读取:五岗模板字段、空行、冻结及月份均 expect(sheet.state).toBe('visible') expect(JSON.stringify(sheet.getRow(target.headerRow).values)).not.toMatch(/加权得分|绩效占比|绩效得分/) const headers = sheet.getRow(target.headerRow).values as string[] + expect(sheet.getCell(target.headerRow, 1).value).toBe('花名') + if (index !== 1) expect(sheet.getCell(target.headerRow, 2).value).toBe('姓名') expect(headers.filter(value => value === '绩效系数')).toHaveLength(1) expect(sheet.getCell(target.headerRow + 1, headers.indexOf('绩效系数')).numFmt).toBe('0.00') expect(sheet.columnCount).toBe(target.columns) @@ -57,6 +59,9 @@ test('按保存岗位导出使用相邻原始值与考核得分,百分比不 for (const position of positions) { const sheet = restored.getWorksheet(position.name)! const template = getPositionSalaryTemplate(position, '2026-10') + expect(sheet.getCell(3, 1).value).toBe('花名') + expect(sheet.getCell(3, 2).value).toBe('姓名') + expect(sheet.views[0]).toEqual(expect.objectContaining({ state: 'frozen', xSplit: 1, ySplit: 3 })) expect(sheet.getRow(3).values).toEqual([undefined, ...template.columns.map(column => column.label)]) if (position.salaryRole === 'ai-planning') expect(JSON.stringify(sheet.getRow(3).values)).toContain('创意成果市场验证 · 市场验证得分(上月)') expect(JSON.stringify(sheet.getRow(3).values)).not.toMatch(/加权得分/) diff --git a/lib/__tests__/performance-salary-templates.test.ts b/lib/__tests__/performance-salary-templates.test.ts index b78bad01..4a61c7e8 100644 --- a/lib/__tests__/performance-salary-templates.test.ts +++ b/lib/__tests__/performance-salary-templates.test.ts @@ -48,7 +48,7 @@ describe('薪资模板月份与字段', () => { const template = getSalaryTemplate('management', '2027-01') const labels = template.columns.map(column => column.label) expect(labels).toHaveLength(23) - expect(labels.filter(label => ['姓名', '花名', '部门'].includes(label))).toEqual(['姓名', '花名', '部门']) + expect(labels.filter(label => ['姓名', '花名', '部门'].includes(label))).toEqual(['花名', '姓名', '部门']) expect(labels).not.toContain('保护提成') expect(labels).toEqual(expect.arrayContaining(['绩效系数', '2027年1月合计总薪资', '2026年12月薪资'])) expect(new Set(template.columns.map(column => column.key)).size).toBe(23) @@ -57,6 +57,8 @@ describe('薪资模板月份与字段', () => { test.each(['ai-planning', 'photography', 'spatial-visual', 'management', 'ai-technical'] as const)('%s默认与配置模板保持原始值在前、考核得分在后', role => { const position = { ...INITIAL_SALARY_POSITIONS[0].value, salaryRole: role, id: 'job', revision: 1, personnelCount: 0, updatedAt: '' } for (const template of [getSalaryTemplate(role, '2026-09'), getPositionSalaryTemplate(position, '2026-09')]) { + expect(template.columns[0]).toMatchObject({ key: 'nickname', label: '花名' }) + if (role !== 'photography' || template.grouped) expect(template.columns[1]).toMatchObject({ key: 'name', label: '姓名' }) expect(template.columns.filter(column => column.key === 'performanceCoefficient')).toHaveLength(1) expect(template.columns.some(column => column.key === 'performanceScore' || column.label.includes('绩效得分'))).toBe(false) expect(template.columns.find(column => column.key === 'currentTotal')?.label).toBe('2026年9月合计总薪资') diff --git a/lib/performance-salary-templates.ts b/lib/performance-salary-templates.ts index 756332fe..97a104eb 100644 --- a/lib/performance-salary-templates.ts +++ b/lib/performance-salary-templates.ts @@ -55,7 +55,7 @@ export function salaryDetailsHref(role: SalaryRole, month: string): string { const column = (key: string, label: string, kind: SalaryTemplateColumn['kind'] = 'text', width = 144): SalaryTemplateColumn => ({ key, label, kind, width }) const group = (key: string, label: string, columns: SalaryTemplateColumn[]): SalaryTemplateGroup => ({ key, label, columns }) const identity = (brand = false) => [ - column('name', '姓名', 'text', 104), column('nickname', '花名', 'text', 104), column('jobGrade', '职级', 'text', 104), + column('nickname', '花名', 'text', 104), column('name', '姓名', 'text', 104), column('jobGrade', '职级', 'text', 104), column('department', '部门', 'text', 160), ...(brand ? [column('brand', '品牌', 'text', 136)] : []), ] const baseWages = () => [column('baseSalary', '基本工资', 'money'), column('gradeSalary', '职级工资', 'money'), column('performanceSalary', '绩效工资', 'money')]