84 lines
3.4 KiB
TypeScript
84 lines
3.4 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import ExcelJS from 'exceljs';
|
|
import PDFDocument from 'pdfkit';
|
|
import {
|
|
FINANCE_BANK_ACCOUNT_TYPE_LABELS,
|
|
type FinanceBankAccountDto,
|
|
} from '@dukang/shared-types';
|
|
import { pickExportColumns, type ExportColumnDef } from '../../common/export/column-export.util';
|
|
|
|
function resolvePdfFontPath(): string {
|
|
const candidates = [
|
|
process.env.EXPORT_PDF_FONT_PATH,
|
|
path.join(process.cwd(), 'assets', 'fonts', 'NotoSansSC-Regular.otf'),
|
|
path.join(process.cwd(), 'assets', 'fonts', 'simhei.ttf'),
|
|
path.join(process.cwd(), 'assets', 'fonts', 'msyh.ttc'),
|
|
path.join(process.cwd(), 'dist', 'assets', 'fonts', 'simhei.ttf'),
|
|
'/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc',
|
|
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
|
|
'C:\\Windows\\Fonts\\simhei.ttf',
|
|
'C:\\Windows\\Fonts\\msyh.ttc',
|
|
].filter(Boolean) as string[];
|
|
|
|
for (const candidate of candidates) {
|
|
if (fs.existsSync(candidate)) return candidate;
|
|
}
|
|
throw new Error('未找到可用于 PDF 的中文字体,请将字体文件放到 server/dukang-api/assets/fonts/');
|
|
}
|
|
|
|
function columnDefs(): ExportColumnDef<FinanceBankAccountDto>[] {
|
|
return [
|
|
{ key: 'type', header: '类型', value: (r) => FINANCE_BANK_ACCOUNT_TYPE_LABELS[r.type] },
|
|
{ key: 'ownerName', header: '归属', value: (r) => r.ownerName },
|
|
{ key: 'cityName', header: '城市', value: (r) => r.cityName ?? '' },
|
|
{ key: 'bankAccountName', header: '户名', value: (r) => r.bankAccountName },
|
|
{ key: 'bankAccountNo', header: '银行账号', value: (r) => r.bankAccountNo },
|
|
{ key: 'bankBranch', header: '开户行', value: (r) => r.bankBranch ?? '' },
|
|
{ key: 'isDefault', header: '默认', value: (r) => (r.type === 'STORE' ? (r.isDefault ? '是' : '否') : '') },
|
|
{ key: 'remark', header: '备注', value: (r) => r.remark ?? '' },
|
|
];
|
|
}
|
|
|
|
export async function buildFinanceBankAccountsXlsx(rows: FinanceBankAccountDto[]): Promise<Buffer> {
|
|
const cols = pickExportColumns(columnDefs());
|
|
const workbook = new ExcelJS.Workbook();
|
|
const sheet = workbook.addWorksheet('银行账户');
|
|
sheet.addRow(cols.map((c) => c.header));
|
|
for (const row of rows) {
|
|
sheet.addRow(cols.map((c) => c.value(row)));
|
|
}
|
|
sheet.columns.forEach((col) => {
|
|
col.width = 18;
|
|
});
|
|
const buffer = await workbook.xlsx.writeBuffer();
|
|
return Buffer.from(buffer);
|
|
}
|
|
|
|
export async function buildFinanceBankAccountsPdf(rows: FinanceBankAccountDto[]): Promise<Buffer> {
|
|
const cols = pickExportColumns(columnDefs());
|
|
const fontPath = resolvePdfFontPath();
|
|
const chunks: Buffer[] = [];
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const doc = new PDFDocument({ size: 'A4', layout: 'landscape', margin: 24, bufferPages: true });
|
|
doc.on('data', (c) => chunks.push(c as Buffer));
|
|
doc.on('end', () => resolve(Buffer.concat(chunks)));
|
|
doc.on('error', reject);
|
|
doc.font(fontPath);
|
|
doc.fontSize(12).text('银行账户');
|
|
doc.moveDown(0.4);
|
|
doc.fontSize(9).text(cols.map((c) => c.header).join(' | '));
|
|
doc.moveDown(0.3);
|
|
for (const row of rows) {
|
|
doc.text(cols.map((c) => String(c.value(row))).join(' | '));
|
|
}
|
|
doc.end();
|
|
});
|
|
}
|
|
|
|
export function buildFinanceBankExportFilename(format: 'xlsx' | 'pdf', count: number): string {
|
|
const stamp = new Date().toISOString().slice(0, 10);
|
|
return `银行账户_${stamp}_${count}.${format}`;
|
|
}
|