40 lines
2.7 KiB
TypeScript
40 lines
2.7 KiB
TypeScript
import type ExcelJS from 'exceljs'
|
||
import { percentageBasisPoints, sourceLabel, performancePositions, type SalaryPosition, type ScoreSourceOption } from './salary-position-contract'
|
||
|
||
export async function buildPositionWorkbook(positions: SalaryPosition[], sources: ScoreSourceOption[]) {
|
||
positions = performancePositions(positions)
|
||
if (!positions.length) throw new Error('暂无可导出的岗位配置。')
|
||
const { default: Excel } = await import('exceljs')
|
||
const workbook = new Excel.Workbook()
|
||
workbook.creator = '品牌中心'
|
||
const used = new Set<string>()
|
||
for (const position of positions) {
|
||
const base = position.name.replace(/[\\/*?:\[\]]/g, ' ').replace(/^'+|'+$/g, '').trim().slice(0, 26) || '岗位'
|
||
let name = base, index = 1
|
||
while (used.has(name.toLocaleLowerCase())) name = `${base.slice(0, 25)}_${++index}`
|
||
used.add(name.toLocaleLowerCase())
|
||
const sheet = workbook.addWorksheet(name)
|
||
sheet.columns = [{ width: 24 }, { width: 14 }, { width: 32 }, { width: 14 }, { width: 16 }, { width: 42 }, { width: 58 }]
|
||
sheet.mergeCells('A1:G1'); sheet.getCell('A1').value = `${position.name} · 岗位绩效配置`
|
||
sheet.mergeCells('A2:G2'); sheet.getCell('A2').value = `${position.jobGrade ? `适用职级 ${position.jobGrade};` : ''}${position.description || '岗位绩效配置'};修改后适用于所有月份;配置版本 ${position.revision}`
|
||
sheet.addRow(['考核维度', '维度权重', 'KPI指标', 'KPI权重', '综合占比', '计分来源', 'KPI说明'])
|
||
for (const dimension of position.dimensions) for (const metric of dimension.metrics) sheet.addRow([
|
||
dimension.name, percentageBasisPoints(dimension.weight) / 10000, metric.name, percentageBasisPoints(metric.weight) / 10000,
|
||
percentageBasisPoints(dimension.weight) * percentageBasisPoints(metric.weight) / 1e8, sourceLabel(metric.source, sources), metric.description,
|
||
])
|
||
if (!position.dimensions.length) sheet.addRow(['绩效未配置'])
|
||
sheet.eachRow((row, rowIndex) => {
|
||
row.height = rowIndex === 1 ? 30 : rowIndex === 2 ? 42 : 48
|
||
row.eachCell({ includeEmpty: true }, cell => {
|
||
cell.font = { name: '微软雅黑', size: rowIndex === 1 ? 14 : 11, bold: rowIndex === 1 || rowIndex === 3, color: { argb: 'FF101828' } }
|
||
cell.alignment = { vertical: 'middle', wrapText: true }
|
||
if (rowIndex === 3) cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE6EDF5' } }
|
||
if (rowIndex > 3 && [2, 4, 5].includes(Number(cell.col))) cell.numFmt = '0.00%'
|
||
})
|
||
})
|
||
sheet.views = [{ state: 'frozen', xSplit: 1, ySplit: 3 }]
|
||
sheet.pageSetup = { orientation: 'landscape', printTitlesRow: '1:3' } as ExcelJS.PageSetup
|
||
}
|
||
return workbook
|
||
}
|