示例:发票
生成包含公司品牌、明细、合计与付款二维码的专业发票。
完整代码
ts
import { createDocx, defineStyles, qrcodePlugin } from 'docx-kit/node'
// 1. Styles
const styles = defineStyles({
companyName: {
fontSize: 22,
fontWeight: 'bold',
color: '#1a1a2e',
},
invoiceTitle: {
fontSize: 28,
fontWeight: 'bold',
color: '#2563eb',
textAlign: 'right',
},
sectionLabel: {
fontSize: 10,
fontWeight: 'bold',
color: '#666',
textTransform: 'uppercase' as any,
},
body: {
fontSize: 11,
lineHeight: 1.4,
fontFamily: 'Calibri',
},
tableHeader: {
fontWeight: 'bold',
backgroundColor: '#2563eb',
color: '#ffffff',
fontSize: 10,
},
tableCell: {
fontSize: 10,
verticalAlign: 'middle',
},
totalRow: {
fontWeight: 'bold',
fontSize: 12,
backgroundColor: '#f0f4ff',
},
footer: {
fontSize: 9,
color: '#999',
textAlign: 'center',
},
})
// 2. Invoice data
interface InvoiceLine {
description: string
quantity: number
rate: number
amount: number
}
const invoiceData = {
invoiceNumber: 'INV-2026-0042',
date: 'June 10, 2026',
dueDate: 'July 10, 2026',
billTo: {
name: 'Acme Corporation',
address: '123 Business Park Drive\nSan Francisco, CA 94105',
email: 'billing@acme.example',
},
from: {
name: 'Example Corp',
address: '456 Innovation Blvd\nAustin, TX 78701',
email: 'hello@example.com',
phone: '+1 (555) 123-4567',
},
}
const lineItems: InvoiceLine[] = [
{ description: 'Web Development — Phase 1 (Frontend)', quantity: 80, rate: 150, amount: 12000 },
{ description: 'Web Development — Phase 2 (Backend API)', quantity: 120, rate: 150, amount: 18000 },
{ description: 'UX/UI Design — Wireframes & Prototypes', quantity: 40, rate: 125, amount: 5000 },
{ description: 'DevOps Setup — CI/CD + Deployment Pipeline', quantity: 24, rate: 175, amount: 4200 },
{ description: 'Project Management — 10 weeks', quantity: 50, rate: 100, amount: 5000 },
]
const subtotal = lineItems.reduce((sum, item) => sum + item.amount, 0)
const tax = subtotal * 0.08
const total = subtotal + tax
// 3. Build
const doc = createDocx({
styles,
page: { size: 'A4', margin: '20mm 25mm' },
metadata: {
title: `Invoice ${invoiceData.invoiceNumber}`,
creator: 'Example Corp',
subject: 'Invoice',
},
})
doc
// === Header ===
.p('EXAMPLE CORP', { className: 'companyName' })
.p(invoiceData.from.address, {
style: { fontSize: 10, color: '#666' },
})
.p(`Email: ${invoiceData.from.email}`, {
style: { fontSize: 10, color: '#666' },
})
.p(`Phone: ${invoiceData.from.phone}`, {
style: { fontSize: 10, color: '#666' },
})
// Spacer
.p(' ', { style: { fontSize: 4 } })
.p('INVOICE', { className: 'invoiceTitle' })
// Divider line
.p('─'.repeat(80), { style: { fontSize: 6, color: '#ddd' } })
// === Meta ===
.p(`Invoice #: ${invoiceData.invoiceNumber}`, {
style: { textAlign: 'right', fontSize: 11 },
})
.p(`Date: ${invoiceData.date}`, {
style: { textAlign: 'right', fontSize: 11 },
})
.p(`Due Date: ${invoiceData.dueDate}`, {
style: { textAlign: 'right', fontSize: 11 },
})
// Spacer
.p(' ', { style: { fontSize: 4 } })
// === Bill To ===
.p('BILL TO', { className: 'sectionLabel' })
.p(invoiceData.billTo.name, {
style: { fontSize: 12, fontWeight: 'bold' },
})
.p(invoiceData.billTo.address, { className: 'body' })
.p(`Email: ${invoiceData.billTo.email}`, { className: 'body' })
// Spacer
.p(' ', { style: { fontSize: 4 } })
// === Line Items Table ===
.table<InvoiceLine>({
columns: [
{ key: 'description', title: 'Description', width: '40%' },
{ key: 'quantity', title: 'Qty', width: '12%', align: 'center' },
{
key: 'rate',
title: 'Rate',
width: '18%',
align: 'right',
render: (v) => `$${(v as number).toLocaleString()}`,
},
{
key: 'amount',
title: 'Amount',
width: '30%',
align: 'right',
render: (v) => `$${(v as number).toLocaleString()}`,
},
],
data: lineItems,
bordered: true,
headerCellStyle: {
fontWeight: 'bold',
backgroundColor: '#2563eb',
color: '#ffffff',
fontSize: 10,
},
cellStyle: {
fontSize: 10,
verticalAlign: 'middle',
},
})
// === Totals ===
.p(' ', { style: { fontSize: 2 } })
.p(`Subtotal: $${subtotal.toLocaleString()}`, {
style: { textAlign: 'right', fontSize: 11, marginRight: 5 },
})
.p(`Tax (8%): $${tax.toLocaleString()}`, {
style: { textAlign: 'right', fontSize: 11, marginRight: 5, color: '#666' },
})
.p('─'.repeat(40), {
style: {
textAlign: 'right',
fontSize: 6,
color: '#ddd',
marginLeft: 'auto',
marginRight: 5,
},
})
.p(`Total Due: $${total.toLocaleString()}`, {
style: {
textAlign: 'right',
fontSize: 14,
fontWeight: 'bold',
color: '#2563eb',
marginRight: 5,
},
})
.pageBreak()
// === Payment Info ===
.h2('Payment Information', {
style: { fontSize: 16, fontWeight: 'bold', color: '#1a1a2e' },
})
.p('Please include the invoice number with your payment.', {
style: { fontSize: 10, color: '#666' },
})
.p(' ', { style: { fontSize: 4 } })
// Payment methods table
.table({
columns: [
{ key: 'method', title: 'Payment Method' },
{ key: 'details', title: 'Details' },
],
data: [
{ method: 'Bank Transfer (ACH)', details: 'Bank: Chase | Account: ****1234 | Routing: 021000021' },
{ method: 'Wire Transfer', details: 'SWIFT: CHASUS33 | IBAN: US12CHAS1234567890' },
{ method: 'Check', details: 'Payable to "Example Corp" — Mail to 456 Innovation Blvd, Austin, TX 78701' },
],
bordered: true,
headerCellStyle: {
fontWeight: 'bold',
backgroundColor: '#f5f5f5',
fontSize: 10,
},
cellStyle: {
fontSize: 10,
verticalAlign: 'middle',
},
})
.p(' ', { style: { fontSize: 8 } })
// QR Code for payment link
.use(qrcodePlugin())
.p('Scan to pay:', {
style: { textAlign: 'center', fontSize: 10, marginBottom: 3 },
})
.plugin('qrcode', {
text: `https://pay.example.com/${invoiceData.invoiceNumber}`,
size: 120,
caption: 'Secure Payment Link',
})
// === Footer ===
.p(' ', { style: { fontSize: 6 } })
.p('─'.repeat(80), { style: { fontSize: 6, color: '#ddd' } })
.p('Thank you for your business!', { className: 'footer' })
.p(`Invoice ${invoiceData.invoiceNumber} • Generated on ${invoiceData.date}`, {
style: { fontSize: 8, color: '#ccc', textAlign: 'center' },
})
// 4. Export
.save(`invoice-${invoiceData.invoiceNumber}.docx`)本例展示的能力
| 功能 | 使用位置 |
|---|---|
| 丰富的文档布局 | 公司页头、收票人信息与合计区 |
| 带样式的表格(蓝色表头) | 明细表格 |
类型泛型 table<InvoiceLine>() | 类型安全的列键 |
自定义 render() 格式化货币 | 单价与金额列 |
pageBreak() | 发票 → 付款信息 |
带题注的 qrcodePlugin | 付款二维码 |
| 居中与右对齐文本 | 发票标题、合计与页脚 |
| ASCII 分隔线 | 章节分隔 |
| 用空段落留白 | 章节之间的视觉间距 |