x-print-designer 0.4.13 → 0.4.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +377 -66
- package/dist/{JsBarcode-Ie7CY3Wt.js → JsBarcode-DSibbGlC.js} +1 -1
- package/dist/{JsBarcode-5g1FBqni.js → JsBarcode-DnTB2TYK.js} +1 -1
- package/dist/{browser-VQbZ-HlB.js → browser-CGxtUZAc.js} +1 -1
- package/dist/{browser-CdoI5PCM.js → browser-DG3U5_to.js} +1 -1
- package/dist/{dom-to-image-more.min-CyxmydGS.js → dom-to-image-more.min-skzBroxH.js} +1 -1
- package/dist/{index-sx0m_xBC.js → index-B-wpcX07.js} +27607 -24127
- package/dist/{index-C6B5Mzsh.js → index-tzwKDb5_.js} +1 -1
- package/dist/{index.es-CJVAF11T.js → index.es-BVS6FbmC.js} +1 -1
- package/dist/{jspdf.es.min-BZ5J-fwr.js → jspdf.es.min-64TFryHQ.js} +1 -1
- package/dist/{jszip.min-DQML3mxT.js → jszip.min-C-iB5bAt.js} +1 -1
- package/dist/print-designer.css +1 -1
- package/dist/print-designer.es.js +3 -2
- package/dist/print-designer.umd.js +56 -51
- package/dist/{vue-D5fIULVq.js → vue-DvM51Rdu.js} +11007 -8442
- package/dist/vue.css +1 -1
- package/dist/vue.d.ts +1 -0
- package/dist/vue.es.js +3 -2
- package/dist/web-component.d.ts +96 -1
- package/docs/designs/onboarding-and-host-integration.md +144 -0
- package/docs/en/guide/web-components-guide.md +154 -1
- package/docs/implementation-plan.md +145 -0
- package/docs/plans/2026-08-11-host-integration-workflow.md +113 -0
- package/package.json +4 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# Web Components API Guide
|
|
2
2
|
|
|
3
3
|
## Contents
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
- [Vue Integration](#vue-integration)
|
|
7
7
|
- [React Integration](#react-integration)
|
|
8
8
|
- [Native HTML Integration](#native-html-integration)
|
|
9
|
+
- [Unified Initialization (Recommended)](#unified-initialization-recommended)
|
|
9
10
|
- [API Index](#api-index)
|
|
10
11
|
- [Instance Methods and Parameters](#instance-methods-and-parameters)
|
|
11
12
|
- [Initialization (Recommended)](#initialization-recommended)
|
|
@@ -57,6 +58,8 @@
|
|
|
57
58
|
- [Scenario 2: Designer Page (Creating or Editing Templates)](#scenario-2-designer-page-creating-or-editing-templates)
|
|
58
59
|
- [Scenario 3: Business Page Print / Export (Actual Business Operation)](#scenario-3-business-page-print--export-actual-business-operation)
|
|
59
60
|
- [Scenario 4: Headless Mode Silent Printing](#scenario-4-headless-mode-silent-printing)
|
|
61
|
+
- [Data Channels & Priority](#data-channels--priority)
|
|
62
|
+
- [Scenario Template Library](#scenario-template-library)
|
|
60
63
|
- [Template and Custom Element JSON Examples](#template-and-custom-element-json-examples)
|
|
61
64
|
- [Notes](#notes)
|
|
62
65
|
|
|
@@ -64,6 +67,10 @@
|
|
|
64
67
|
|
|
65
68
|
| Method | Description |
|
|
66
69
|
| --- | --- |
|
|
70
|
+
| `init(config)` | Unified initialization: one config object for mode/data/onSave/crud/branding/theme etc. Auto-queues before `ready`, applies right after |
|
|
71
|
+
| `setData(data, opts)` | Unified data injection entry with channel (`variables`/`testData`/`sampleData`/`availableVariables`) |
|
|
72
|
+
| `setTemplateLibrary(items, opts)` | Replace or merge the built-in scenario template library (host-injected templates) |
|
|
73
|
+
| `loadExampleTemplate(id)` | Load a built-in example template (copied as an editable template) |
|
|
67
74
|
| `print(request)` | Execute print |
|
|
68
75
|
| `export(request)` | Export PDF/Images/HTML |
|
|
69
76
|
| `getPreviewHtml()` | Generate and get HTML preview code |
|
|
@@ -229,6 +236,90 @@ Example (no framework):
|
|
|
229
236
|
</html>
|
|
230
237
|
```
|
|
231
238
|
|
|
239
|
+
## Unified Initialization (Recommended)
|
|
240
|
+
|
|
241
|
+
No dedicated `init` wait is needed. Use the **method channel** (`el.init(config)`) or the **attribute channel** (`config="..."` attribute) — both auto-queue before `ready` and apply right after, so you never have to listen for `ready` manually.
|
|
242
|
+
|
|
243
|
+
```html
|
|
244
|
+
<!-- Attribute channel: declarative, equivalent to calling init(config) -->
|
|
245
|
+
<print-designer
|
|
246
|
+
config='{"mode":"template","testData":{"id":1,"title":"Demo"},"uiMode":"beginner"}'
|
|
247
|
+
></print-designer>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
// Method channel
|
|
252
|
+
const el = document.querySelector('print-designer') as any
|
|
253
|
+
el.init({
|
|
254
|
+
mode: 'template',
|
|
255
|
+
testData: { id: 1, title: 'Demo Report', items: [{ name: 'A', price: 100 }] },
|
|
256
|
+
onSave: async (payload) => { await fetch('/api/templates/save', { method: 'POST', body: JSON.stringify(payload) }) },
|
|
257
|
+
crud: { mode: 'remote', endpoints: { templates: { list: '/print/templates', get: '/print/templates/{id}', upsert: '/print/templates', delete: '/print/templates/{id}' } } },
|
|
258
|
+
branding: { title: 'Enterprise Print Center', showTitle: true },
|
|
259
|
+
theme: 'light'
|
|
260
|
+
})
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Priority rule:** setters called explicitly (e.g. `el.setTheme('dark')`) take precedence over matching `init` fields — no double-write conflicts.
|
|
264
|
+
|
|
265
|
+
### `DesignerInitConfig` fields
|
|
266
|
+
|
|
267
|
+
| Field | Type | Description |
|
|
268
|
+
| --- | --- | --- |
|
|
269
|
+
| `mode` | `'template' \| 'report'` | Work mode |
|
|
270
|
+
| `viewMode` | `'edit' \| 'preview'` | View mode |
|
|
271
|
+
| `uiMode` | `'beginner' \| 'expert' \| null` | UI mode (simple/full) |
|
|
272
|
+
| `language` | `string` | `'zh'` / `'en'` |
|
|
273
|
+
| `headless` | `boolean` | Headless mode |
|
|
274
|
+
| `data` | `Record<string, any>` | Data (default channel of `setData`) |
|
|
275
|
+
| `testData` | `Record<string, any>` | Test/preview data |
|
|
276
|
+
| `variables` | `Record<string, any>` | Runtime variables (override testData when printing) |
|
|
277
|
+
| `onSave` | `(payload) => void \| Promise<void> \| null` | Save callback |
|
|
278
|
+
| `autoSave` | `{ enabled, intervalMs? }` | Auto-save |
|
|
279
|
+
| `fieldDictionary` | `DesignerFieldDictionary \| null` | Field dictionary (CN labels in variable panel) |
|
|
280
|
+
| `textPolishHandler` | `(text) => Promise<string> \| null` | Host-provided text polish handler |
|
|
281
|
+
| `textPolishConfig` | `TextPolishConfig \| null` | Built-in DeepSeek polish config |
|
|
282
|
+
| `branding` | `{ title?, logoUrl?, showTitle?, showLogo? }` | Branding |
|
|
283
|
+
| `theme` | `string` | `'light'` / `'dark'` / `'system'` |
|
|
284
|
+
| `printDefaults` | `DesignerPrintDefaults` | Default print/export options & connection settings |
|
|
285
|
+
| `previewMode` | `DesignerPreviewModeOptions` | Standalone preview mode |
|
|
286
|
+
| `crud` | `{ mode?, endpoints?, config? }` | Remote CRUD config |
|
|
287
|
+
|
|
288
|
+
### Self-check `checklist` event
|
|
289
|
+
|
|
290
|
+
Emitted automatically on `ready`. `detail: { checks: [{ name, passed, hint? }...], allPassed }`. Items include `ready`, `dataChannel`, `printApi`, `exportApi`, `onSaveBound`, `monacoLoader`. Failed items also produce a `console.warn` (`[PrintDesigner] ...`) so missing setup (e.g. no `onSave`) is easy to spot.
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
el.addEventListener('checklist', (e) => {
|
|
294
|
+
console.log(e.detail.checks, 'allPassed:', e.detail.allPassed)
|
|
295
|
+
})
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Vue host: `XPrintDesigner`
|
|
299
|
+
|
|
300
|
+
Vue 3 hosts can import the adapter component from `x-print-designer/vue` (or the package root) — props map to config, events are forwarded, common methods are exposed via ref. No `ready` management needed.
|
|
301
|
+
|
|
302
|
+
```vue
|
|
303
|
+
<template>
|
|
304
|
+
<XPrintDesigner :config="config" @checklist="onChecklist" />
|
|
305
|
+
</template>
|
|
306
|
+
|
|
307
|
+
<script setup lang="ts">
|
|
308
|
+
import { ref } from 'vue'
|
|
309
|
+
import { XPrintDesigner } from 'x-print-designer'
|
|
310
|
+
import 'x-print-designer/style.css'
|
|
311
|
+
|
|
312
|
+
const config = ref({
|
|
313
|
+
mode: 'template',
|
|
314
|
+
testData: { id: 1, title: 'Demo' },
|
|
315
|
+
onSave: async (payload) => { /* ... */ }
|
|
316
|
+
})
|
|
317
|
+
const onChecklist = (detail) => console.log(detail)
|
|
318
|
+
</script>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Props: `config` / `mode` / `uiMode` / `viewMode` / `headless` / `onSave` / `theme`. Events: `ready` / `print` / `printed` / `export` / `exported` / `error` / `checklist`. Exposed methods: `init` / `setData` / `print` / `export` / `setOnSave` / `setPreviewMode`.
|
|
322
|
+
|
|
232
323
|
## Instance Methods and Parameters
|
|
233
324
|
|
|
234
325
|
All methods are exposed on the `print-designer` element instance.
|
|
@@ -1695,6 +1786,68 @@ await el.export({
|
|
|
1695
1786
|
})
|
|
1696
1787
|
```
|
|
1697
1788
|
|
|
1789
|
+
## Data Channels & Priority
|
|
1790
|
+
|
|
1791
|
+
Multiple data injection channels exist. When **reading**, the following priority applies (same key → higher channel wins):
|
|
1792
|
+
|
|
1793
|
+
```
|
|
1794
|
+
runtimeVariables (setVariables / setData channel 'variables')
|
|
1795
|
+
> testData (setTestData / setSampleData / setData channel 'testData')
|
|
1796
|
+
> sampleData (host static sample data, fallback only)
|
|
1797
|
+
> ext.availableVariables (template field tree, for field hints only)
|
|
1798
|
+
```
|
|
1799
|
+
|
|
1800
|
+
For new integrations, use the single entry `setData(data, { channel, merge })`:
|
|
1801
|
+
|
|
1802
|
+
```js
|
|
1803
|
+
designer.setData(
|
|
1804
|
+
{ items: [{ name: 'Inspection Drone', qty: 2, total: 12800 }] },
|
|
1805
|
+
{ channel: 'variables', merge: true }
|
|
1806
|
+
)
|
|
1807
|
+
```
|
|
1808
|
+
|
|
1809
|
+
The four legacy methods (`setTestData` / `setSampleData` / `setVariables` / `setTemplateVariables`) remain as thin wrappers with unchanged behavior.
|
|
1810
|
+
|
|
1811
|
+
## Scenario Template Library
|
|
1812
|
+
|
|
1813
|
+
The template dropdown and empty state group built-in examples by **business scenario** and support search. Built-in scenarios target drone operations:
|
|
1814
|
+
|
|
1815
|
+
| Scenario key | Name | Examples |
|
|
1816
|
+
| --- | --- | --- |
|
|
1817
|
+
| `device-run` | Device Operations | Device card, flight task record, device status, battery, range stats |
|
|
1818
|
+
| `inspection` | Inspection Records | Inspection report/task/defect records, flight logs |
|
|
1819
|
+
| `event-feedback` | Event Feedback | Alert summary, event report, abnormal feedback, resolution form |
|
|
1820
|
+
| `other` | Other | Generic examples (delivery note, etc.) |
|
|
1821
|
+
|
|
1822
|
+
### Inject a custom library `setTemplateLibrary`
|
|
1823
|
+
|
|
1824
|
+
`mode: 'replace'` (default) replaces the whole built-in library; `mode: 'merge'` overwrites by `id` and appends new ids. The dropdown/empty state refresh reactively. Invalid items (missing `id`/`name`, or invalid `data`) are dropped.
|
|
1825
|
+
|
|
1826
|
+
```ts
|
|
1827
|
+
el.setTemplateLibrary([
|
|
1828
|
+
{
|
|
1829
|
+
id: 'biz-device-card',
|
|
1830
|
+
name: 'Device Card (custom)',
|
|
1831
|
+
description: 'For device archiving print',
|
|
1832
|
+
category: 'device-run', // reuse a built-in key or pass any custom string
|
|
1833
|
+
data: { pages: [/* ... */], canvasSize: { width: 794, height: 1123 } }
|
|
1834
|
+
}
|
|
1835
|
+
], { mode: 'merge' })
|
|
1836
|
+
```
|
|
1837
|
+
|
|
1838
|
+
```ts
|
|
1839
|
+
// Load a built-in example by id (copied as an editable template; loads directly if the same name exists)
|
|
1840
|
+
await el.loadExampleTemplate('example-device-status')
|
|
1841
|
+
```
|
|
1842
|
+
|
|
1843
|
+
### Data-driven template wizard
|
|
1844
|
+
|
|
1845
|
+
In the template dropdown, "Generate Template from Data" lets users paste sample JSON. The designer infers scalar fields (text/number/date) and array fields (object arrays → tables), generates a skeleton layout ("title + one label row per field + data table", table auto-bound and rendering rows), and loads it into the canvas for fine-tuning. This is **skeleton generation** — no pixel-level auto layout is promised.
|
|
1846
|
+
|
|
1847
|
+
### Group / Ungroup
|
|
1848
|
+
|
|
1849
|
+
Select multiple elements (Ctrl/Cmd + click) and click the **Group** toolbar button to wrap them into a `group` element — moved, resized (children scale proportionally), copied and deleted as a whole. Ungroup via the properties panel to restore members as independent elements with absolute coordinates. At least 2 elements are required; locked elements cannot be grouped.
|
|
1850
|
+
|
|
1698
1851
|
## Template and Custom Element JSON Examples
|
|
1699
1852
|
|
|
1700
1853
|
**Template Data**
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# x-print-designer 插件侧改进实施方案
|
|
2
|
+
|
|
3
|
+
> 状态:实施中(按 W 项勾选推进)
|
|
4
|
+
> 目标:降低新用户上手门槛,收敛宿主胶水复杂度,补齐文档与类型。
|
|
5
|
+
|
|
6
|
+
## 总体原则
|
|
7
|
+
|
|
8
|
+
1. **默认不破坏现有 API**:所有新增能力走"渐进增强",存量宿主零改动可继续运行。
|
|
9
|
+
2. **新手优先,但可升级**:新手模式是可切换的 UI 状态(localStorage 持久化),不是删除高级功能。
|
|
10
|
+
3. **数据统一、机制内聚**:数据通道与循环页折叠收进插件内部,宿主无需感知。
|
|
11
|
+
4. **文档与类型同步交付**:每个功能必须同时补 i18n 词条 + 类型 + README,不留债。
|
|
12
|
+
|
|
13
|
+
## 里程碑
|
|
14
|
+
|
|
15
|
+
- **M1(P0)**:新手模式 + 示例模板 —— 解决"打开就懵"
|
|
16
|
+
- **M2(P1)**:首次引导 + 数据通道统一
|
|
17
|
+
- **M3(P2)**:内部机制自动化 + 文档类型补齐
|
|
18
|
+
|
|
19
|
+
## 实施顺序与依赖
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
M1.W1 侧边栏分层 ──┐
|
|
23
|
+
M1.W3 设置+持久化 ──┼──> M1.W2 属性面板分层 ──> M1 验收
|
|
24
|
+
M1.W4 示例模板 ────┴──> M1.W5 空态引导 ────────┘
|
|
25
|
+
│
|
|
26
|
+
M2.W7 Onboarding ──> M2.W8 变量可视化 ──> M2.W9 数据通道 ──> M2 验收
|
|
27
|
+
│
|
|
28
|
+
M3.W10 自动折叠 ──> M3.W11 文档类型 ──> M3 验收(宿主编译验证)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- W1/W3 先行(骨架),W2 依赖 W3 的 uiMode 状态。
|
|
32
|
+
- W4/W5 可并行;W5 是 W7 的依赖(Step1 复用示例入口)。
|
|
33
|
+
- W9(数据通道)最后做,触及渲染取值链,需专项回归。
|
|
34
|
+
- 每项完成即跑 `pnpm build:wc` + demo 页手测;M1/M2 结束后各做一次宿主编译冒烟。
|
|
35
|
+
|
|
36
|
+
## W 项清单
|
|
37
|
+
|
|
38
|
+
### 状态图例
|
|
39
|
+
|
|
40
|
+
- [ ] 待开始
|
|
41
|
+
- [x] 已完成
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### W1 ✅ 精简侧边栏:核心/高级元素分层
|
|
46
|
+
|
|
47
|
+
**目标**:默认只展示 6~8 个高频元素,其余折叠。
|
|
48
|
+
|
|
49
|
+
- **文件**:`src/components/layout/Sidebar.vue`、`src/stores/designer.ts`、`src/locales/zh.ts`、`src/locales/en.ts`
|
|
50
|
+
- **改动**:
|
|
51
|
+
- `StandardElementItem` 增加 `advanced?: boolean`。
|
|
52
|
+
- 元素打标:核心 8 个(文本、文档标题、图片、页码、表格、自定义表格、条形码、二维码);其余高级。
|
|
53
|
+
- `store.uiMode === 'beginner'` 时用 computed `visibleCategories` 过滤,组间插入"更多元素"折叠区。
|
|
54
|
+
- **风险**:无破坏性,仅展示层过滤。
|
|
55
|
+
- **验收**:新手模式下侧边栏只显示核心组 + 折叠入口;展开后可全部可达;expert 模式与原一致。
|
|
56
|
+
- **状态**:已完成(2026-08-10)。
|
|
57
|
+
|
|
58
|
+
### W2 ✅ 属性面板:常用/高级分层
|
|
59
|
+
|
|
60
|
+
**目标**:选中元素后默认只看到 3~5 个高频属性。
|
|
61
|
+
|
|
62
|
+
- **文件**:`src/components/elements/{LongTextElement,TableElement,CustomTableElement,ImageElement}.vue`、`src/components/layout/PropertiesPanel.vue`、`src/types/index.ts`、`src/locales/*`
|
|
63
|
+
- **改动**:`PropertySection`/`PropertyField` 增加 `advanced?: boolean`;核心元素 schema 打标(表格的脚本/条件格式/页眉页脚样式、文本的字体族/对齐/边框等);beginner 模式下整组过滤高级分组,组内高级字段折叠到"高级设置"。
|
|
64
|
+
- **依赖**:W3(uiMode 状态)。
|
|
65
|
+
- **风险**:schema 打标工作量大(19 个元素),纯增量可分批;当前先覆盖 4 个核心元素,其余后续补齐。
|
|
66
|
+
- **验收**:新手模式下每个元素属性面板 ≤5 个常规模块;expert 模式与原来 100% 一致。
|
|
67
|
+
- **状态**:已完成(2026-08-10 首批覆盖 text/table/customTable/image;2026-08-11 第二批补齐剩余元素:Text/Date/List/Signature/RichText/Rect/Circle/Line/PageNumber/Barcode/QRCode/Chart,LoopRender 无属性面板 schema 无需打标。浏览器 beginner/expert 双模式实测通过,typecheck/build:wc/17 符号验证通过)。
|
|
68
|
+
|
|
69
|
+
### W3 ✅ 新手模式开关:设置面板 + 持久化 + WC 方法
|
|
70
|
+
|
|
71
|
+
**目标**:三种入口可切换"简洁/完整"模式并持久化。
|
|
72
|
+
|
|
73
|
+
- **文件**:`src/stores/designer.ts`、`src/components/layout/settings/SettingsModal.vue`、`src/components/PrintDesigner.vue`、`src/web-component.ts`、`src/locales/zh.ts`、`src/locales/en.ts`
|
|
74
|
+
- **改动**:
|
|
75
|
+
- store 新增 `uiMode: 'beginner' | 'expert'` 状态 + `setUIMode(mode)` action(读写 `print-designer-ui-mode`)。
|
|
76
|
+
- `PrintDesigner` 新增可选 prop `ui-mode`。
|
|
77
|
+
- `web-component.ts` 暴露 `setUIMode(mode)`。
|
|
78
|
+
- SettingsModal 基础设置页加"界面模式"单选。
|
|
79
|
+
- **风险**:默认 beginner 影响老用户 → 首次进入提示条缓解(见 W7);当前默认逻辑为"已有本地模板则 expert,纯新用户 beginner"。
|
|
80
|
+
- **验收**:三种入口均能切换并持久化;刷新后保持。
|
|
81
|
+
- **状态**:已完成(2026-08-10)。
|
|
82
|
+
|
|
83
|
+
### W4 ✅ 内置示例模板库
|
|
84
|
+
|
|
85
|
+
**目标**:用户先加载带数据的成品模板,再修改。
|
|
86
|
+
|
|
87
|
+
- **文件(新增)**:`src/examples/templates.ts`、`src/examples/index.ts`;改 `src/stores/templates.ts`、`src/locales/{zh,en}.ts`
|
|
88
|
+
- **内容**:4 个自带完整 testData 的示例(送货单 example-order、巡检报告 example-inspection、告警汇总单 example-alert、设备标签 example-label),经 `createNewElement` 元素工厂生成合法默认值再覆盖关键字段;`isValidExampleData` 结构校验兜底;store 新增 `exampleTemplates` / `getExampleTemplate` getter(本地化 + 深拷贝只读)。
|
|
89
|
+
- **验收**:typecheck + vite build 通过(exit 0);示例数据在 getter 内运行时校验,非法结构自动过滤。
|
|
90
|
+
|
|
91
|
+
### W5 ✅ 首次加载引导:空状态 → 示例模板
|
|
92
|
+
|
|
93
|
+
- **文件**:`src/components/layout/toolbar/TemplateDropdown.vue`、`src/web-component.ts`(`loadExampleTemplate`)、locales
|
|
94
|
+
- **改动**:模板列表为空时显示"示例模板"卡片墙(标题 + 描述 + 加载按钮);点击后同名模板直接加载、否则复制为可编辑模板;新增 WC 方法 `loadExampleTemplate(id)` 供宿主调用。
|
|
95
|
+
- **依赖**:W4。
|
|
96
|
+
- **验收**:typecheck + vite build 通过(exit 0);空 localStorage 打开 dropdown 显示示例卡片,点击成功加载画布。
|
|
97
|
+
|
|
98
|
+
### W7 ✅ 首次引导(Onboarding)
|
|
99
|
+
|
|
100
|
+
- **文件(新增)**:`src/components/onboarding/OnboardingGuide.vue`、`src/composables/useOnboarding.ts`;改 `src/components/PrintDesigner.vue`、`src/components/layout/settings/SettingsModal.vue`
|
|
101
|
+
- **步骤**:选模板 → 拖元素 → 绑变量 → 预览打印(4 步,进度条 + 上一步/下一步/跳过/完成)。
|
|
102
|
+
- **验收**:全新 localStorage 打开 demo 自动出现引导;跳过/完成后写入标记不复发;设置页新增"重新播放引导"按钮(`onboarding.restart()`)。typecheck + vite build 通过。
|
|
103
|
+
|
|
104
|
+
### W8 ✅ 变量绑定可视化增强
|
|
105
|
+
|
|
106
|
+
- **文件**:`src/components/properties/PropertyFieldSelect.vue`、`src/components/properties/PropertyLongText.vue`、locales
|
|
107
|
+
- **改动**:长文本输入框输入 `@` 自动弹出字段选择;字段选择器与长文本 placeholder 改为教学文案(`{#字段}` 绑定提示)。
|
|
108
|
+
- **验收**:typecheck + vite build 通过。
|
|
109
|
+
|
|
110
|
+
### W9 ✅ 数据通道统一
|
|
111
|
+
|
|
112
|
+
- **文件(新增)**:`src/utils/dataChannels.ts`;改 `src/stores/designer.ts`、`src/web-component.ts`、`README.md`
|
|
113
|
+
- **改动**:单一解析优先级 `runtimeVariables > testData > sampleData > ext.availableVariables`;`resolveTableData` 改走统一通道;store 新增 `setData(data, { channel, merge })`;WC 新增 `setData`,旧 4 方法变薄包装;README 加优先级章节。
|
|
114
|
+
- **验收**:typecheck + vite build 通过(exit 0)。
|
|
115
|
+
- **依赖**:M1 完成后进行。
|
|
116
|
+
|
|
117
|
+
### W10 ✅ 循环页自动折叠(宿主不再调 `collapseLoopPages`)
|
|
118
|
+
|
|
119
|
+
- **文件**:`src/types/index.ts`、`src/stores/designer.ts`、`src/stores/templates.ts`、`src/web-component.ts`
|
|
120
|
+
- **改动**:`autoCollapseLoopPages` 默认 true(store state + `setAutoCollapseLoopPages`);保存流程 `buildSavePages` 自动折叠展开的循环页(先折叠再还原表格物化,原始模板参照缺失时跳过);WC 保留 `collapseLoopPages` 作为关闭自动折叠时的手动兜底(幂等)。
|
|
121
|
+
- **验收**:typecheck + vite build 通过(exit 0)。
|
|
122
|
+
|
|
123
|
+
### W11 ✅ 文档与类型补齐
|
|
124
|
+
|
|
125
|
+
- **文件**:`README.md`、`src/web-component.d.ts`、新增 `scripts/verify-dist-types.mjs`、`package.json`(build:wc 接入校验)
|
|
126
|
+
- **内容**:补 `setData`/`setUIMode`/`setDataLoading`/`setFieldDictionary`/`setCrudEndpoints`/`setTextPolishConfig`/`setTextPolishHandler`/`loadExampleTemplate`/`setAutoCollapseLoopPages` 等文档与类型;新增 `DesignerDataOptions`/`TextPolishConfig` 类型;verify-dist-types.mjs 校验 13 个关键符号已发布(接入 `build:wc`)。
|
|
127
|
+
- **验收**:typecheck + vite build 通过(exit 0);`copy-wc-types + verify-dist-types` 通过(13 符号齐全)。宿主侧删除 shim 的编译验证在宿主项目单独执行。
|
|
128
|
+
|
|
129
|
+
### W12 ✅ 元素组合 / 取消组合(Group 容器元素)
|
|
130
|
+
|
|
131
|
+
- **目标**:多选 ≥2 个元素后一键组合为组容器,整体移动/缩放/复制/删除,可取消组合恢复成员。
|
|
132
|
+
- **文件**:`src/types/index.ts`(`ElementType.GROUP` + `PrintElement.children`)、`src/stores/designer.ts`(`groupSelectedElements`/`ungroupSelectedElements` + `updateElement` 组缩放联动 + 粘贴时组内 children id 再生)、新增 `src/components/elements/GroupElement.vue`(递归渲染组内 children,复用元素组件映射,`pointer-events: none` 只读预览)、`src/components/canvas/Canvas.vue`、`src/components/layout/PropertiesPanel.vue`(选中组显示成员数与取消组合入口)、`src/components/layout/toolbar/AlignToolbar.vue`(多选工具栏组合按钮 + 选中组时取消组合按钮)、locales(`toolbar.group/ungroup`、`properties.section.group`、`properties.groupHint`、`properties.ungroup`、`toast.group*`)。
|
|
133
|
+
- **行为约定**:
|
|
134
|
+
- 组合后 children 坐标换算为组内相对坐标;取消组合时恢复为页面绝对坐标。
|
|
135
|
+
- 组缩放时 children 按 `newW/oldW`、`newH/oldH` 等比联动。
|
|
136
|
+
- 复制粘贴组时递归再生 children id,避免与源组冲突。
|
|
137
|
+
- 组合守卫:模板可编辑、选中 ≥2、不包含锁定元素。
|
|
138
|
+
- **验收**:typecheck + build:wc 通过(17 符号发布);浏览器实测:多选组合 → 组容器生成/选中/属性面板取消组合入口 → 整体缩放 children 按比例联动 → 复制粘贴 id 再生不冲突 → 取消组合坐标恢复 → 打印预览中 GROUP 正常渲染。
|
|
139
|
+
- **状态**:已完成(2026-08-11)。
|
|
140
|
+
|
|
141
|
+
## 不做的事(控制范围)
|
|
142
|
+
|
|
143
|
+
- 不改元素渲染核心(Table/CustomTable 分页逻辑)——属于独立 Bug 修复专项。
|
|
144
|
+
- 不新增元素类型、不拆分 designer store(独立工程债,另立专项)。
|
|
145
|
+
- 不在 minor 版本中删除任何已文档化 API。
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
intent: 实现 Phase 1 宿主接入线:init(config) 统一初始化 + config 属性声明式接入 + Vue 适配层 XPrintDesigner + 接入自检 checklist,使宿主 ≤10 行代码、零 ready 时序管理即可接入
|
|
3
|
+
success_criteria:
|
|
4
|
+
- 宿主最小接入代码 ≤ 10 行且无需手动监听 ready
|
|
5
|
+
- 存量宿主零改动可用(现有 setter/属性/事件全保留)
|
|
6
|
+
- typecheck + build:wc 通过;dist/web-component.d.ts 含 init( 与 DesignerInitConfig 符号
|
|
7
|
+
- demo 页 config 属性与 init() 均可工作;checklist 事件在缺前置条件时触发
|
|
8
|
+
risk_level: medium
|
|
9
|
+
auto_approve: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
- [x] **Step 1: 定义 DesignerInitConfig 类型**
|
|
15
|
+
action: 在 src/web-component.d.ts 新增并导出 DesignerInitConfig 接口,字段覆盖:mode('template'|'report')、viewMode('edit'|'preview')、uiMode('beginner'|'expert'|null)、language(string)、headless(boolean)、data(Record<string,any>)、testData(Record<string,any>)、variables(Record<string,any>)、onSave(函数)、autoSave({enabled,intervalMs?})、fieldDictionary、textPolishHandler、textPolishConfig、branding({title?,logoUrl?,showTitle?,showLogo?})、theme(string)、printDefaults、previewMode(DesignerPreviewModeOptions)、crud({mode?,endpoints?,config?})。同时导出这些用到的内联子类型(AutoSaveConfig、CrudInitConfig)以免 d.ts 缺声明。在 src/web-component.ts 顶部 import 该类型:import type { DesignerInitConfig } from './web-component.d'。
|
|
16
|
+
loop: false
|
|
17
|
+
verify:
|
|
18
|
+
- type: shell
|
|
19
|
+
command: node ./scripts/typecheck.mjs
|
|
20
|
+
- type: artifact
|
|
21
|
+
path: src/web-component.d.ts
|
|
22
|
+
assert:
|
|
23
|
+
kind: exists
|
|
24
|
+
|
|
25
|
+
- [x] **Step 2: 实现 init(config) 与待应用队列**
|
|
26
|
+
action: 在 src/web-component.ts 新增私有字段 `private pendingInit: DesignerInitConfig | null = null;` 与 `private _explicitlySet = new Set<string>();`。新增公开方法 `init(config: DesignerInitConfig)`:将 config 合并存入 pendingInit(浅合并),若 this.isReady 则立即调用 this._applyInit()。新增私有方法 `_applyInit()`:按顺序调用已有 setter——setMode/setViewMode/setUIMode/setLanguage/setBranding/setTheme/setPrintDefaults/setAutoSave/setOnSave/setFieldDictionary/setTextPolishHandler/setTextPolishConfig/setCrudMode/setData/setTestData/setPreviewMode,每个字段仅在其 key 不在 _explicitlySet 时应用;应用后置 pendingInit = null。在现有 setter(setMode、setViewMode、setUIMode、setLanguage、setBranding、setTheme、setPrintDefaults、setAutoSave、setOnSave、setFieldDictionary、setTextPolishHandler、setTextPolishConfig、setCrudMode、setData、setTestData、setPreviewMode)内,函数体首行加入 this._explicitlySet.add('<方法名>') 以标记显式调用优先级。在 connectedCallback 中 `this.isReady = true;` 之后、`setTimeout(() => this.dispatchEvent(new CustomEvent('ready')), 0)` 之前,调用 `this._applyInit();`。
|
|
27
|
+
loop: until `node ./scripts/typecheck.mjs` 通过且 init/_applyInit/pendingInit 均存在
|
|
28
|
+
max_iterations: 3
|
|
29
|
+
verify:
|
|
30
|
+
- type: shell
|
|
31
|
+
command: node ./scripts/typecheck.mjs
|
|
32
|
+
- type: artifact
|
|
33
|
+
path: src/web-component.ts
|
|
34
|
+
assert:
|
|
35
|
+
kind: exists
|
|
36
|
+
|
|
37
|
+
- [x] **Step 3: config 属性声明式接入**
|
|
38
|
+
action: 在 src/web-component.ts 的 observedAttributes 数组中加入 'config'(结果为 ['lang','headless','mode','view-mode','ui-mode','config'])。在 attributeChangedCallback 中新增分支:name === 'config' 且 newValue !== oldValue 时,先 try JSON.parse(newValue),解析失败则 dispatch new CustomEvent('error', { detail: { scope: 'config', error: new Error('Invalid config JSON') } }) 并 return(不影响默认 UI);解析成功则调用 this.init(parsed as DesignerInitConfig)。同步在 src/web-component.d.ts 的接口声明中补充 config 属性注释(jsdoc,不改类型结构)。
|
|
39
|
+
loop: until `node ./scripts/typecheck.mjs` 通过且 observedAttributes 含 'config'
|
|
40
|
+
max_iterations: 3
|
|
41
|
+
verify:
|
|
42
|
+
- type: shell
|
|
43
|
+
command: node ./scripts/typecheck.mjs
|
|
44
|
+
- type: artifact
|
|
45
|
+
path: src/web-component.ts
|
|
46
|
+
assert:
|
|
47
|
+
kind: exists
|
|
48
|
+
|
|
49
|
+
- [x] **Step 4: 接入自检 checklist 事件**
|
|
50
|
+
action: 在 src/web-component.ts 新增私有方法 `_runChecklist()`:生成检查项数组 checks(每项 { name: string, passed: boolean, hint?: string }),至少包含——ready: this.isReady;dataChannel: 存在 setData 方法;printApi: this.printApi 非 null;exportApi: typeof this.export === 'function';onSaveBound: this._onSave.value 非 null;monacoLoader: typeof loader !== 'undefined'。在 ready 派发前(Step 2 中 _applyInit 之后)调用 this._runChecklist();方法末尾若存在未通过项,console.warn('[PrintDesigner] 接入自检未全部通过:' + 未通过项 name 列表),并 dispatch new CustomEvent('checklist', { detail: { checks, allPassed } })。在 src/web-component.d.ts 中以注释形式补充 checklist 事件说明(jsdoc)。
|
|
51
|
+
loop: until `node ./scripts/typecheck.mjs` 通过且 web-component.ts 含 '_runChecklist' 与 "'checklist'"
|
|
52
|
+
max_iterations: 3
|
|
53
|
+
verify:
|
|
54
|
+
- type: shell
|
|
55
|
+
command: node ./scripts/typecheck.mjs
|
|
56
|
+
- type: artifact
|
|
57
|
+
path: src/web-component.ts
|
|
58
|
+
assert:
|
|
59
|
+
kind: exists
|
|
60
|
+
|
|
61
|
+
- [x] **Step 5: 构建并校验产物类型**
|
|
62
|
+
action: 运行 `node ./scripts/generate-tailwind-css.mjs`(若 src/style.generated.css 缺失或本步骤前未生成)后执行 `pnpm build:wc`。若构建失败,修正报错后重跑,直至成功。构建成功后确认 dist/web-component.d.ts 已包含 init( 与 DesignerInitConfig。
|
|
63
|
+
loop: until `pnpm build:wc` 退出码 0 且 dist/web-component.d.ts 含 'init(' 与 'DesignerInitConfig'
|
|
64
|
+
max_iterations: 3
|
|
65
|
+
verify:
|
|
66
|
+
- type: shell
|
|
67
|
+
command: pnpm build:wc
|
|
68
|
+
- type: artifact
|
|
69
|
+
path: dist/web-component.d.ts
|
|
70
|
+
assert:
|
|
71
|
+
kind: exists
|
|
72
|
+
|
|
73
|
+
- [x] **Step 6: verify-dist-types 增补新符号**
|
|
74
|
+
action: 在 scripts/verify-dist-types.mjs 的 requiredSymbols 数组追加两项(带注释分组):`'init('`(统一初始化,阶段1)与 `'DesignerInitConfig'`(统一初始化类型,阶段1)。不改动既有符号。保存后运行 `node ./scripts/verify-dist-types.mjs` 确认通过(在此之前需已存在 dist/web-component.d.ts,即 Step 5 产物)。
|
|
75
|
+
loop: until `node ./scripts/verify-dist-types.mjs` 输出「校验通过」且退出码 0
|
|
76
|
+
max_iterations: 3
|
|
77
|
+
verify:
|
|
78
|
+
- type: shell
|
|
79
|
+
command: node ./scripts/verify-dist-types.mjs
|
|
80
|
+
- type: artifact
|
|
81
|
+
path: scripts/verify-dist-types.mjs
|
|
82
|
+
assert:
|
|
83
|
+
kind: exists
|
|
84
|
+
|
|
85
|
+
- [x] **Step 7: 新建 Vue 适配层组件 XPrintDesigner**
|
|
86
|
+
action: 新建文件 src/components/XPrintDesigner.vue:template 内渲染 <print-designer> 自定义元素,通过 ref 持有元素实例;props 定义:config(Object, default null)、mode(String)、uiMode(String)、viewMode(String)、headless(Boolean)、onSave(Function)、theme(String);watch config 变化时调用 el.init(props.config)(若 el 已 isReady,否则等 ready 事件后调用),watch 其余 props 映射到对应 setter(mode→setMode、uiMode→setUIMode、viewMode→setViewMode、headless→_headless、theme→setTheme);组件 mounted 后监听元素 ready/print/printed/export/exported/error/checklist 事件并 emit 同名事件;defineExpose 暴露方法:init(config)、setData(payload, options)、print(request)、export(request)、setOnSave(handler)、setPreviewMode(options)。在 src/index.ts 末尾追加 `export { default as XPrintDesigner } from './components/XPrintDesigner.vue';`。
|
|
87
|
+
loop: until `node ./scripts/typecheck.mjs` 通过且 src/components/XPrintDesigner.vue 存在且 src/index.ts 含 'XPrintDesigner'
|
|
88
|
+
max_iterations: 3
|
|
89
|
+
verify:
|
|
90
|
+
- type: shell
|
|
91
|
+
command: node ./scripts/typecheck.mjs
|
|
92
|
+
- type: artifact
|
|
93
|
+
path: src/components/XPrintDesigner.vue
|
|
94
|
+
assert:
|
|
95
|
+
kind: exists
|
|
96
|
+
|
|
97
|
+
- [x] **Step 8: 更新 README 接入文档(5 分钟接入清单)**
|
|
98
|
+
action: 在 README.md 的 Web Component 接入章节之前新增「5 分钟接入(推荐)」小节:给出最小接入示例(① 引入脚本 ② <print-designer> 标签 ③ config 属性传 JSON 或 el.init(config) ④ 监听 checklist/ready),示例代码标注「≤10 行完成接入、无需手动监听 ready」。同时在新小节补充 checklist 事件说明(checks/allPassed、未通过时 console.warn 提示)。不改动既有 API 文档章节。
|
|
99
|
+
loop: false
|
|
100
|
+
verify:
|
|
101
|
+
- type: artifact
|
|
102
|
+
path: README.md
|
|
103
|
+
assert:
|
|
104
|
+
kind: exists
|
|
105
|
+
|
|
106
|
+
- [x] **Step 9: Demo 验证 config 属性与 init/checklist(人工评审)**
|
|
107
|
+
action: 启动 `npm run dev`(vite dev server,默认 http://localhost:5173),打开 demo 页面。人工验证三点:① 在页面控制台执行 `document.querySelector('print-designer').init({ uiMode: 'beginner', theme: 'light' })` 后界面模式与主题生效;② 给 <print-designer> 添加 config 属性(JSON 字符串)后刷新页面,配置生效;③ 移除 onSave 配置后刷新,控制台出现接入自检 warn 且页面收到 checklist 事件(allPassed: false)。验证完成后停止 dev server。
|
|
108
|
+
loop: false
|
|
109
|
+
verify:
|
|
110
|
+
- type: browser
|
|
111
|
+
url: http://localhost:5173
|
|
112
|
+
check: demo 页可打开;init 调用后 uiMode/theme 生效;config 属性生效;缺 onSave 时 checklist allPassed=false 且 console.warn 出现
|
|
113
|
+
gate: human
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x-print-designer",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.28",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/print-designer.umd.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dev": "vite",
|
|
35
35
|
"dev:lib": "node ./scripts/generate-tailwind-css.mjs && vite build --config vite.config.wc.dev.ts --watch",
|
|
36
36
|
"build": "node ./scripts/bump-version.mjs && node ./scripts/typecheck.mjs && vite build",
|
|
37
|
-
"build:wc": "node ./scripts/bump-version.mjs && node ./scripts/typecheck.mjs && node ./scripts/generate-tailwind-css.mjs && vite build --config vite.config.wc.ts && vite build --config vite.config.vue.ts && node ./scripts/copy-wc-types.mjs",
|
|
37
|
+
"build:wc": "node ./scripts/bump-version.mjs && node ./scripts/typecheck.mjs && node ./scripts/generate-tailwind-css.mjs && vite build --config vite.config.wc.ts && vite build --config vite.config.vue.ts && node ./scripts/copy-wc-types.mjs && node ./scripts/verify-dist-types.mjs",
|
|
38
38
|
"link": "npm link",
|
|
39
39
|
"build:watch": "vite build --watch",
|
|
40
40
|
"unlink": "npm unlink -g",
|
|
@@ -79,5 +79,6 @@
|
|
|
79
79
|
"vue": "3.5.13",
|
|
80
80
|
"vue-i18n": "11.2.8",
|
|
81
81
|
"vue-tsc": "^2.1.10"
|
|
82
|
-
}
|
|
82
|
+
},
|
|
83
|
+
"packageManager": "pnpm@11.21.0+sha512.521705bce689924eac72f5a3587122f362689ef6571e55ba80076fd637c11132ecffada26fad4ea79c485bfddbfd3d5a2a5b05805a77e893de71ec8a6cca3bb1"
|
|
83
84
|
}
|