create-lumfall 1.0.0 → 1.0.1

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.
Files changed (34) hide show
  1. package/cli.js +2 -2
  2. package/package.json +1 -1
  3. package/templates/document/README.md +21 -108
  4. package/templates/document/app/pages/docs/docs-config.js +23 -109
  5. package/templates/document/docs/guide/example.md +41 -0
  6. package/templates/document/docs/guide/introduction.md +20 -44
  7. package/templates/document/docs/advanced/dashboard.md +0 -66
  8. package/templates/document/docs/advanced/health.md +0 -72
  9. package/templates/document/docs/advanced/monitoring.md +0 -60
  10. package/templates/document/docs/advanced/security.md +0 -88
  11. package/templates/document/docs/core/app-instance.md +0 -114
  12. package/templates/document/docs/core/controller-service.md +0 -113
  13. package/templates/document/docs/core/lifecycle.md +0 -60
  14. package/templates/document/docs/core/middleware.md +0 -83
  15. package/templates/document/docs/core/plugins.md +0 -77
  16. package/templates/document/docs/core/router-schema.md +0 -102
  17. package/templates/document/docs/dsl/api-contract.md +0 -88
  18. package/templates/document/docs/dsl/extend.md +0 -311
  19. package/templates/document/docs/dsl/menu.md +0 -101
  20. package/templates/document/docs/dsl/model-project.md +0 -122
  21. package/templates/document/docs/dsl/overview.md +0 -116
  22. package/templates/document/docs/dsl/reference.md +0 -175
  23. package/templates/document/docs/dsl/schema-actions.md +0 -135
  24. package/templates/document/docs/dsl/schema.md +0 -121
  25. package/templates/document/docs/frontend/build.md +0 -118
  26. package/templates/document/docs/frontend/curl.md +0 -75
  27. package/templates/document/docs/frontend/page.md +0 -99
  28. package/templates/document/docs/frontend/widgets.md +0 -151
  29. package/templates/document/docs/guide/config.md +0 -108
  30. package/templates/document/docs/guide/deployment.md +0 -115
  31. package/templates/document/docs/guide/getting-started.md +0 -199
  32. package/templates/document/docs/guide/structure.md +0 -98
  33. package/templates/document/docs/reference/commands.md +0 -70
  34. package/templates/document/docs/reference/faq.md +0 -94
@@ -1,116 +0,0 @@
1
- # DSL 总览
2
-
3
- Lumfall 对 B 端管理台的核心设计是一套**声明式 DSL**:菜单结构、页面形态、
4
- 列表页的搜索栏 / 表格 / 表单 / 详情,全部由 `model/` 目录下的配置文件描述,
5
- 启动时自动扫描合并,前端 Dashboard 页面按配置渲染——**写配置,而不是写页面**。
6
-
7
- - 完整规则源文件:框架包内 `model/docs/dsl-guide.md`(编写规则)与
8
- `model/docs/dashboard-model.md`(字段速查),本章节是其使用视角的展开
9
- - 参考实现:同工作区 `lumfall-business/`(两个 Model、多个 Project 的完整示例)
10
-
11
- ## 两层 DSL:Model 与 Project
12
-
13
- ```text
14
- Model(模型) 一个业务域的公共默认配置(菜单骨架),可被多个 Project 继承
15
- Project(项目) 一个具体项目的差异化配置,与所属 Model 深度合并
16
- ```
17
-
18
- - DSL 以 CommonJS 模块存放在业务项目根目录 `model/` 下,**新增文件即生效,无需注册**
19
- - `key` / `modelKey` 由扫描器按目录名 / 文件名自动注入,不要手写
20
- - 合并规则:同 `key` 深度合并(Project 覆盖 Model),新 `key` 追加到末尾,
21
- 详见 [Model 与 Project](./model-project.md)
22
-
23
- ```text
24
- model/
25
- ├── index.js # 扫描器 + 合并引擎(框架自带,不要动)
26
- ├── business/ # ← Model:电商系统
27
- │ ├── model.js # 公共默认配置
28
- │ └── project/
29
- │ ├── taobao.js # 项目:淘宝
30
- │ └── jd.js # 项目:京东
31
- └── course/ # ← Model:课程系统
32
- ├── model.js
33
- └── project/
34
- └── bilibili.js
35
- ```
36
-
37
- ## 四种页面形态
38
-
39
- 页面渲染方式由菜单项的 `moduleType` 决定(详见[菜单项 DSL](./menu.md)):
40
-
41
- | `moduleType` | 形态 | 说明 |
42
- | --- | --- | --- |
43
- | `schema` | 列表工作台 | **主要形态**:一份字段 schema 驱动搜索栏 + 表格 + 动态表单/详情抽屉,见 [schema 模块 DSL](./schema.md) |
44
- | `custom` | 自定义页 | 跳转到业务自己注册的前端路由 |
45
- | `sider` | 侧边复合视图 | 左侧二级菜单 + 右侧子页面 |
46
- | `iframe` | 嵌入页 | 内嵌外部 URL 或内部页面 |
47
-
48
- ## 一个最小例子
49
-
50
- ```js
51
- // model/business/model.js —— 公共默认
52
- module.exports = {
53
- model: "dashboard",
54
- name: "电商系统",
55
- menu: [
56
- {
57
- key: "product",
58
- name: "商品管理",
59
- menuType: "module",
60
- moduleType: "schema",
61
- schemaConfig: {
62
- api: "/api/project/product", // 接口基址,见「接口契约」
63
- schema: {
64
- type: "object",
65
- properties: {
66
- productName: {
67
- type: "string",
68
- label: "商品名称",
69
- tableOption: { width: 200 }, // 进表格列
70
- searchOption: { componentType: "input" }, // 进搜索栏
71
- createFormOption: { componentType: "input" }, // 进新增表单
72
- },
73
- status: {
74
- type: "string",
75
- label: "上架状态",
76
- tableOption: {
77
- enumList: [
78
- { label: "上架", value: "1" },
79
- { label: "下架", value: "0" },
80
- ],
81
- },
82
- },
83
- },
84
- required: ["productName"],
85
- },
86
- },
87
- },
88
- ],
89
- };
90
- ```
91
-
92
- ```js
93
- // model/business/project/taobao.js —— 只写差异
94
- module.exports = {
95
- name: "淘宝",
96
- desc: "淘宝电商项目",
97
- homePage: "/schema?projectKey=taobao&key=product",
98
- menu: [
99
- // 只覆盖名称,其余(schemaConfig 等)全部继承 Model
100
- { key: "product", name: "商品管理(淘宝)" },
101
- ],
102
- };
103
- ```
104
-
105
- 重启服务后,`/view/dashboard?projectKey=taobao` 就是一个可用的商品管理页:
106
- 搜索、分页、枚举标签、新增/编辑/详情抽屉全部由这份配置驱动。
107
-
108
- ## 章节导航
109
-
110
- - [Model 与 Project](./model-project.md):字段定义与合并规则
111
- - [菜单项 DSL](./menu.md):menuType / moduleType / 分组 / 路由参数
112
- - [schema 模块](./schema.md):字段 schema、表格列、搜索项
113
- - [按钮与动态表单](./schema-actions.md):tableConfig、增删改查抽屉
114
- - [接口契约](./api-contract.md):schema 模块的后端接口标准
115
- - [扩展 DSL](./extend.md):业务侧自定义搜索 / 表单控件与动态组件
116
- - [完整模板与注意事项](./reference.md):全量配置模板 + 20 条避坑清单
@@ -1,175 +0,0 @@
1
- # 完整模板与注意事项
2
-
3
- ## 全量配置模板
4
-
5
- 包含所有菜单类型的项目级模板,可直接复制修改:
6
-
7
- ```js
8
- module.exports = {
9
- name: "示例项目",
10
- desc: "展示所有菜单类型的示例",
11
- homePage: "/schema?projectKey=demo&key=product",
12
-
13
- menu: [
14
- // ─── 1. custom 模块(自定义路由页面)───
15
- {
16
- key: "home",
17
- name: "首页",
18
- menuType: "module",
19
- moduleType: "custom",
20
- customConfig: { path: "/todo" },
21
- },
22
-
23
- // ─── 2. iframe 模块(嵌入外部页面)───
24
- {
25
- key: "external",
26
- name: "外部链接",
27
- menuType: "module",
28
- moduleType: "iframe",
29
- iframeConfig: { path: "https://example.com" },
30
- },
31
-
32
- // ─── 3. sider 模块(侧边栏复合视图)───
33
- {
34
- key: "management",
35
- name: "管理",
36
- menuType: "module",
37
- moduleType: "sider",
38
- siderConfig: {
39
- menu: [
40
- { key: "settings", name: "设置", menuType: "module", moduleType: "custom",
41
- customConfig: { path: "/todo" } },
42
- { key: "stats", name: "统计", menuType: "module", moduleType: "iframe",
43
- iframeConfig: { path: "https://stats.example.com" } },
44
- ],
45
- },
46
- },
47
-
48
- // ─── 4. schema 模块(搜索栏 + 表格 + 动态表单)───
49
- {
50
- key: "product",
51
- name: "商品管理",
52
- menuType: "module",
53
- moduleType: "schema",
54
- schemaConfig: {
55
- api: "/api/project/product",
56
- schema: {
57
- type: "object",
58
- properties: {
59
- productId: {
60
- type: "string",
61
- label: "商品ID",
62
- tableOption: { width: 300, ellipsis: true, tooltip: true },
63
- editFormOption: { componentType: "input", disabled: true },
64
- },
65
- productName: {
66
- type: "string",
67
- label: "商品名称",
68
- minLength: 3,
69
- maxLength: 10,
70
- tableOption: { width: 200 },
71
- searchOption: { componentType: "input", default: "",
72
- placeholder: "请输入商品名称", allowClear: true },
73
- createFormOption: { componentType: "input" },
74
- editFormOption: { componentType: "input" },
75
- detailPanelOption: {},
76
- },
77
- status: {
78
- type: "string",
79
- label: "上架状态",
80
- tableOption: { width: 200, enumList: [
81
- { label: "上架", value: "1" },
82
- { label: "下架", value: "0" },
83
- ] },
84
- searchOption: { componentType: "select", default: "", enumList: [
85
- { label: "上架", value: "1" },
86
- { label: "下架", value: "0" },
87
- ] },
88
- detailPanelOption: {},
89
- },
90
- createTime: {
91
- type: "string",
92
- label: "创建时间",
93
- tableOption: { width: 180 },
94
- searchOption: { componentType: "dateRange", default: [],
95
- showTime: true, valueFormat: "YYYY-MM-DD HH:mm:ss" },
96
- detailPanelOption: {},
97
- },
98
- },
99
- required: ["productName"],
100
- },
101
- tableConfig: {
102
- headerButtons: [
103
- { label: "新增商品", eventKey: "showComponent", type: "outline",
104
- eventOption: { comName: "createForm" } },
105
- ],
106
- rowButtons: [
107
- { label: "查看", eventKey: "showComponent", type: "primary",
108
- eventOption: { comName: "detailPanel" } },
109
- { label: "修改", eventKey: "showComponent", type: "warning",
110
- eventOption: { comName: "editForm" } },
111
- { label: "删除", eventKey: "delete", type: "danger",
112
- eventOption: { params: { productId: "schema::productId" } } },
113
- ],
114
- componentConfig: {
115
- createForm: { title: "新增商品", saveBtnText: "新增商品" },
116
- editForm: { mainKey: "productId", title: "修改商品", saveBtnText: "修改商品" },
117
- detailPanel: { mainKey: "productId", title: "商品详情" },
118
- },
119
- },
120
- },
121
- },
122
-
123
- // ─── 5. group 分组(下拉子菜单)───
124
- {
125
- key: "system",
126
- name: "系统管理",
127
- menuType: "group",
128
- subMenu: [
129
- { key: "users", name: "用户管理", menuType: "module", moduleType: "custom",
130
- customConfig: { path: "/todo" } },
131
- { key: "roles", name: "角色管理", menuType: "module", moduleType: "custom",
132
- customConfig: { path: "/todo" } },
133
- ],
134
- },
135
-
136
- // ─── 6. 仅覆盖(从 Model 继承其余属性,只改 name)───
137
- { key: "report", name: "报表(自定义名称)" },
138
- ],
139
- };
140
- ```
141
-
142
- ## 注意事项(避坑清单)
143
-
144
- | # | 注意点 | 说明 |
145
- | --- | --- | --- |
146
- | 1 | **`key` 必填且同级唯一** | 菜单项合并、前端查找全部依赖 `key`,缺失会导致合并不生效、菜单点击无响应 |
147
- | 2 | **`homePage` 格式** | 写页面内路由 `/path?projectKey=xxx&key=xxx`(不带 `/view/dashboard` 前缀),`projectKey` 必须与文件名一致 |
148
- | 3 | **覆盖只需写 `key` + 差异字段** | `{ key: "product", name: "商品管理(pdd)" }` 即可覆盖名称,其余从 Model 继承 |
149
- | 4 | **不要手写 `key` / `modelKey`** | 扫描器自动注入,手动写无意义 |
150
- | 5 | **sider 子菜单支持任意 moduleType** | 也支持嵌套 group(层级不宜过深) |
151
- | 6 | **group 的 `subMenu` 子项必须写 `menuType: "module"`** | 否则前端无法正确渲染子菜单项 |
152
- | 7 | **iframe 的 `path` 可以是完整 URL 或页面内路径** | 原样作为 `<iframe src>`;未配置时显示空态 |
153
- | 8 | **新增 Model / Project 无需改代码** | 按目录约定放文件,重启即自动加载 |
154
- | 9 | **注意 `menuType` 拼写** | 拼写错误会导致菜单项无法识别为 module / group |
155
- | 10 | **sider 子菜单项的 `key` 同级唯一** | 路由 query 参数是 `siderKey`,但 key 匹配逻辑不变 |
156
- | 11 | **覆盖形态时带全对应 config** | 改 `moduleType` 为 `iframe` / `schema` 时必须同时提供 `iframeConfig` / `schemaConfig` |
157
- | 12 | **不配 `tableOption` / `searchOption` 就不显示** | 表格列与搜索栏互相独立,由各自 Option 的存在与否决定 |
158
- | 13 | **`api` 是基址,不是列表地址** | 前端自动请求 `GET <api>/list`,见[接口契约](./api-contract.md) |
159
- | 14 | **router-schema 的 path 必须与路由完全一致** | 不一致时校验**静默不生效**(不报错) |
160
- | 15 | **`dateRange` 搜索值拆为 `_start` / `_end`** | 固定 `YYYY-MM-DD HH:mm:ss`;未选值不下发;组件忽略 `default`,URL 预填对它无效 |
161
- | 16 | **sider 子项 custom 的 `path` 必须以 `/` 开头** | 否则拼出 `/sidertaobao/...` 之类的非法路由,无法跳转 |
162
- | 17 | **`componentConfig` 必须放在 `tableConfig` 下** | 写在 `schemaConfig` 顶层不生效 |
163
- | 18 | **`showComponent` 用 `eventOption.comName`** | 字段名是 `comName`(不是 `componentName`) |
164
- | 19 | **表单 `componentType` 当前仅支持 `input` / `inputNumber` / `select`** | `dynamicSelect` / `dateRange` 未在表单侧注册;`select` 未配 `default` 会回退第一个枚举值 |
165
- | 20 | **必填校验用顶层 `schema.required` 数组** | 自动注入对应 option 的 `required`(红星 + 校验),不要在每个 option 里手写 |
166
-
167
- ## 字段速查卡
168
-
169
- 完整的字段级结构速查(含每个子字段的语义)见框架包内
170
- `model/docs/dashboard-model.md`;本文档各页的表格已覆盖日常使用的全部字段。
171
-
172
- ## 下一步
173
-
174
- - [Dashboard 与 Model 配置](../advanced/dashboard.md):Dashboard 页面如何消费这份配置
175
- - [常见错误自查](../reference/faq.md):启动与运行问题排查
@@ -1,135 +0,0 @@
1
- # 按钮与动态表单
2
-
3
- schema 模块的增删改查交互由两部分 DSL 驱动:`tableConfig` 里的**按钮**
4
- (表头按钮 / 行按钮)和**动态组件注册**(`componentConfig`)。
5
- 动态组件以抽屉(`a-drawer`,宽 550)呈现,覆盖新增、编辑、详情三种形态。
6
-
7
- ## 按钮配置
8
-
9
- 按钮放在 `schemaConfig.tableConfig` 下,每项透传给 `<a-button>`:
10
-
11
- ```js
12
- tableConfig: {
13
- // 表头按钮:渲染在表格上方右侧,type 直接映射 a-button 的 type
14
- headerButtons: [
15
- { label: "新增商品", eventKey: "showComponent", type: "outline",
16
- eventOption: { comName: "createForm" } },
17
- ],
18
- // 行按钮:渲染在最右侧固定的「操作」列(text 按钮,type 映射状态色)
19
- rowButtons: [
20
- { label: "查看", eventKey: "showComponent", type: "primary",
21
- eventOption: { comName: "detailPanel" } },
22
- { label: "修改", eventKey: "showComponent", type: "warning",
23
- eventOption: { comName: "editForm" } },
24
- { label: "删除", eventKey: "delete", type: "danger",
25
- eventOption: { params: { productId: "schema::productId" } } },
26
- ],
27
- }
28
- ```
29
-
30
- 操作列宽度自动估算(`30 + Σ(按钮字数 × 14 + 26)`),无需配置;
31
- 未配置按钮时操作列不渲染。
32
-
33
- ## eventKey:点击行为
34
-
35
- | `eventKey` | 内置行为 | `eventOption` |
36
- | --- | --- | --- |
37
- | `delete` | 确认框 → `DELETE <api>`(body 为参数对象)→ 成功后刷新表格 | `params`: 目前**只取第一组键值对**,取值语法 `"schema::<fieldKey>"` 表示从行数据取值 |
38
- | `showComponent` | 打开 `comName` 对应的动态组件抽屉 | `comName`: `createForm` / `editForm` / `detailPanel`(**字段名是 `comName`,不是 `componentName`**) |
39
- | 其他(如 `edit`) | 无内置行为,向上 emit `operate` 事件,可自行扩展 | — |
40
-
41
- ::: warning componentConfig 必须放在 tableConfig 下
42
- 框架读取的是 `schemaConfig.tableConfig.componentConfig`,
43
- 写在 `schemaConfig` 顶层不生效。
44
- :::
45
-
46
- ## componentConfig:动态组件注册
47
-
48
- key 固定为三个(前端组件注册表只有这三个,未注册的 key 不渲染):
49
-
50
- ```js
51
- tableConfig: {
52
- componentConfig: {
53
- createForm: { title: "新增商品", saveBtnText: "新增商品" },
54
- editForm: { mainKey: "productId", title: "修改商品", saveBtnText: "修改商品" },
55
- detailPanel: { mainKey: "productId", title: "商品详情" },
56
- },
57
- }
58
- ```
59
-
60
- | 组件 | 形态 | 数据流 | 必配 |
61
- | --- | --- | --- | --- |
62
- | `createForm` | 新增表单抽屉 | 直接打开,保存 `POST <api>` | 无 |
63
- | `editForm` | 编辑表单抽屉 | 先 `GET <api>?<mainKey>=<值>` 回显,保存 `PUT <api>`(body 带 `{ [mainKey]: 值 }`) | `mainKey` |
64
- | `detailPanel` | 详情抽屉(只读) | 先 `GET <api>?<mainKey>=<值>` 回显 | `mainKey` |
65
-
66
- - `title` 默认「创建」/「详情」,`saveBtnText` 默认「保存」
67
- - `mainKey` 是行数据主键字段名——**未配置时编辑 / 详情无法工作**
68
- - 表单字段由各字段的 `createFormOption` / `editFormOption` 决定(见下)
69
- - 保存 / 操作成功后组件 emit `command: loadTableData`,框架自动刷新表格
70
-
71
- ## 动态表单与详情字段(xxxOption)
72
-
73
- 字段配置了对应 Option 后进入同名动态组件的 schema:
74
-
75
- ```js
76
- productName: {
77
- type: "string",
78
- label: "商品名称",
79
- minLength: 3, // JSON-Schema 约束:表单 ajv 校验 + placeholder 提示
80
- maxLength: 10,
81
- createFormOption: { // 新增表单项
82
- componentType: "input",
83
- default: "10086",
84
- },
85
- editFormOption: { // 编辑表单项
86
- componentType: "input",
87
- disabled: true, // 如主键字段编辑时禁用
88
- // visible: false, // 隐藏该项(v-show,字段仍随 getValue 提交)
89
- },
90
- detailPanelOption: {}, // 详情展示:配置即以「label: value」行展示该字段
91
- },
92
- ```
93
-
94
- ### 表单控件类型
95
-
96
- | `componentType` | arco 组件 | 说明 |
97
- | --- | --- | --- |
98
- | `input` | `a-input` | `placeholder` 等直接透传 |
99
- | `inputNumber` | `a-input-number` | 数值范围走 schema 的 `minimum` / `maximum` |
100
- | `select` | `a-select` | `enumList`: `[{label, value}]`,保存时按枚举值 ajv 校验 |
101
-
102
- > `dynamicSelect` / `dateRange` 尚未在表单侧注册;
103
- > `componentType` 未注册时该项不渲染。
104
-
105
- ### 通用 option 字段
106
-
107
- - `required`:一般**不手写**——由顶层 `schema.required` 自动注入(红星 + 校验)
108
- - `visible: false`:隐藏表单项(`v-show`,字段仍随 `getValue()` 提交)
109
- - `disabled` / `default` / `placeholder`:透传给 arco 组件
110
-
111
- ### 表单校验
112
-
113
- 表单内置 ajv,每个表单项在 blur / 保存时按字段级 JSON-Schema
114
- (`type` / `minLength` / `maxLength` / `pattern` / `minimum` / `maximum` /
115
- `enum`)校验,错误文案显示在项下方;任一项失败则整个表单不提交。
116
-
117
- ## 完整数据流
118
-
119
- ```text
120
- 点击按钮(eventKey=showComponent)
121
- → schema-view 按 eventOption.comName 匹配动态组件,调用组件的 show(rowData)
122
- ├── createForm:直接打开(不接收行数据)
123
- └── editForm / detailPanel:先 GET <api>?<mainKey>=<值> 回显,再打开
124
- → 保存成功 emit command: loadTableData → 表格刷新
125
- ```
126
-
127
- ::: tip 组件类型可以自己扩展
128
- 表单控件(`componentType`)与动态组件都支持业务侧注册自定义实现——
129
- 比如批量导入面板、自定义向导抽屉,与内置的新增/编辑/详情同一套触发机制,
130
- 见[扩展 DSL](./extend.md)。
131
- :::
132
-
133
- ## 下一步
134
-
135
- - [接口契约](./api-contract.md):这些交互背后的后端接口标准
@@ -1,121 +0,0 @@
1
- # schema 模块 DSL
2
-
3
- schema 模块(`moduleType: "schema"`)是 DSL 的主要形态:**一份字段 schema
4
- 同时驱动搜索栏、表格列、新增/编辑表单、详情面板**。每个字段在哪个视图出现、
5
- 以什么控件出现,由该字段是否配置对应的 `xxxOption` 决定。
6
-
7
- ## schemaConfig 总览
8
-
9
- ```js
10
- {
11
- key: "product",
12
- name: "商品管理",
13
- menuType: "module",
14
- moduleType: "schema",
15
- schemaConfig: {
16
- api: "/api/project/product", // 接口基址(不是完整列表地址,见「接口契约」)
17
- schema: { /* 字段 schema,本页重点 */ },
18
- tableConfig: { /* 按钮与动态组件,见「按钮与动态表单」 */ },
19
- searchConfig: {}, // 预留字段,前端暂未消费
20
- },
21
- }
22
- ```
23
-
24
- ::: warning 不要手写 components 字段
25
- 动态组件(表单/详情)的 schema 由框架根据 `tableConfig.componentConfig`
26
- 自动派生,`schemaConfig` 顶层不要手写 `components` 字段。
27
- :::
28
-
29
- ## 字段定义:一份 schema,四个视图
30
-
31
- ```js
32
- schema: {
33
- type: "object",
34
- properties: {
35
- productName: {
36
- type: "string", // JSON-Schema 类型(表单项按此做 ajv 校验)
37
- label: "商品名称", // 表格列标题 / 表单 label / 详情行 label
38
- minLength: 3, // 可选 JSON-Schema 约束:表单侧校验 + 提示
39
- maxLength: 10,
40
-
41
- tableOption: { width: 200 }, // 配了才进表格列
42
- searchOption: { componentType: "input" }, // 配了才进搜索栏
43
- createFormOption: { componentType: "input" }, // 配了才进新增表单
44
- editFormOption: { componentType: "input" }, // 配了才进编辑表单
45
- detailPanelOption: {}, // 配了才进详情面板
46
- },
47
- },
48
- required: ["productName"],
49
- }
50
- ```
51
-
52
- **关键规则**(由前端 `buildDtoSchema` 按 `${comName}Option` 统一拆分实现):
53
-
54
- - `tableOption` / `searchOption` / `createFormOption` / `editFormOption` /
55
- `detailPanelOption` 走**同一套机制**,只是消费方不同
56
- - 配了哪个 Option 字段就进哪个视图,视图之间互相独立——同一字段可以只配其一
57
- - 合并后字段会挂到 `option` 属性上传给对应组件;`type` / `label` /
58
- 约束字段等非 `xxxOption` 键原样保留
59
- - **必填自动注入**:字段名出现在顶层 `required` 数组中,其表单 `option`
60
- 自动获得 `required: true`(红星 + 校验),**不要在各 option 里手写**
61
-
62
- ## tableOption:表格列
63
-
64
- 透传给 arco `<a-table-column>`(`v-bind`),`width` / `ellipsis` / `tooltip` /
65
- `align` / `fixed` 等标准配置均可直接使用。另有三个扩展字段:
66
-
67
- | 字段 | 类型 | 说明 |
68
- | --- | --- | --- |
69
- | `enumList` | `array` | 枚举标签:`[{label, value}]`,命中枚举值的单元格渲染为彩色标签(颜色按索引循环) |
70
- | `toFixed` | `number` | 数字保留 N 位小数 |
71
- | `visible` | `boolean` | `false` 时该列不渲染(字段仍参与搜索 / 数据) |
72
-
73
- > 所有列默认带 `ellipsis: true, tooltip: true` 防止长文本撑破列宽,
74
- > `tableOption` 里的同名配置可覆盖默认值。
75
-
76
- ## searchOption:搜索项
77
-
78
- 控件类型由 `componentType` 选择(注册于框架 `schema-search-bar` 的
79
- search-item-config),其余配置透传给对应 arco 组件:
80
-
81
- | `componentType` | arco 组件 | 额外字段 | 搜索值下发形状 |
82
- | --- | --- | --- | --- |
83
- | `input` | `a-input` | 无(`placeholder`、`allowClear` 直接透传) | 标量 |
84
- | `select` | `a-select` | `enumList`: `[{label, value}]` | 标量 |
85
- | `dynamicSelect` | `a-select` | `api`: 选项接口,挂载后自动请求,响应 `data` 须为 `[{label, value}]` | 标量 |
86
- | `dateRange` | `a-range-picker` | `valueFormat`(建议配合 `showTime: true`) | 拆为 `<fieldKey>_start` / `<fieldKey>_end` 两个参数 |
87
-
88
- ### default 与空值语义
89
-
90
- - `default` 是初始 / 重置值:`input` / `select` / `dynamicSelect` 用标量,
91
- 建议 `""` 表示不选
92
- - `select` / `dynamicSelect` **未配置 `default` 时会回退选中第一个枚举值**,
93
- 建议始终显式写 `default: ""`
94
- - `dateRange` 的重置值恒为 `[]`(组件忽略 `default`,URL 预填对它也无效)
95
- - **空字符串会原样下发**:`getValue()` 只在值为 `undefined` 时省略字段,
96
- `""`(含 `default: ""`)会进入请求——**后端需把 `""` 视为「不过滤」**
97
- - `dateRange` 选中后固定拆成 `<field>_start` / `<field>_end` 两个参数,
98
- 值为 `YYYY-MM-DD HH:mm:ss` 字符串;未选值时两个参数都不下发
99
-
100
- ## URL 预填搜索值
101
-
102
- 路由 query 中存在与字段同名的参数时(如 `?productName=手机`),会覆盖该
103
- 搜索项的 `option.default`——实现「从别处带着搜索条件跳转过来」。
104
- 仅对标量控件(`input` / `select` / `dynamicSelect`)生效。
105
-
106
- ## 搜索数据流
107
-
108
- ```text
109
- schema-search-bar(收集各搜索项 getValue)
110
- → search-panel(@load / @search / @reset 统一转为 search 事件)
111
- → schema-view(apiParams = 搜索值,下发表格)
112
- → schema-table(watch apiParams → 重置分页 → GET <api>/list)
113
- ```
114
-
115
- - 首次挂载:全部搜索项就绪后**自动触发一次带默认值的查询**(含 URL 预填值)
116
- - 点「查询」:立即按当前值触发;点「重置」:恢复 `default` 后重新拉全量
117
-
118
- ## 下一步
119
-
120
- - [按钮与动态表单](./schema-actions.md):增删改查按钮与表单/详情抽屉
121
- - [接口契约](./api-contract.md):后端需要实现的接口标准
@@ -1,118 +0,0 @@
1
- # 前端构建
2
-
3
- 前端构建由框架内置的 Webpack 5 管线完成,业务项目一般**零配置**,
4
- 特殊需求通过 `app/webpack.config.js` 扩展。
5
-
6
- ## 构建模式
7
-
8
- `frontendBuild(_ENV)`(见[构建与部署](../guide/deployment.md)):
9
-
10
- | 模式 | 说明 |
11
- | --- | --- |
12
- | `_ENV=local` | Webpack dev server(`127.0.0.1:9002`),HMR 热更新,模板写盘 |
13
- | `_ENV=prod` | 产物构建到 `app/public/dist/prod/`,CSS 抽离压缩、JS Terser 压缩(去 console)、构建前清空 dist |
14
-
15
- 两种模式都会把页面模板写成 `app/public/dist/entry.<name>.tpl` 供 Koa 渲染。
16
-
17
- ## 入口自动发现
18
-
19
- 构建入口通过扫描得到(框架页面目录 + 业务 `app/pages/`),规则与页面系统一致:
20
- `**/entry.*.js`,业务同名覆盖框架。**新增 / 删除页面不需要改任何构建配置**。
21
-
22
- ## 分包策略
23
-
24
- 生产构建把 JS 拆成三类,配合浏览器长缓存:
25
-
26
- | chunk | 内容 | 变化频率 |
27
- | --- | --- | --- |
28
- | `vendor` | node_modules 第三方库 | 几乎不变 |
29
- | `common` | 被 ≥2 个入口引用的 common / widgets 业务代码 | 较少 |
30
- | `entry.<page>` | 页面自身代码 | 经常 |
31
-
32
- `runtime` 单独抽出;文件名带内容 hash,内容不变则文件名不变。
33
-
34
- ## Webpack 别名
35
-
36
- 页面代码里可用的框架别名:
37
-
38
- | 别名 | 指向 |
39
- | --- | --- |
40
- | `$lumfallBoot` | 页面启动器 |
41
- | `$lumfallPage` | 框架页面目录(框架的 app/pages) |
42
- | `$lumfallCommon` | 框架公共工具目录 |
43
- | `$lumfallCurl` | 请求工具 `curl.js` |
44
- | `$lumfallUtils` | 通用工具 `utils.js` |
45
- | `$lumfallWidgets` | 框架内置组件目录 |
46
- | `$lumfallStore` | Pinia store(`menu.js` / `project.js`) |
47
- | `$lumfallAssert` | 框架静态资源(logo / avatar / 公共样式) |
48
- | `$lumfallHeaderContainer` | 头部布局组件 |
49
- | `$lumfallSchemaForm` / `$lumfallSchemaSearchBar` / `$lumfallSchemaTable` | schema 三件套 |
50
- | `$lumfallSiderContainer` | 侧边布局组件 |
51
-
52
- 另有四个「业务覆盖点」别名,业务项目里存在对应文件时指向业务文件,
53
- 否则指向空模块(所以**业务可以不写这些文件**)。它们是 DSL 的业务侧
54
- 扩展入口——注册自定义搜索 / 表单控件、schema-view 动态组件与 custom 路由,
55
- 完整契约见[扩展 DSL](../dsl/extend.md):
56
-
57
- | 别名 | 业务文件 |
58
- | --- | --- |
59
- | `$businessDashboardRouterConfig` | `app/pages/dashboard/router.js` |
60
- | `$businessComponentConfig` | `app/pages/dashboard/complex-view/schema-view/components/component-config.js` |
61
- | `$businessFormItemConfig` | `app/pages/widgets/schema-form/form-item-config.js` |
62
- | `$businessSearchItemConfig` | `app/pages/widgets/schema-search-bar/complex-view/search-item-config.js` |
63
-
64
- ## 扩展 Webpack 配置
65
-
66
- `app/webpack.config.js` 导出配置对象,与框架配置 `webpack-merge` 的
67
- `merge.smart` 合并。常见场景:
68
-
69
- ```js
70
- // 给 .md 文件加原文导入(本站就是这么做的)
71
- module.exports = {
72
- module: {
73
- rules: [{ test: /\.md$/, type: "asset/source" }],
74
- },
75
- };
76
- ```
77
-
78
- ```js
79
- // 增加 resolve 别名
80
- const path = require("path");
81
-
82
- module.exports = {
83
- resolve: {
84
- alias: {
85
- $business: path.resolve(__dirname, "pages/business"),
86
- },
87
- },
88
- };
89
- ```
90
-
91
- ## 依赖解析:框架共享依赖直接可用
92
-
93
- 框架在 webpack.base 的 `resolve.alias` 里维护了一份**共享依赖白名单**
94
- (alias 指向包的真实目录,`require.resolve` 以框架自身为解析上下文),
95
- 业务页面**可以直接 import 白名单里的库**,无需在业务 `package.json`
96
- 里重复安装:
97
-
98
- - 当前白名单:`vue`、`vue-router`、`pinia`、`@arco-design/web-vue`、
99
- `@babel/runtime`、`axios`、`lodash`、`moment`、`md5`
100
- - alias 指向包目录,所以子路径 import 全部可用
101
- (`@arco-design/web-vue/es/icon`、`@babel/runtime/helpers/*`、`lodash/cloneDeep` 等)
102
- - 框架解析优先于业务 `node_modules`,运行时**只有一份实例**——
103
- 业务即使声明了同名库,构建时也解析到框架那份(不会出现双 Vue)
104
- - 需要暴露更多框架依赖时,在框架 `webpack.base.js` 的 `sharedDeps`
105
- 数组加一行包名;框架没有的库(如文档站的 `markdown-it`)仍需业务自己安装
106
- - 需要 lumfall ≥ 1.1.1;更早版本在 pnpm 下解析不到框架依赖,
107
- 需在业务 `package.json` 显式声明(显式声明在任意版本下都有效)
108
-
109
- `_` 与 `axios` 另有全局注入(ProvidePlugin),页面代码不 import 也能用。
110
-
111
- ## loader 覆盖注意
112
-
113
- - 业务页面的 JS 默认由 babel-loader 处理(生产环境 preset-env +
114
- transform-runtime,worker 并行);`.vue` 由 vue-loader 处理
115
- - `.css` 走 style-loader(dev)/ MiniCssExtract(prod);`.less` 额外经过
116
- less-loader,页面里推荐 `lang="less"`
117
- - `merge.smart` 下相同 `test` 的规则会合并,`use` 数组会被生产配置覆盖——
118
- 想改某个 loader 的行为时优先用「新增规则」或换文件类型,避免整条覆盖