casualroom/apps/fenghuo/web/lib/profile/utils.ts

180 lines
6.6 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as ExcelJS from 'exceljs';
import { EliteFormData } from '@fenghuo/common';
/**
* 导出精英表单为 Excel 文件
* @param data 表格数据
* @param columns 列头
* @param filename 文件名(可选)
*/
export async function exportEliteFormToExcel(
data: EliteFormData[],
columns: string[],
filename?: string
): Promise<void> {
try {
// 创建工作簿
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('骨干名册');
// 设置列定义
worksheet.columns = [
{ header: '序号', key: 'sequence', width: 8 },
{ header: '专业', key: 'profession', width: 15 },
{ header: '台站', key: 'station', width: 20 },
{ header: '技师(值班代号)', key: 'technician', width: 25 },
{ header: '领班员/台站长(值班代号)', key: 'supervisor', width: 28 },
{ header: '值机员/值班员(值班代号)', key: 'operator', width: 25 }
];
// 设置表头样式
const headerRow = worksheet.getRow(1);
headerRow.height = 25;
headerRow.eachCell((cell) => {
// 移除背景色
cell.font = {
size: 10,
name: '黑体'
};
cell.alignment = {
vertical: 'middle',
horizontal: 'center'
};
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
});
// 按专业分组数据
const groupedData = new Map<string, EliteFormData[]>();
data.forEach(row => {
const profession = row.profession;
if (!groupedData.has(profession)) {
groupedData.set(profession, []);
}
const professionRows = groupedData.get(profession);
if (professionRows) {
professionRows.push(row);
}
});
// 添加数据行并处理合并单元格
let currentRow = 2; // 从第2行开始第1行是表头
let sequenceNumber = 1;
// 辅助函数:根据职务等级生成星星
const getStars = (dutyLevel: number): string => {
return '★'.repeat(dutyLevel);
};
// 辅助函数:格式化人员信息
const formatPersonInfo = (person: { name: string; dutyCode: string; dutyLevel: number }): string => {
const stars = person.dutyLevel > 0 ? getStars(person.dutyLevel) : '';
return `${person.name}(${person.dutyCode})${stars}`;
};
for (const [profession, rows] of groupedData) {
const startRow = currentRow;
// 添加该专业的所有行
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
if (!row) continue; // 跳过undefined的行
const excelRow = worksheet.addRow({
sequence: i === 0 ? sequenceNumber : '', // 只在第一行显示序号
profession: i === 0 ? profession : '', // 只在第一行显示专业名称
station: row.parentOrganization ? `${row.parentOrganization}${row.station}` : row.station,
technician: row.technicians.map(formatPersonInfo).join('、') || '',
supervisor: row.supervisors.map(formatPersonInfo).join('、') || '',
operator: row.operators.map(formatPersonInfo).join('、') || ''
});
// 设置行高(根据内容自动调整)
const maxLines = Math.max(
row.technicians.length || 1,
row.supervisors.length || 1,
row.operators.length || 1
);
excelRow.height = Math.max(40, maxLines * 20);
// 设置单元格样式
excelRow.eachCell((cell, colNumber) => {
cell.alignment = {
vertical: 'middle',
horizontal: colNumber <= 3 ? 'center' : 'left', // 序号、专业、台站居中,其他左对齐
wrapText: true
};
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
cell.font = {
name: '仿宋GB2312',
size: 10
};
});
currentRow++;
}
// 如果该专业有多行,合并序号和专业单元格
if (rows.length > 1) {
const endRow = currentRow - 1;
// 合并序号列
worksheet.mergeCells(startRow, 1, endRow, 1);
// 合并专业列
worksheet.mergeCells(startRow, 2, endRow, 2);
// 设置合并后单元格的对齐方式和字体
worksheet.getCell(startRow, 1).alignment = {
vertical: 'middle',
horizontal: 'center'
};
worksheet.getCell(startRow, 1).font = {
name: '仿宋GB2312',
size: 11
};
worksheet.getCell(startRow, 2).alignment = {
vertical: 'middle',
horizontal: 'center'
};
worksheet.getCell(startRow, 2).font = {
name: '仿宋GB2312',
size: 11
};
}
sequenceNumber++;
}
// 生成文件并下载
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
const defaultFilename = `骨干名册_${new Date().toISOString()}.xlsx`;
// 创建下载链接
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename || defaultFilename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
} catch (error) {
console.error('导出Excel失败:', error);
throw new Error('导出Excel失败请稍后重试');
}
}