Skip to content

Commit 99bdc6a

Browse files
committed
feat: add VAT electronic invoice sample template
1 parent 65cf418 commit 99bdc6a

2 files changed

Lines changed: 220 additions & 0 deletions

File tree

packages/samples/src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
supermarketFlexRowReceiptTemplate,
1212
supermarketReceiptTemplate,
1313
} from './templates/supermarket-receipt'
14+
import { vatElectronicInvoiceTemplate } from './templates/vat-electronic-invoice'
1415
import {
1516
verticalMixedTextDemoData,
1617
verticalMixedTextTemplate,
@@ -33,6 +34,7 @@ export {
3334
supermarketFlexRowReceiptTemplate,
3435
supermarketReceiptTemplate,
3536
} from './templates/supermarket-receipt'
37+
export { vatElectronicInvoiceTemplate } from './templates/vat-electronic-invoice'
3638
export {
3739
verticalMixedTextDataSource,
3840
verticalMixedTextDemoData,
@@ -215,6 +217,12 @@ export const sampleTemplates: SampleTemplateEntry[] = [
215217
category: 'business',
216218
schema: simpleInvoiceTemplate,
217219
},
220+
{
221+
id: 'vat-electronic-invoice',
222+
name: '增值税电子普通发票',
223+
category: 'business',
224+
schema: vatElectronicInvoiceTemplate,
225+
},
218226
{
219227
id: 'flow-invoice',
220228
name: '流式发票',
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import type { DocumentSchema, MaterialNode } from '@easyink/schema'
2+
import { SCHEMA_VERSION } from '@easyink/shared'
3+
4+
const TAX_RED = '#8b1e1e'
5+
const BLACK = '#111111'
6+
7+
type TextAlign = 'left' | 'center' | 'right'
8+
type VerticalAlign = 'top' | 'middle' | 'bottom'
9+
10+
interface TextOptions {
11+
fontSize?: number
12+
fontWeight?: string
13+
color?: string
14+
textAlign?: TextAlign
15+
verticalAlign?: VerticalAlign
16+
lineHeight?: number
17+
writingMode?: 'horizontal' | 'vertical'
18+
}
19+
20+
function textNode(
21+
id: string,
22+
x: number,
23+
y: number,
24+
width: number,
25+
height: number,
26+
content: string,
27+
options: TextOptions = {},
28+
): MaterialNode {
29+
return {
30+
id,
31+
type: 'text',
32+
x,
33+
y,
34+
width,
35+
height,
36+
props: {
37+
content,
38+
fontSize: options.fontSize ?? 4,
39+
fontWeight: options.fontWeight ?? 'normal',
40+
color: options.color ?? TAX_RED,
41+
textAlign: options.textAlign ?? 'center',
42+
verticalAlign: options.verticalAlign ?? 'middle',
43+
lineHeight: options.lineHeight ?? 1.35,
44+
writingMode: options.writingMode ?? 'horizontal',
45+
letterSpacing: 0,
46+
wrapMode: 'anywhere',
47+
overflow: 'hidden',
48+
},
49+
}
50+
}
51+
52+
function rectNode(
53+
id: string,
54+
x: number,
55+
y: number,
56+
width: number,
57+
height: number,
58+
borderColor: string,
59+
borderWidth = 0.25,
60+
): MaterialNode {
61+
return {
62+
id,
63+
type: 'rect',
64+
x,
65+
y,
66+
width,
67+
height,
68+
props: {
69+
fillColor: 'transparent',
70+
borderWidth,
71+
borderColor,
72+
borderType: 'solid',
73+
borderRadius: 0,
74+
},
75+
}
76+
}
77+
78+
function ruleNode(
79+
id: string,
80+
x: number,
81+
y: number,
82+
width: number,
83+
height: number,
84+
color = TAX_RED,
85+
): MaterialNode {
86+
return {
87+
id,
88+
type: 'rect',
89+
x,
90+
y,
91+
width,
92+
height,
93+
props: {
94+
fillColor: color,
95+
borderWidth: 0,
96+
borderColor: 'transparent',
97+
borderType: 'solid',
98+
borderRadius: 0,
99+
},
100+
}
101+
}
102+
103+
const invoiceElements: MaterialNode[] = [
104+
rectNode('vat_outer_frame', 8, 8, 281, 194, BLACK, 0.3),
105+
106+
rectNode('vat_qr_box', 17, 16, 27, 27, TAX_RED, 0.35),
107+
textNode('vat_qr_placeholder', 19, 24, 23, 12, '动态\n二维码', {
108+
fontSize: 4.1,
109+
lineHeight: 1.25,
110+
}),
111+
112+
textNode('vat_title', 94, 19, 108, 12, '电子发票(普通发票)', {
113+
fontSize: 8.9,
114+
fontWeight: 'bold',
115+
color: TAX_RED,
116+
}),
117+
ruleNode('vat_title_rule_1', 100, 34.6, 97, 0.35),
118+
ruleNode('vat_title_rule_2', 100, 36.2, 97, 0.35),
119+
120+
textNode('vat_number_label', 216, 21, 54, 7, '发票号码:', {
121+
fontSize: 4.2,
122+
textAlign: 'left',
123+
}),
124+
textNode('vat_date_label', 216, 34, 54, 7, '开票日期:', {
125+
fontSize: 4.2,
126+
textAlign: 'left',
127+
}),
128+
129+
rectNode('vat_main_frame', 15, 50, 267, 130, TAX_RED, 0.3),
130+
131+
ruleNode('vat_buyer_label_split', 23, 50, 0.3, 31),
132+
ruleNode('vat_party_split', 149, 50, 0.3, 31),
133+
ruleNode('vat_seller_label_split', 157, 50, 0.3, 31),
134+
ruleNode('vat_party_bottom', 15, 81, 267, 0.3),
135+
136+
textNode('vat_buyer_label', 15.5, 53, 7, 24, '购买方信息', {
137+
fontSize: 4.1,
138+
writingMode: 'vertical',
139+
}),
140+
textNode('vat_buyer_fields', 25, 58, 116, 14, '名称:\n统一社会信用代码/纳税人识别号:', {
141+
fontSize: 4.2,
142+
lineHeight: 1.55,
143+
textAlign: 'left',
144+
}),
145+
textNode('vat_seller_label', 149.5, 53, 7, 24, '销售方信息', {
146+
fontSize: 4.1,
147+
writingMode: 'vertical',
148+
}),
149+
textNode('vat_seller_fields', 159, 58, 116, 14, '名称:\n统一社会信用代码/纳税人识别号:', {
150+
fontSize: 4.2,
151+
lineHeight: 1.55,
152+
textAlign: 'left',
153+
}),
154+
155+
textNode('vat_item_name_header', 34, 82, 52, 9, '项目名称', { fontSize: 4.2 }),
156+
textNode('vat_spec_header', 91, 82, 32, 9, '规格型号', { fontSize: 4.2 }),
157+
textNode('vat_unit_header', 122, 82, 18, 9, '单位', { fontSize: 4.2 }),
158+
textNode('vat_qty_header', 142, 82, 23, 9, '数量', { fontSize: 4.2 }),
159+
textNode('vat_price_header', 168, 82, 25, 9, '单价', { fontSize: 4.2 }),
160+
textNode('vat_amount_header', 204, 82, 25, 9, '金额', { fontSize: 4.2 }),
161+
textNode('vat_tax_rate_header', 235, 82, 31, 9, '税率/征收率', { fontSize: 4.2 }),
162+
textNode('vat_tax_amount_header', 264, 82, 16, 9, '税额', { fontSize: 4.2 }),
163+
164+
ruleNode('vat_items_bottom', 15, 143.5, 267, 0.3),
165+
textNode('vat_total_label', 35, 135.8, 38, 8, '合 计', { fontSize: 4.2 }),
166+
167+
ruleNode('vat_total_amount_bottom', 15, 154.5, 267, 0.3),
168+
ruleNode('vat_total_amount_label_split', 84, 143.5, 0.3, 11),
169+
textNode('vat_amount_words_label', 34, 145.4, 48, 7, '价税合计(大写)', {
170+
fontSize: 4.1,
171+
}),
172+
textNode('vat_amount_number_label', 201, 145.4, 60, 7, '(小写)', {
173+
fontSize: 4.1,
174+
}),
175+
176+
ruleNode('vat_remark_top', 15, 165.5, 267, 0.3),
177+
ruleNode('vat_remark_label_split', 23, 165.5, 0.3, 14.5),
178+
textNode('vat_remark_label', 15.5, 168, 7, 9.5, '备注', {
179+
fontSize: 4.1,
180+
writingMode: 'vertical',
181+
}),
182+
183+
textNode('vat_issuer_label', 36, 187, 38, 7, '开票人:', {
184+
fontSize: 4.2,
185+
textAlign: 'left',
186+
}),
187+
]
188+
189+
/**
190+
* 增值税电子普通发票空白模板。
191+
*/
192+
export const vatElectronicInvoiceTemplate: DocumentSchema = {
193+
version: SCHEMA_VERSION,
194+
unit: 'mm',
195+
meta: {
196+
name: '增值税电子普通发票',
197+
description: 'A4 横向增值税发票(电子/普通发票)空白版式。',
198+
},
199+
page: {
200+
mode: 'fixed',
201+
width: 297,
202+
height: 210,
203+
background: {
204+
color: '#ffffff',
205+
},
206+
print: {
207+
orientation: 'landscape',
208+
},
209+
},
210+
guides: { x: [], y: [] },
211+
elements: invoiceElements,
212+
}

0 commit comments

Comments
 (0)