Skip to content
QuireKit
Classic docs
Alpha · evolving API
Classic developmentView Markdown ↗

Generate and read back official documents

A business system submits official-document JSON and gets an editable document laid out to GB/T 9704; after editing, the same data format reads back.

A business system, such as forms with a back-end service, only assembles one JSON value following the protocol on this page. @quirekit/official-document lays out the head, red rule, title, structure numbering, sign-off, imprint and page numbers to GB/T 9704-2012. The result edits in Classic like any document and exports to Word, PDF and OFD. Its elements carry GB/T 33476.2 official-document fields, so the edited document reads back as the same JSON for the business system.

@quirekit/official-document is a commercial component; obtain the distribution and license first, see Commercial use.

1. Flow

  1. The business system builds official-document JSON from the form (sections 2-8).
  2. The front end validates it, compiles it and loads the document into Classic.
  3. People edit and export online; when needed, read the content back as JSON (section 10) for the business system to store.
ts

composeOfficialDocument comes with the official-document extension: @quirekit/classic-ai installs it, and otherwise install createClassicOfficialDocumentPlugin() from @quirekit/official-document/classic. It registers the data's seals and pictures with the editor's media before replacing the document, and returns false without changing the document when the data is invalid. Without the command, register collectOfficialDocumentImages(data) with the media first, then load the result of compileOfficialDocument(data); read back with extractOfficialDocumentData(instance.getJSON(), { images }). Saving, versions and file conversion are covered in Save, open and convert files.

Word files can also be produced without a browser, by compiling in a Node service and exporting with the Classic DOCX service. Node has no browser font measurement, so whether the even-page imprint shares the last body page is judged with estimated glyph widths; check the file in Word before delivery.

2. Complete example

A notice with a copy number, classification and urgency:

json

3. Fields

Only kind, issuer.agency and body are required. Omit fields without content: an optional field written as null or an empty string is rejected.

FieldTypeMeaning and rules
version1Protocol version; may be omitted
kindkind valueSee section 5
format"letter"Letter format (section 6), usually for a letter (函); omitted uses the document format
issuer.agencytextIssuing agency's full or standard short name, used in the sign-off; the lead agency of a joint document
issuer.jointtext arrayCo-issuing agencies of a joint document, in order after the lead agency
issuer.marktextAgency mark; defaults to agency + 文件 (+ 令 for an order, + 会议纪要 for minutes); \n breaks lines
copyNumberdigit stringCopy number, usually six digits such as 000123
secrecy.level秘密, 机密, 绝密Classification level
secrecy.termtextPeriod, declassification time or condition such as 1年; set as 机密★1年
urgency特急, 加急Urgency; telegrams also use 特提 and 平急
documentNumbertextDocument number with the year in hexagonal brackets, such as 示政发〔2026〕12号; an order number 第1号 or minutes issue 第1期
signerstext arraySigners of an upward document (request, report), one per issuing agency in agency order
titletextTitle; a long title breaks before 关于 automatically, or use \n; not used for orders and minutes
adoptiontextAdoption statement such as (2026年10月17日……会议通过), for resolutions and similar kinds
recipientstext arrayMain recipients, one agency per item, without 、 or :; not used for announcements, public notices and communiqués
bodyblock arraySee section 4
attachmentstext arrayAttachment names without trailing punctuation; numbered when more than one
signaturesign-offSee section 7
dateYYYY-MM-DDDate of the document, written as 2026年12月20日; omitted leaves 年 月 日 to fill in
notetextNote, without brackets
attendeeslist arrayMinutes attendance: { "label": "出席", "names": ["张某", "李某"] }, labels 出席, 请假, 列席
imprint.cctext arrayCopied agencies
imprint.officetextPrinting and distributing office, usually the issuer's general office; omitted in the letter format
imprint.dateYYYY-MM-DDPrinting date, omitted in the letter format; omit the whole imprint when the document has none

4. Body

body lists blocks in reading order. There are four kinds:

BlockFormLayout
Paragraph{ "type": "paragraph", "text": "…" }FangSong 16 pt with a two-character indent; do not start with spaces
Heading{ "type": "heading", "level": 1, "title": "…" }Levels 1-4 are numbered 一、, (一), 1. and (1); lower levels restart under each upper heading
Table{ "type": "table", "title": "…", "header": [[…]], "rows": [[…]] }Full body width with 0.5 pt single rules; title centred above (SimHei), header rows in SimHei, centred and repeated on every page; rows never split
Image{ "type": "image", "src": "data:image/png;base64,…", "caption": "…" }On its own line, centred, caption centred below
  • Do not write ordinals in titles; they are generated. The first heading must be level 1.
  • When body text continues on the heading's line, end title with 。 and put the text in text: { "type": "heading", "level": 2, "title": "严格值班值守。", "text": "各单位要安排好节日期间值班。" }.

Tables:

json
FieldMeaning
titleTable title, optional
headerHeader rows, optional; repeated on every page the table spans
rowsBody rows; every row, header rows included, has one string per column, without merged cells; \n in a cell starts a new paragraph
columnsOne entry per column: width is relative (equal by default), align is start (default), center or end
fontSizeTable text size: 16 (三号, default), 14 (四号) or 12 (小四)

Images: src is a PNG or JPEG data URL; width is in mm, by default the image's size at 96 dpi and at most the 156 mm body width, the height following the image; caption is optional. Images live in the editor's media like seals, see section 7. Horizontal tables (GB/T 9704 §8) are not supported yet.

5. Document kinds

kindKindNotes
resolution决议Usually unsigned, often with adoption
decision决定
order命令(令)Order head without title or recipients; documentNumber is the order number; signed by a leader
communique公报Usually without recipients or sign-off
announcement公告Usually without recipients
public-notice通告Usually without recipients
opinion意见
notice通知
circular通报
report报告Upward document; write signers
request请示Upward document; write signers
reply批复
proposal议案Signed by a leader
letter函
minutes纪要Minutes head without title or recipients; write attendees; usually unsigned

Orders and minutes cannot be joint documents; orders take no copy number, classification or urgency.

6. Letter format

With "format": "letter" the document follows GB/T 9704 10.1: the agency mark is the agency name without 文件, its top edge 30 mm below the page top; 4 mm below it a red double rule (thick over thin), and 20 mm above the page bottom another (thin over thick), both 170 mm long. Copy number, classification and urgency sit flush left and the document number flush right, with the title two lines below; the first page shows no page number; the imprint lists copied agencies only (imprint with cc) at the bottom of the last page. A joint letter uses the lead agency's mark, while the sign-off still lists every agency. The letter format takes no signers and is not available for orders or minutes.

json

7. Sign-off and joint documents

Without signature the document is signed by the agency (the unsealed layout). The other forms:

  • Sealed: { "type": "sealed" }, see "Seals and signature stamps" below
  • Signers' signature stamps: { "type": "stamp", "stamps": [...] }, see below
  • Leader sign-off (orders, proposals): { "type": "leader", "position": "市长", "name": "张某" }
  • No sign-off (resolutions, communiqués, minutes): { "type": "none" }

For a joint document, list the co-issuing agencies in issuer.joint: the agency names stack in the head with 文件 centred on their right, and the sign-off lists the lead agency first and the others below. Signers of an upward document sit two per line in agency order:

json

Seals and signature stamps

Laid out to GB/T 9704-2012 §7.3.5.1 and §7.3.5.3, for either setup:

  • With an e-signature system: give no images. The document lays out the sign-off and reserves the seal positions (invisible, moving with pagination); after export the e-signature system seals at the coordinates locateOfficialSeals reports.
  • Without one: give the seal images (PNG data URLs with transparency) in the data; they are placed in the document and included in Word, PDF and OFD exports.
json
FieldMeaning
sealsOne per issuing agency in agency order; omit to reserve every position. The count must equal the number of agencies
diameterSeal diameter in mm, 20–60, default 42

A sealed date stands four characters from the right, the agency is centred on it, and the seal is concentric with them, its top half a line below the body. A joint document sets its seals in a row in agency order, the last one on the date and the others to its left, 2 mm apart; when the agency names are too long to sit under their seals side by side, the seals stack one per row.

json
FieldMeaning
stampsOne per issuing agency in agency order: position is the signer's full title, image the stamp, omitted to reserve the position
heightStamp height in mm, 8–30, default 15; the width follows the image, or 2.5 × the height without one

The stamp stands two blank lines below the body and four characters from the right, the title two characters to its left and centred on it, and the date one blank line below the stamp, four characters from the right; a joint document has one agency per row.

In the browser, @quirekit/official-document/classic reports the positions:

ts

Images are kept in the editor's media rather than in the document JSON; composeOfficialDocument registers them before replacing the document.

8. Back-end validation

schema/official-document.schema.json in the distribution (JSON Schema 2020-12) describes the field structure, so a back end can validate first with a JSON Schema 2020-12 validator in its own language. validateOfficialDocumentData also checks the rules a schema cannot state:

  • every kind except orders and minutes needs a title;
  • dates must be real calendar days;
  • the first heading is level 1;
  • orders take no copy number, classification or urgency, and orders and minutes cannot be joint documents;
  • there are no more signers than issuing agencies, and attendees is for minutes only;
  • the letter format is not for orders or minutes and takes no signers; outside it, an imprint needs office and date;
  • there are as many seals (seals) or signature stamps (stamps) as issuing agencies;
  • every table row, header rows included, has one cell per column.

A failed validation returns every problem with a JSON Pointer path and a Chinese message, ready to show next to the form field:

json

9. Integration notes

The interface is language-neutral: the business system builds JSON that follows this protocol in any language and hands it to the front end over HTTP. When assembling the data:

  • field names use the protocol's camelCase, such as documentNumber and fontSize;
  • leave unset fields out rather than writing null or empty strings (a paragraph's text must not be empty);
  • write dates as 2026-12-20;
  • headings carry no ordinals such as 一、 or (一); the program numbers them;
  • every table row, header rows included, has one cell per column, and there are as many seals or signature stamps as issuing agencies;
  • seals, signature stamps and body pictures are data URLs: PNG with transparency for seals and stamps, PNG or JPEG for pictures.

A back end can first validate the structure with schema/official-document.schema.json from the distribution (section 8). Read-back JSON has the same structure, so the types used to generate it also deserialize it.

10. Read back

extractOfficialDocumentData(document, options?) reads editor content (instance.getJSON()) or an imported DOCX and returns { ok: true, data, warnings } or { ok: false, issues }:

  • Only text inside the official-document fields is read; paragraphs started outside them are not, while paragraphs added inside the body are.
  • Pending revisions read as if all were accepted; the document's revisions are not changed.
  • Body tables and pictures read back as table and image blocks; content the protocol cannot hold, such as a table with merged cells, is skipped with its position in warnings, and an unreadable date stays empty with a warning. Column widths read back as the twips they resolved to, in the same proportions.
  • Joint agencies come from the sign-off; a mismatch with the names in the head produces a warning.
  • A document edited in Microsoft Word reads back after import (verified with Mac Word 16.109.2).
  • While editing online, Document elements on the View ribbon opens a right-side panel listing the document's elements by head, body and imprint, edited like a form; changes go into the matching fields and can be undone. The body and attachment note show a summary and can be located. Import @quirekit/official-document/styles.css for the panel's styles.
  • Seal and signature-stamp images live in the editor's media and read back only with { images: mediaResolver }; in the browser, readOfficialDocumentData(editor) from @quirekit/official-document/classic passes it. An unreadable image produces a warning and reads back as a reserved position.

Unedited data compiles back into the same document.

11. Current scope

Supported: the fifteen kinds above in the document and letter formats, copy number, classification and term, urgency, signers, joint documents, four heading levels, body tables and pictures, attachment notes, agency, sealed (reserved or with images), signature-stamp, leader and no sign-off, notes, minutes attendance, copied agencies and printing, odd/even page numbers, and Word/PDF/OFD export.

Not yet supported: horizontal tables and merged table cells. Whether WPS and other official-document systems recognize the fields is unverified; PDF and OFD exports contain the layout only, without the fields.

QuireKitQuireKit · Core, plugins and Classic docs