gongxiangp2/lib/performance-salary-export.ts

84 lines
3.8 KiB
TypeScript

import type ExcelJS from 'exceljs'
import { SALARY_ROLES } from './performance-salary-roles'
import { getSalaryTemplate, isSalaryMonth, SALARY_TEMPLATE_BLANK_ROWS } from './performance-salary-templates'
const XLSX_MIME = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
export function salaryExportFileName(month: string) {
if (!isSalaryMonth(month)) throw new Error('请选择有效月份后重试。')
return `绩效薪资模板_${month}.xlsx`
}
export async function buildSalaryTemplateWorkbook(month: string) {
salaryExportFileName(month)
const { default: Excel } = await import('exceljs')
const workbook = new Excel.Workbook()
workbook.creator = '品牌中心'
const border: Partial<ExcelJS.Borders> = {
top: { style: 'thin', color: { argb: 'FFE2E8F0' } }, bottom: { style: 'thin', color: { argb: 'FFE2E8F0' } },
left: { style: 'thin', color: { argb: 'FFE2E8F0' } }, right: { style: 'thin', color: { argb: 'FFE2E8F0' } },
}
for (const role of SALARY_ROLES) {
const template = getSalaryTemplate(role.key, month)
const sheet = workbook.addWorksheet(role.title)
const size = template.columns.length
const headerRow = template.grouped ? 3 : 2
sheet.mergeCells(1, 1, 1, size)
const title = sheet.getCell(1, 1)
title.value = `${month} ${role.title}薪资明细`
title.font = { name: '微软雅黑', size: 14, bold: true, color: { argb: 'FF101828' } }
title.alignment = { vertical: 'middle', horizontal: 'left' }
sheet.getRow(1).height = 34
if (template.grouped) {
let start = 1
for (const group of template.groups) {
const end = start + group.columns.length - 1
if (end > start) sheet.mergeCells(2, start, 2, end)
sheet.getCell(2, start).value = group.label
start = end + 1
}
sheet.getRow(2).height = 28
}
template.columns.forEach((column, index) => {
sheet.getColumn(index + 1).width = Math.round(column.width / 7)
sheet.getCell(headerRow, index + 1).value = column.label
})
sheet.getRow(headerRow).height = 64
for (let row = 2; row <= headerRow + SALARY_TEMPLATE_BLANK_ROWS; row += 1) {
if (row > headerRow) sheet.getRow(row).height = 30
for (let col = 1; col <= size; col += 1) {
const cell = sheet.getCell(row, col)
cell.border = border
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }
cell.font = { name: '微软雅黑', size: 11, color: { argb: 'FF344054' }, bold: row <= headerRow }
if (row <= headerRow) cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: row < headerRow ? 'FFE6EDF5' : 'FFF8FAFC' } }
else {
const kind = template.columns[col - 1].kind
cell.numFmt = kind === 'money' ? '#,##0.00' : kind === 'percent' ? '0.00%' : kind === 'number' ? '0.##' : '@'
}
}
}
sheet.views = [{ state: 'frozen', xSplit: 1, ySplit: headerRow, topLeftCell: `B${headerRow + 1}` }]
sheet.pageSetup = { orientation: 'landscape', printTitlesRow: `1:${headerRow}` }
sheet.pageSetup.printArea = `A1:${sheet.getColumn(size).letter}${headerRow + SALARY_TEMPLATE_BLANK_ROWS}`
}
return workbook
}
export async function saveSalaryTemplateWorkbook(month: string) {
const workbook = await buildSalaryTemplateWorkbook(month)
const buffer = await workbook.xlsx.writeBuffer()
const blob = new Blob([buffer], { type: XLSX_MIME })
if (typeof URL.createObjectURL !== 'function') throw new Error('当前浏览器无法下载文件,请更换浏览器后重试。')
const url = URL.createObjectURL(blob)
const anchor = document.createElement('a')
anchor.href = url
anchor.download = salaryExportFileName(month)
anchor.style.display = 'none'
document.body.appendChild(anchor)
try { anchor.click() } finally {
anchor.remove()
window.setTimeout(() => URL.revokeObjectURL(url), 1000)
}
}