lan-low-code-cli 0.0.0-stage → 2.1.0
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 +814 -3
- package/bin/llc.js +13 -0
- package/dist/api/formDefine.js +161 -0
- package/dist/client.js +140 -0
- package/dist/commands/app.js +252 -0
- package/dist/commands/config.js +75 -0
- package/dist/commands/control.js +158 -0
- package/dist/commands/field.js +125 -0
- package/dist/commands/form.js +1294 -0
- package/dist/commands/locale.js +60 -0
- package/dist/config.js +106 -0
- package/dist/constants.js +275 -0
- package/dist/generator/index.js +1317 -0
- package/dist/index.js +136 -0
- package/dist/types.js +50 -0
- package/dist/utils/icon.js +26 -0
- package/dist/utils/locale.js +53 -0
- package/dist/utils/logger.js +78 -0
- package/dist/utils/random.js +79 -0
- package/dist/widgets.js +304 -0
- package/package.json +40 -3
package/README.md
CHANGED
|
@@ -1,3 +1,814 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# low-code-cli(`llc`)
|
|
2
|
+
|
|
3
|
+
低代码表单引擎命令行工具。在 Node 端**独立实现**,不依赖任何前端包(`@ekp-infra/*`、`@ekp-runtime/*`、`@lui/*`),
|
|
4
|
+
直接组装数据并调用后台接口,支持:
|
|
5
|
+
|
|
6
|
+
- **创建表单**:覆盖 6 种表单类型(普通 / 审批意见 / 全局配置项 / 弹窗 / 通用 / 引用者)
|
|
7
|
+
- **自动获取可用字段**:表单数据模型字段、外部映射表字段、字段库
|
|
8
|
+
- **自动完善表单字段**:依据数据模型自动生成完整表单配置(`fdConfig`:字段控件 + 场景 viewModel + 权限 + 多语言 + 全局规则)并保存
|
|
9
|
+
|
|
10
|
+
## 一、安装与构建
|
|
11
|
+
|
|
12
|
+
本项目**使用 pnpm 管理依赖**(`package.json` 已声明 `packageManager: pnpm@10.26.2`)。
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cd D:\project\aiWork\low-code-cli
|
|
16
|
+
|
|
17
|
+
# 若本机未安装 pnpm:node -v >= 16 时可直接启用 corepack
|
|
18
|
+
corepack enable
|
|
19
|
+
|
|
20
|
+
pnpm install # 安装依赖(会自动执行 prepare -> build)
|
|
21
|
+
pnpm build # 构建
|
|
22
|
+
pnpm link --global # 可选:全局注册 llc 命令
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
> 请勿混用 npm/yarn,以免生成多余的 `package-lock.json` / `yarn.lock`。
|
|
26
|
+
> 常用脚本:`pnpm build`、`pnpm typecheck`、`pnpm start`、`pnpm run rebuild`(clean + build,注意 `pnpm rebuild` 是 pnpm 内置命令,脚本需用 `pnpm run rebuild`)。
|
|
27
|
+
> 非交互式 CI 可使用 `pnpm install --frozen-lockfile`。
|
|
28
|
+
|
|
29
|
+
## 二、鉴权与服务端地址
|
|
30
|
+
|
|
31
|
+
请求头统一携带 `X-AUTH-TOKEN`,服务端基址由用户提供。三种配置方式,优先级从高到低:
|
|
32
|
+
|
|
33
|
+
| 方式 | 示例 |
|
|
34
|
+
|---|---|
|
|
35
|
+
| 命令行参数 | `--base-url <url> --token <token>` |
|
|
36
|
+
| 环境变量 | `LLC_BASE_URL` / `LLC_TOKEN` |
|
|
37
|
+
| 配置文件 | `llc config set`(写入 `~/.lcode/config.json`)或项目根目录 `lcode.config.json` |
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
llc config set --base-url http://mkdev01.ywork.me/data --token <X-AUTH-TOKEN>
|
|
41
|
+
llc config show
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> `baseUrl` 需包含 `/data` 前缀。完整请求地址 = `${baseUrl}/sys-xform/<module>/<method>`。
|
|
45
|
+
|
|
46
|
+
## 三、命令一览
|
|
47
|
+
|
|
48
|
+
### 创建表单
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
llc form create --name <名称> [选项]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**所属应用**(低代码应用)决定表单挂在哪个应用下,是 `modeling` 接口族的核心参数:
|
|
55
|
+
|
|
56
|
+
| 选项 | 说明 |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `--app-id <appId>` | **表单所属应用 id**(应用主键 `fdId`)。给出后默认走 `modeling` 接口族,写入 `fdAppId` |
|
|
59
|
+
| `--group-id <fdGroupId>` | 表单所属分组 id(`modeling` 族) |
|
|
60
|
+
| `--edit-draft` / `--no-edit-draft` | 草稿状态是否允许编辑(`modeling` 族,默认允许) |
|
|
61
|
+
| `--reader-flag` | 阅读者为空时所有人可阅读(`modeling` 族) |
|
|
62
|
+
| `--data-source-id <id>` | 外部数据源 id(`modeling` 族) |
|
|
63
|
+
| `--outer-mapping` | 是否映射外部表(`modeling` 族) |
|
|
64
|
+
| `--fd-entity-id <id>` | 业务建模对应 appId / 应用模块对应 templateId(默认取 `--app-id`) |
|
|
65
|
+
| `--fd-entity-name <name>` | 所属实体 model 名称(`modeling` 族由服务端固定写入,通常无需传) |
|
|
66
|
+
| `--fd-entity-key <key>` | 实体扩展键(预留) |
|
|
67
|
+
| `--fd-run-entity-name <name>` | 表单运行时实体名称 |
|
|
68
|
+
| `--table-name <name>` | 主表名(不传则调用对应接口自动生成) |
|
|
69
|
+
|
|
70
|
+
其余选项:
|
|
71
|
+
|
|
72
|
+
| 选项 | 说明 |
|
|
73
|
+
|---|---|
|
|
74
|
+
| `--name <name>` | 表单名称(必填) |
|
|
75
|
+
| `--code <code>` | 业务编码,默认 `template_xxxxxx` |
|
|
76
|
+
| `--type <type>` | 表单类型:`common` \| `general`(默认)\| `config` \| `modal` \| `template` \| `refer`,也可用 1-6 |
|
|
77
|
+
| `--api <family>` | 接口族:`auto`(默认)\| `modeling` \| `general` \| `design`,见下节 |
|
|
78
|
+
| `--source-form-id <fdId>` | 引用源表单 id(`type=refer` 必填) |
|
|
79
|
+
| `--category <fdId>` | 表单分类 id(`general` 族) |
|
|
80
|
+
| `--icon <icon>` | 页面图标(图标名或图标 JSON)。**必填语义**:不给则使用内置默认图标 |
|
|
81
|
+
| `--readers <ids>` / `--editors <ids>` | 可阅读者 / 可编辑者,逗号分隔(`general` 族) |
|
|
82
|
+
| `--mechanism-entity-name <name>` | 机制实体名(决定可用控件库),默认按接口族推导 |
|
|
83
|
+
| `--mechanism-entity-code <code>` | 机制编码,默认按接口族推导 |
|
|
84
|
+
| `--from-model <fdId>` | 从指定数据模型拷贝字段(默认用新表单自身数据模型) |
|
|
85
|
+
| `--fields <names>` | 仅生成指定字段,逗号分隔 |
|
|
86
|
+
| `--add-field <spec>` | **新增/调整字段**,格式 `name:label[:dataType\|controlType[:controlType]]`,可重复;见「控件类型」章节 |
|
|
87
|
+
| `--option <spec>` | 为下拉/单选/多选**新建选项**:`"字段名=选项1,选项2:值2"`,可重复 |
|
|
88
|
+
| `--detail <spec>` | **新建/调整明细表**:`"明细表标题=字段1:标题1[:控件类型],..."`,可重复,见「明细表」章节 |
|
|
89
|
+
| `--include-system` | 同时把系统字段渲染到表单上(默认只渲染业务字段) |
|
|
90
|
+
| `--per-row <n>` | 每行控件数,默认 2 |
|
|
91
|
+
| `--span <n>` | 控件栅格宽度,默认 12 |
|
|
92
|
+
| `--locale <locales>` | 多语言,逗号分隔,**第一个为主语言**(默认 `Cn`);`all` = `Cn,Us,Tw` |
|
|
93
|
+
| `--lang-file <path>` | 多语言文案文件(JSON),见「多语言」章节 |
|
|
94
|
+
| `--layout <mode>` | 渲染布局:`rows`(默认)\| `grid` 栅格 \| `tabs` 多页签,见「布局」章节 |
|
|
95
|
+
| `--grid-columns <n>` | 栅格列数(`--layout grid`,默认取 `--per-row`) |
|
|
96
|
+
| `--tabs <spec>` | 多页签定义:`"标题:字段1,字段2\|标题2:字段3"`(`--layout tabs`) |
|
|
97
|
+
| `--tab-layout <mode>` | 页签内层布局:`rows`(默认)\| `grid` 栅格,可组合出「页签 + 栅格」的嵌套结构 |
|
|
98
|
+
| `--required <fields>` | 必填字段(逗号分隔,作用于 `add`/`edit`) |
|
|
99
|
+
| `--readonly <fields>` | 只读字段(逗号分隔,`editable=false`,作用于 `add`/`edit`) |
|
|
100
|
+
| `--hidden <fields>` | 隐藏字段(逗号分隔,`visible=false`,作用于 `add`/`edit`/`view`) |
|
|
101
|
+
| `--auth-file <path>` | 精细字段权限(JSON),见「字段权限」章节 |
|
|
102
|
+
| `--action <spec>` | 控件动作:`"字段名:事件:函数源码或@js文件"`,可重复;全局动作用 `$global`,见「控件动作」章节 |
|
|
103
|
+
| `--action-file <path>` | 控件动作定义文件(JSON),见「控件动作」章节 |
|
|
104
|
+
| `--no-config` | 仅创建空表单,不生成字段配置 |
|
|
105
|
+
| `--publish` | 创建后立即发布 |
|
|
106
|
+
| `--dry-run` | 只打印将提交的数据,不发起请求 |
|
|
107
|
+
|
|
108
|
+
### 接口族与表单类型的对应关系(重要)
|
|
109
|
+
|
|
110
|
+
后端 `SysGeneralFormDefineService` 对类型有强校验:
|
|
111
|
+
|
|
112
|
+
```java
|
|
113
|
+
case add:
|
|
114
|
+
case update:
|
|
115
|
+
if (!Objects.equals(formDefinedVO.getFdFormDefineType(), FormDefineType.General)) {
|
|
116
|
+
throw new ParamsNotValidException();
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
即 `generalFormDefine/*` **只能建审批意见表单**。CLI 提供三种接口族:
|
|
121
|
+
|
|
122
|
+
| 接口族 | 适用场景 | 接口链路 |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `modeling` | **低代码应用下建表单(推荐)** | `sysModelingXForm/generateTableName` → `create` → `saveDesign`(或 `saveDesignAndPublish`) |
|
|
125
|
+
| `general` | 审批意见表单(后台"表单管理") | `generalFormDefine/init` → `add` → `save` → `publish` |
|
|
126
|
+
| `design` | 表单引擎原始接口,任意类型 | `sysXFormDesign/create` → `save` → `publish` |
|
|
127
|
+
|
|
128
|
+
`--api auto`(默认)的选择规则:
|
|
129
|
+
|
|
130
|
+
1. 给了 `--app-id` → `modeling`(应用下建表单)
|
|
131
|
+
2. 否则 `--type general` → `general`
|
|
132
|
+
3. 其余 → `design`
|
|
133
|
+
|
|
134
|
+
显式指定与类型冲突的组合会被直接拦截(如 `--type common --api general`)。
|
|
135
|
+
|
|
136
|
+
### 各接口族的关键差异
|
|
137
|
+
|
|
138
|
+
| | `modeling` | `general` | `design` |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| 表单归属 | `fdAppId`(`modeling_xform.fd_app_id` 外键) | 独立定义表 | 表单设计表 |
|
|
141
|
+
| `fdEntityName` | 服务端写死 `sys-modeling` | `init` 返回 `...SysGeneralFormDefine` | 需自行指定 |
|
|
142
|
+
| `fdRunEntityName` | 服务端写死 `sys-modeling` | `init` 返回 | 需自行指定 |
|
|
143
|
+
| `fdEntityId` | 服务端写死 = 表单 id | `init` 返回 = 表单 id | 需自行指定 |
|
|
144
|
+
| 表名规则 | `mk_model_yyyyMMdd` + 随机 5 位 | 服务端生成 | `sysXFormDataModel/generateTableName` |
|
|
145
|
+
| 发布 | `saveDesignAndPublish`(含发布校验与默认视图) | `publish` | `publish`(`XFormDesignPushVO`) |
|
|
146
|
+
|
|
147
|
+
机制默认值:`general` 族 → `sys-xform` / `...SysGeneralFormDefine`;`modeling` 与 `design` 族 → `sys-modeling` / `...SysModelingMainEntity`(可用 `--mechanism-entity-*` 覆盖)。
|
|
148
|
+
|
|
149
|
+
### 应用(创建 / 查询 / 修改 / 删除)
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
llc app list # 列出应用,返回的 fdId 即 --app-id
|
|
153
|
+
llc app list --keyword 请假 # 按名称搜索
|
|
154
|
+
llc app list --no-auth # 使用不做权限校验的接口(sysModelingApplication/listNotAuth)
|
|
155
|
+
llc app get --id <appId> # 查看详情(含可访问者/可维护者)
|
|
156
|
+
|
|
157
|
+
# 新建应用(后端会同时创建默认首页)
|
|
158
|
+
llc app create --name 客户管理 --code crm --desc 客户全生命周期 --icon iconCommon_line_16_file
|
|
159
|
+
|
|
160
|
+
# 修改应用(只传需要改的项;不会丢失可访问者/可维护者)
|
|
161
|
+
llc app update --id <appId> --name 客户管理2.0 --desc 新描述
|
|
162
|
+
|
|
163
|
+
# 删除应用(连带其下表单,需 --yes 确认)
|
|
164
|
+
llc app delete --id <appId> --yes
|
|
165
|
+
llc app delete-data --id <appId> --yes # 只清业务数据,保留应用
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
> 应用编码 `--code` 只允许**字母/数字/连字符**(平台校验 `^[a-zA-Z-0-9]*$`),不能使用下划线;CLI 会本地预校验。
|
|
169
|
+
|
|
170
|
+
### 删除表单
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
llc form delete --id <fdId> --yes # 删除表单(连同数据模型,需 --yes)
|
|
174
|
+
llc form delete-data --id <fdId> --yes # 只删运行时业务数据,保留表单定义
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 获取可用字段
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
llc field list --form-id <fdId> # 表单已有字段(数据模型)
|
|
181
|
+
llc field list --model-id <fdId> # 指定数据模型字段
|
|
182
|
+
llc field list --table <tableName> # 外部映射表字段
|
|
183
|
+
llc field library [--keyword <kw>] # 字段库
|
|
184
|
+
llc field gen-key --name <名称> # 生成字段编码
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 控件类型
|
|
188
|
+
|
|
189
|
+
**先查环境再选控件**:
|
|
190
|
+
|
|
191
|
+
`ash
|
|
192
|
+
llc control list # 列出环境全部可用控件(含桌面/移动端包、数据项类型、是否登记、是否支持选项)
|
|
193
|
+
llc control list --all # 含布局/外观类
|
|
194
|
+
llc control show --type moneytext # 查看某控件的属性面板配置项与默认值
|
|
195
|
+
llc control show --element @elem/xform-select --json
|
|
196
|
+
`
|
|
197
|
+
|
|
198
|
+
control list 的数据源是 {origin}/web/sys/artifact/elements/index.json + 各控件 config.json(首次运行会逐个拉取并落盘缓存,之后秒回);已登记 表示可直接用于 --add-field,支持选项 表示可用 --option(dictType=optionDict)。
|
|
199
|
+
|
|
200
|
+
`--add-field` 的第三个 token 既可写**数据项类型**(`varchar`/`number`/…),
|
|
201
|
+
也可直接写**控件类型**(`moneytext`/`select`/…),第四 token 为控件类型:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
--add-field "fd_a:项目名称" # 默认单行文本
|
|
205
|
+
--add-field "fd_b:预算金额:moneytext" # 按控件类型
|
|
206
|
+
--add-field "fd_c:评分:number:rate" # 数据项类型 + 控件类型
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**若字段名已存在,则视为「调整该字段」**:覆盖其标题与控件类型,保留 `fdId`、`fdOrder` 等,
|
|
210
|
+
因此可以对既有表单做控件替换(`llc form autofill --add-field "fd_amt:预算金额:moneytext" --apply`)。
|
|
211
|
+
|
|
212
|
+
支持的全部控件(`src/constants.ts#CONTROL_TYPE_MAP`,均经真实环境 `config.json` 的
|
|
213
|
+
`xform.type` 成对校验;无移动端包的控件回落为桌面端包,与平台 `platform=all` 行为一致):
|
|
214
|
+
|
|
215
|
+
| 分类 | 控件类型 |
|
|
216
|
+
|---|---|
|
|
217
|
+
| 文本 | `text`、`textarea`、`rich-text`、`upcasing`、`phoneNumber`、`hyperlinks` |
|
|
218
|
+
| 数值 | `numbertext`、`moneytext`、`rate`、`slider`、`timepicker`、`daterange` |
|
|
219
|
+
| 选择 | `select`、`radio`、`checkbox`(均支持 `--option` 配选项) |
|
|
220
|
+
| 日期 | `timestamp`、`timeZone` |
|
|
221
|
+
| 组织/地址 | `address` |
|
|
222
|
+
| 附件/媒体 | `attachment`、`image`、`video` |
|
|
223
|
+
| 编码/码图 | `barcode`、`qrcode` |
|
|
224
|
+
| 其它 | `switch`、`hidden`、`dividing`、`subject`、`relation`、`relationQuery` |
|
|
225
|
+
|
|
226
|
+
`--option` 为选择类控件建选项,写入 `controlProps.options` 与 `fdFontExtendData.options`,
|
|
227
|
+
并生成 `prop:'option'` 的多语言条目:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
--option "fd_col_level=高:high,中:mid,低:low"
|
|
231
|
+
--option "fd_col_type=研发:rd,实施:impl,运维:ops" # 省略值则按 1..n
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 明细表
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
llc form autofill --id <fdId> --apply --publish \
|
|
238
|
+
--detail "设备清单=fd_sname:设备名称,fd_scount:设备数量:numbertext,fd_sstatus:设备状态:select" \
|
|
239
|
+
--detail "人员明细=fd_pname:姓名,fd_pwork:是否在职:switch" \
|
|
240
|
+
--option "fd_sstatus=在用,报废,维修中" \
|
|
241
|
+
--required "fd_sname,fd_pname"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
明细表会生成**一整个子数据模型**(`fdType:'detail'`),落库位置:
|
|
245
|
+
|
|
246
|
+
| 位置 | 内容 |
|
|
247
|
+
|---|---|
|
|
248
|
+
| `dataModel` | 新增一个 detail 模型:`fdId` 来自 `sysXFormDataModel/getSystemDefaultModel`,表名来自 `generateTableName({fdType:'detail'})`,系统字段 `fd_id`/`fd_main_id`/`fd_order`,`fdAttribute` 为明细表控件配置 |
|
|
249
|
+
| `view.render.desktop` | `main` 末尾追加独立行(span 24):`row → { key:<明细表名>, children:[明细字段引用] }` |
|
|
250
|
+
| `view.render.mobile` | 平铺追加明细表节点与字段引用 |
|
|
251
|
+
| `view.controlMappings` | 追加 `@elem/xform-detail-table` / `@elem/xform-m-detail-table`(**明细表控件需要进 mappings**) |
|
|
252
|
+
| `view.controlStyle` | 明细表自身条目(desktop + mobile);**明细字段不需要** |
|
|
253
|
+
| `auth` | 按表名新增条目:`add/edit` 带 `canAddRow/canDeleteRow/canImport` 与行操作,`view` 带 `canExport` |
|
|
254
|
+
| `lang` | 明细表标题(`prop:'label'`,含 `default`)与明细字段标题/占位/选项 |
|
|
255
|
+
|
|
256
|
+
要点:
|
|
257
|
+
|
|
258
|
+
- **再次执行 `--detail` 同名标题会复用已有明细表**(保留 `fdId`、系统字段与已有列),可继续调整字段;
|
|
259
|
+
不传 `--detail` 时已有明细表原样保留。
|
|
260
|
+
- 明细字段的控件类型、选项、权限与主表字段完全一致(`--option`/`--required`/`--readonly`/`--hidden`
|
|
261
|
+
对明细字段同样生效,按字段名匹配)。
|
|
262
|
+
- 明细表控件的默认属性(`mode`/`defaultRowNumber`/`showNumber`/`showRowSelection` 等)
|
|
263
|
+
**不在** `config.json` 里,而由前端写死;CLI 按 `src/constants.ts#DETAIL_CONTROL_DEFAULTS` 复刻。
|
|
264
|
+
|
|
265
|
+
### 布局
|
|
266
|
+
|
|
267
|
+
`--layout` 决定 `viewModel.view.render.desktop` 的结构。**移动端始终是平铺的字段引用**
|
|
268
|
+
(实测真实表单的 `render.mobile` 不含任何布局容器),因此布局只影响桌面端。
|
|
269
|
+
|
|
270
|
+
| `--layout` | 桌面端结构 | 真实样本依据 |
|
|
271
|
+
|---|---|---|
|
|
272
|
+
| `rows`(默认) | `main` → 若干 `@elem/xform-row` → 字段引用 | ✔ |
|
|
273
|
+
| `grid` | `main` → `layout` → `@elem/layout-grid` → 若干 `@elem/layout-grid.GridItem` → 字段引用 | ✔ |
|
|
274
|
+
| `tabs` | `main` → `@elem/xform-tabs` → 若干 `@elem/xform-tabpane` → `@elem/xform-row` → 字段引用 | ✔ |
|
|
275
|
+
|
|
276
|
+
要点(均为真实表单核对结论):
|
|
277
|
+
|
|
278
|
+
- **栅格布局控件不进 `controlMappings`**;**多页签控件必须进**(`tab-appearance` / `tabs` / `tabpane` 三件套)。
|
|
279
|
+
- 多页签的 key 约定:外观 key 形如 `@elem/xform-tab-appearance~xxxxxx`,
|
|
280
|
+
tabs 节点 key 为 `<外观key>-tabItem`,面板为 `<外观key>-tabN`,
|
|
281
|
+
且 `controlProps.parent = { name: '@elem/xform-tab-appearance', type: 'appearance' }`。
|
|
282
|
+
渲染树中**没有**独立的 `tab-appearance` 节点。
|
|
283
|
+
- 页签标题走多语言:`controlProps.tabMessageKey`,
|
|
284
|
+
对应 `lang[..] = { prop:'tabs', name:<字段名>, type:'input', content:{ Cn, Us, Tw, default } }`。
|
|
285
|
+
- `--tabs` 未列出的字段会**自动归入末尾的「其它」页**;未提供 `--tabs` 时全部字段进单个「其它」页。
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
llc form create --name 复杂表单 --app-id <appId> --layout tabs \
|
|
289
|
+
--tabs "基本信息:fd_col_a,fd_col_b|金额信息:fd_col_c,fd_col_d" \
|
|
290
|
+
--add-field "fd_col_a:姓名" --add-field "fd_col_b:部门" \
|
|
291
|
+
--add-field "fd_col_c:金额:number" --add-field "fd_col_d:日期:timestamp" \
|
|
292
|
+
--publish
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 字段权限(必填 / 可见 / 只读)
|
|
296
|
+
|
|
297
|
+
对应控件属性面板的「字段权限」(各控件 `config.json` 的
|
|
298
|
+
`controlGroup > fieldPermission > { required, editable, visible }`),
|
|
299
|
+
落库位置是 `auth[0].{add|edit|view}[表名].fields[字段名]`:
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
{ "visible": true, "editable": true, "required": false, "hide": false }
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
快捷参数:
|
|
306
|
+
|
|
307
|
+
| 参数 | 写入 |
|
|
308
|
+
|---|---|
|
|
309
|
+
| `--required <fields>` | `add` / `edit` 的 `required: true` |
|
|
310
|
+
| `--readonly <fields>` | `add` / `edit` 的 `editable: false` |
|
|
311
|
+
| `--hidden <fields>` | `add` / `edit` / `view` 的 `visible: false` |
|
|
312
|
+
|
|
313
|
+
精细控制用 `--auth-file`:
|
|
314
|
+
|
|
315
|
+
```json
|
|
316
|
+
{
|
|
317
|
+
"add": { "fd_col_a": { "required": true } },
|
|
318
|
+
"edit": { "fd_col_b": { "visible": false }, "fd_col_c": { "editable": false } },
|
|
319
|
+
"view": { "fd_col_d": { "visible": false } }
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
> 注意:`--required` 写入的是**权限**(`auth`),不是数据项本身。
|
|
324
|
+
> 数据项的「是否显示」是 `fdDisplay`,本 CLI 默认只把业务字段渲染成控件,不写 `fdDisplay`。
|
|
325
|
+
|
|
326
|
+
### 多语言
|
|
327
|
+
|
|
328
|
+
表单标题、控件提示等文案统一存放在 `fdConfig.lang` 中,key 形如 `!{mv0dg6b08kjn1fost7o}`。
|
|
329
|
+
|
|
330
|
+
#### 1. messageKey 格式(重要)
|
|
331
|
+
|
|
332
|
+
前端识别多语言标记的正则是 `/\!\{([\w\.]*)\}/gi`,`\w` = `[A-Za-z0-9_]`,**不含连字符**。
|
|
333
|
+
key 主体必须与前端 `sys-xform/src/util/runtimeUtil.ts#uuid` 一致:
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
Date.now().toString(36) + Math.random().toString(36).slice(2) // 纯 base36
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
CLI 已按此实现(`src/utils/random.ts#generateMessageKey`),并对历史非法 key 自动重建。
|
|
340
|
+
|
|
341
|
+
#### 2. 语言解析顺序
|
|
342
|
+
|
|
343
|
+
`sys-xform/src/components/runtime/utils.ts` 的规则是 `content[当前语言] → content['Cn']`。
|
|
344
|
+
因此只写 `Cn` 时任何语言的用户都能看到中文兜底;要展示真实翻译需显式开启多语言。
|
|
345
|
+
|
|
346
|
+
#### 3. 用法
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
# 只写中文(默认)
|
|
350
|
+
llc form create --name 请假单 --type general
|
|
351
|
+
|
|
352
|
+
# 同时写入 简体/英文/繁体(两者等价)
|
|
353
|
+
llc form create --name 请假单 --type general --locale Cn,Us,Tw
|
|
354
|
+
llc form create --name 请假单 --type general --locale all
|
|
355
|
+
|
|
356
|
+
# 提供真实翻译
|
|
357
|
+
llc form create --name 请假单 --type general --locale Cn,Us --lang-file ./lang.json
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
`lang.json` 结构:
|
|
361
|
+
|
|
362
|
+
```json
|
|
363
|
+
{
|
|
364
|
+
"Us": { "姓名": "Name", "金额": "Amount", "请输入": "Please enter" },
|
|
365
|
+
"Tw": { "金额": "金額" }
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
非主语言的取值优先级:
|
|
370
|
+
|
|
371
|
+
| 顺序 | 来源 | 说明 |
|
|
372
|
+
|---|---|---|
|
|
373
|
+
| 1 | `--lang-file` | 用户翻译,按「字段标题」再按「字段物理名」匹配 |
|
|
374
|
+
| 2 | 控件自带译文 | 从控件多语言资源接口取(如英文 placeholder `Please enter`) |
|
|
375
|
+
| 3 | 主语言文案 | 兜底,与前端 `ide-model/business/input/inputLocale.tsx` 行为一致 |
|
|
376
|
+
|
|
377
|
+
第 3 条保证不会出现空白标题;语言码大小写自动归一(`us` / `US` → `Us`)。
|
|
378
|
+
`--locale` / `--lang-file` 同样适用于 `llc form autofill`。
|
|
379
|
+
|
|
380
|
+
#### 4. 覆盖范围
|
|
381
|
+
|
|
382
|
+
| `lang[].prop` | 对应文案 | 是否由 CLI 生成 |
|
|
383
|
+
|---|---|---|
|
|
384
|
+
| `label` | 字段标题 | 是 |
|
|
385
|
+
| `placeholder` | 控件输入提示 | 是 |
|
|
386
|
+
| `option` | 下拉 / 单选 / 多选的**选项文案** | 是(已有选项时完善) |
|
|
387
|
+
|
|
388
|
+
选项多语言的落库结构(与真实环境数据一致):
|
|
389
|
+
|
|
390
|
+
```
|
|
391
|
+
lang["!{xxx}"] = { prop:'option', name:<fdName>, type:'input', content:{ Cn:'选项1' } }
|
|
392
|
+
fdAttribute…controlProps.options[] = { label:'!{xxx}', value:'1' }
|
|
393
|
+
fdFontExtendData.options[] = { messageKey:'!{xxx}', label:'选项1', value:'1', … }
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
要点:
|
|
397
|
+
|
|
398
|
+
- **选项必须先存在**。CLI 不会凭空创建选项;选项由数据项管理 / 设计器 / Excel 导入向导配置,
|
|
399
|
+
CLI 负责把它们的文案补成多语言(并保留 `colorSwitch`、`type`、`value` 等原有字段)。
|
|
400
|
+
- **数据字典选项会被跳过**。`messageKey` 形如 `${sys-xform:enum.X}` / `sys-xform:enum.X`
|
|
401
|
+
的选项走平台静态多语言资源,写入 `lang` 反而会污染,因此原样保留。
|
|
402
|
+
- 选项的 `--lang-file` 匹配支持两种 key:**选项文案**(如 `选项1`)与
|
|
403
|
+
**`字段名#选项值`**(如 `fd_col_x#2`,用于多个选项文案重复时的精确匹配)。
|
|
404
|
+
|
|
405
|
+
### 控件动作(onChange / onLoad 等)
|
|
406
|
+
|
|
407
|
+
许多控件支持配置动作。动作存放于 `fdConfig.attribute.formAttr.controlAction`(真实表单结构已核对):
|
|
408
|
+
|
|
409
|
+
```
|
|
410
|
+
controlAction.control['<表名>.<控件uuid>'][<事件>] = [{ name, id, function }]
|
|
411
|
+
controlAction.global[<事件>] = [{ name, id, function }]
|
|
412
|
+
controlAction.javascript = 所有函数源码拼接(设计器 JS 面板按此展示)
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
`function` 是**函数源码字符串**,运行时经
|
|
416
|
+
`new Function('MKXFORM', 'return (' + source + ')')` 求值后挂到控件的
|
|
417
|
+
`controlProps.controlActions[事件]`(`sys-xform/src/components/runtime/business/action.ts`)。
|
|
418
|
+
|
|
419
|
+
#### 1. 两种写法
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
# 内联源码(可重复)
|
|
423
|
+
llc form autofill --id <fdId> --apply --publish \
|
|
424
|
+
--action "fd_col_a:onChange:function onChange(value){ MKXFORM.setValue('fd_col_b', value) }"
|
|
425
|
+
|
|
426
|
+
# 复杂函数建议放 js 文件(@开头)
|
|
427
|
+
llc form autofill --id <fdId> --apply --publish --action "fd_col_a:onChange:@./on-change.js"
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
或用 JSON 文件(适合多条 / 全局动作):
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
llc form autofill --id <fdId> --apply --publish --action-file ./actions.json
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
`actions.json`:
|
|
437
|
+
|
|
438
|
+
```json
|
|
439
|
+
{
|
|
440
|
+
"fd_col_a": { "onChange": "function onChange(value){ … }" },
|
|
441
|
+
"$global": { "onLoad": "function onLoad(){ … }" }
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
也支持数组形式:`[{ "target": "fd_col_a", "event": "onChange", "source": "…", "name": "可选函数名" }]`。
|
|
446
|
+
|
|
447
|
+
#### 2. 规则与边界
|
|
448
|
+
|
|
449
|
+
| 项 | 说明 |
|
|
450
|
+
|---|---|
|
|
451
|
+
| 目标 | 字段物理名(`fd_col_a`);`$global` 为全局动作,仅支持 `onLoad` / `onBeforeSubmit` / `onAfterSubmit` |
|
|
452
|
+
| 控件级事件 | 任意标识符(`onChange` / `onFocus` / `onBlur`…),运行时按控件实际支持的事件触发 |
|
|
453
|
+
| 函数签名 | 控件级 `function onChange(value, rowNum)`(value 当前值,rowNum 明细行号);运行时闭包内可用 `MKXFORM`(如 `MKXFORM.setValue('表名.字段名', v)`) |
|
|
454
|
+
| key | `表名.控件uuid`(与运行时 `addActionToControlProps` 的查找规则一致);明细表字段同样适用 |
|
|
455
|
+
| 函数重名 | 自动追加随机后缀(与前端 `mergeControlAction` 行为一致) |
|
|
456
|
+
| 函数命名 | 控件级动作禁止裸事件名(`onChange` 等)——CLI 自动规范为 `onChange_<控件id>` 并同步重写函数源码声明;`$global` 全局动作保持裸事件名(如 `onLoad`) |
|
|
457
|
+
| 目标字段不存在 | 跳过并告警,不阻断 |
|
|
458
|
+
| 已有动作 | **保留**。`autofill` 会加载已有 `formAttr` 合并写入,不会清掉设计器里配置的动作/表单规则 |
|
|
459
|
+
|
|
460
|
+
`form create` 同样支持 `--action` / `--action-file`。
|
|
461
|
+
|
|
462
|
+
### 查询环境语言
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
llc locale list
|
|
466
|
+
llc locale list --element @elem/xform-select --json
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
数据源是控件多语言资源接口 `POST {baseUrl}/sys-lang/getFrontResource`
|
|
470
|
+
(`path=sys/artifact/elements/i18n`),其响应的 `data[0].data` 按**原始语言码**(`zh-cn`)分组:
|
|
471
|
+
|
|
472
|
+
```
|
|
473
|
+
环境为「@elem/xform-input」提供的语言(共 1 个)
|
|
474
|
+
zh-cn -> Cn 请输入
|
|
475
|
+
可直接用于 --locale 的取值
|
|
476
|
+
Cn
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
用途是回答「**哪些语言有现成译文**」——这些语言在 `--locale` 里能自动填上真实译文(如英文 placeholder)。
|
|
480
|
+
环境**配置的**语言全集(前端 `mk.getUserConfig('allLocales')`)未暴露后端接口,如需其它语言请直接 `--locale` 指定。
|
|
481
|
+
|
|
482
|
+
### 控件必填属性校验(发布前)
|
|
483
|
+
|
|
484
|
+
CLI 在 `form create` / `form autofill` 保存前会校验**控件必填属性值**,规则对齐设计器
|
|
485
|
+
(`formBuilderHelper` 必填规则 + 发布时 `validates.validating()` 阻断):
|
|
486
|
+
|
|
487
|
+
- 校验对象:控件 `config.json` 属性面板中满足
|
|
488
|
+
`required && !disabled && !protected && !slotScope` 的**叶子属性项**;
|
|
489
|
+
- 值为空(`undefined/null/''/空数组`)即报错,格式 `请输入<label>(key)`;
|
|
490
|
+
- 与设计器一致地跳过:带 `enableWhen`/`hidden` 的条件渲染项(未渲染不校验)、
|
|
491
|
+
分组容器(baseGroup/styleGroup 等)、`inputLocale` 类标题项(取 `title` 值);
|
|
492
|
+
- 校验失败默认**中止保存/发布**(预览模式仅提示);加 `--force` 可跳过。
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
llc form autofill --id <fdId> --apply --publish # 校验失败会中止
|
|
496
|
+
llc form autofill --id <fdId> --apply --publish --force # 跳过校验
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**必填属性兜底默认值**:部分控件声明了必填属性但无默认值(设计器中靠用户填写),
|
|
500
|
+
CLI 按 `src/constants.ts#REQUIRED_PROP_DEFAULTS` 自动补齐,
|
|
501
|
+
取值来自设计器创建表单的实测值或控件约定:
|
|
502
|
+
|
|
503
|
+
| 控件 | 属性 | 默认值 |
|
|
504
|
+
|---|---|---|
|
|
505
|
+
| textarea | height | `"3"`(3 行,设计器实测) |
|
|
506
|
+
| address | org / multi | `{"orgTypeArr":["8"],…}` / `false`(设计器实测) |
|
|
507
|
+
| rate | max | `5` |
|
|
508
|
+
| slider | min / max | `0` / `100` |
|
|
509
|
+
| rich-text | height | `300`(config.json min 200) |
|
|
510
|
+
| bar-code | height | `80` |
|
|
511
|
+
| hyperlinks | largestSet | `"infinit"`(选项首项) |
|
|
512
|
+
|
|
513
|
+
例外:`upcasing.relationControl`(联动控件)是语义性选择,CLI 不兜底;
|
|
514
|
+
未指定时校验会拦截,需显式给出(存于 `fdFontExtendData.relationControl = {fdName, fdLabel}`)。
|
|
515
|
+
|
|
516
|
+
**条件必填**:带 `enableWhen` 的属性项按条件判定——条件为「键 = 简单值」且在 `controlProps` 中成立时才校验
|
|
517
|
+
(如 datetime 的 `defaultValueType='formula'` 时公式配置 `defaultValueFormulaVO` 必填);
|
|
518
|
+
条件不成立或为复杂表达式时跳过,与设计器一致。
|
|
519
|
+
|
|
520
|
+
**初始值模式**:新建字段 `defaultValueType` 默认为 `null`(无初始值),与控件 `config.json` 默认一致;
|
|
521
|
+
不要写 `formula`——公式模式下 `defaultValueFormulaVO` 必填,设计器提交会被拦截。
|
|
522
|
+
若需要公式初始值,按以下结构写入 `fdFontExtendData`(迁移自前端 `dataMigration.ts`):
|
|
523
|
+
|
|
524
|
+
```json
|
|
525
|
+
{
|
|
526
|
+
"defaultValueType": "formula",
|
|
527
|
+
"defaultValueFormulaVO": { "script": "\"2026-01-01\"", "type": "Eval", "vo": { "mode": "formula", "content": "2026-01-01" } }
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
另:`labelProps.layout` 默认写入 `horizontal`(左右布局)、`labelTextAlign: 'left'`;
|
|
531
|
+
如需上下布局可在生成后调整或后续提供选项。
|
|
532
|
+
|
|
533
|
+
### 自动完善表单字段
|
|
534
|
+
|
|
535
|
+
> **布局保护**:`autofill` 不带 `--layout` 时会**沿用已有视图**——设计器里的栅格布局、
|
|
536
|
+
> 多页签等布局不会被动过;同时保留已配置的控件动作(`controlAction`)与表单规则。
|
|
537
|
+
> 显式传入 `--layout`(如 `--layout grid --grid-columns 3`)才会按参数重建布局。
|
|
538
|
+
> 通过 `--add-field` 新增的字段不在旧布局中,保存时会告警提示,需显式 `--layout` 才会展示。
|
|
539
|
+
|
|
540
|
+
```bash
|
|
541
|
+
# 预览(不写入)
|
|
542
|
+
llc form autofill --id <fdId>
|
|
543
|
+
|
|
544
|
+
# 确认后写入
|
|
545
|
+
llc form autofill --id <fdId> --apply
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
`autofill` 支持与 `create` 相同的 `--add-field` / `--include-system` / `--icon` / `--fields` / `--per-row` / `--span` 选项,
|
|
549
|
+
同样会重建每个字段的 `fdAttribute.config`、`view.controlMappings` 与多语言(`lang`)。
|
|
550
|
+
|
|
551
|
+
> `saveDesign` 会把表单置为**草稿态**。修复已发布表单时请加 `--publish`(`modeling` 族会走 `saveDesignAndPublish`)。
|
|
552
|
+
> 不加 `--publish` 且原状态为 `official` 时会给出提示。
|
|
553
|
+
它会先尝试 `sysModelingXForm/loadBase`,命中则按 `modeling` 族处理;否则读取表单的 `fdFormDefineType` 自动在 `general` / `design` 之间选择。
|
|
554
|
+
|
|
555
|
+
> 若表单是早期版本 CLI 生成的(缺少 `fdAttribute.config` / 渲染节点不是 `{key}` 引用),
|
|
556
|
+
> 执行一次 `llc form autofill --id <fdId> --apply` 即可修复为可加载格式。
|
|
557
|
+
|
|
558
|
+
### 其他
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
llc app list [--keyword <name>]
|
|
562
|
+
llc form list [--keyword <kw>]
|
|
563
|
+
llc form get --id <fdId> [--with-config]
|
|
564
|
+
llc form publish --id <fdId> [--api modeling|general|design] [--desc <说明>]
|
|
565
|
+
llc form category-list
|
|
566
|
+
llc config show | set | clear
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## 四、调用的后台接口
|
|
570
|
+
|
|
571
|
+
| 功能 | 接口 |
|
|
572
|
+
|---|---|
|
|
573
|
+
| 控件多语言资源(语言探测) | `POST sys-lang/getFrontResource` |
|
|
574
|
+
| 应用新建(含默认首页) | `POST sys-modeling/sysModelingApplication/add` |
|
|
575
|
+
| 应用编辑页数据 | `POST sys-modeling/sysModelingApplication/edit` |
|
|
576
|
+
| 应用修改 | `POST sys-modeling/sysModelingApplication/update` |
|
|
577
|
+
| 应用删除 | `POST sys-modeling/sysModelingApplication/delete` |
|
|
578
|
+
| 应用业务数据删除 | `POST sys-modeling/sysModelingApplication/deleteData` |
|
|
579
|
+
| 表单删除 | `POST sys-modeling/sysModelingXForm/delete` |
|
|
580
|
+
| 表单业务数据删除 | `POST sys-modeling/sysModelingXForm/deleteData` |
|
|
581
|
+
| 【modeling 族】生成主表名 | `POST sys-modeling/sysModelingXForm/generateTableName` |
|
|
582
|
+
| 【modeling 族】检查表名 | `POST sys-modeling/sysModelingXForm/checkTableNameExist` |
|
|
583
|
+
| 【modeling 族】检查表单名 | `POST sys-modeling/sysModelingXForm/checkXFormNameExist` |
|
|
584
|
+
| 【modeling 族】表单新建 | `POST sys-modeling/sysModelingXForm/create` |
|
|
585
|
+
| 【modeling 族】保存设计 | `POST sys-modeling/sysModelingXForm/saveDesign` |
|
|
586
|
+
| 【modeling 族】保存并发布 | `POST sys-modeling/sysModelingXForm/saveDesignAndPublish` |
|
|
587
|
+
| 【modeling 族】发布 | `POST sys-modeling/sysModelingXForm/publish` |
|
|
588
|
+
| 【modeling 族】加载设计 | `POST sys-modeling/sysModelingXForm/loadDesign` |
|
|
589
|
+
| 【modeling 族】加载基本信息 | `POST sys-modeling/sysModelingXForm/loadBase` |
|
|
590
|
+
| 【modeling 族】应用列表 | `POST sys-modeling/sysModelingApplication/list` |
|
|
591
|
+
| 【modeling 族】应用列表(免权限) | `POST sys-modeling/sysModelingApplication/listNotAuth` |
|
|
592
|
+
| 【general 族】表单初始化 | `POST sys-xform/generalFormDefine/init` |
|
|
593
|
+
| 【general 族】表单新建 | `POST sys-xform/generalFormDefine/add` |
|
|
594
|
+
| 【general 族】表单加载 | `POST sys-xform/generalFormDefine/get` |
|
|
595
|
+
| 【general 族】表单保存 | `POST sys-xform/generalFormDefine/save` |
|
|
596
|
+
| 【general 族】表单发布 | `POST sys-xform/generalFormDefine/publish` |
|
|
597
|
+
| 【general 族】表单列表 | `POST sys-xform/generalFormDefine/list` |
|
|
598
|
+
| 【design 族】表单新建 | `POST sys-xform/sysXFormDesign/create` |
|
|
599
|
+
| 【design 族】表单加载 | `POST sys-xform/sysXFormDesign/load` |
|
|
600
|
+
| 【design 族】表单保存 | `POST sys-xform/sysXFormDesign/save` |
|
|
601
|
+
| 【design 族】表单发布 | `POST sys-xform/sysXFormDesign/publish` |
|
|
602
|
+
| 表单分类列表 | `POST sys-xform/generalFormCategory/list` |
|
|
603
|
+
| 表单数据模型(字段) | `POST sys-xform/sysXFormDataModel/loadByFormId` |
|
|
604
|
+
| 数据模型字段 | `POST sys-xform/sysXFormDataModel/getModelFields` |
|
|
605
|
+
| 数据模型(按 id) | `POST sys-xform/sysXFormDataModel/load` |
|
|
606
|
+
| 主表名生成 | `POST sys-xform/sysXFormDataModel/generateTableName` |
|
|
607
|
+
| 外部表字段 | `POST sys-xform/sysXFormDataModelField/loadFieldMeta` |
|
|
608
|
+
| 字段库 | `POST sys-xform/sysXFormWordsField/list` |
|
|
609
|
+
| 字段编码生成 | `POST sys-xform/sysXFormWordsField/generateFdKey` |
|
|
610
|
+
|
|
611
|
+
## 五、生成的表单配置结构(`fdConfig`,**持久化格式**)
|
|
612
|
+
|
|
613
|
+
> ⚠️ 表单引擎有**两套格式**:IDE 内存中的 form-builder 树 ≠ 落库格式。
|
|
614
|
+
> CLI 必须生成后者,否则前端加载时控件无法还原。
|
|
615
|
+
|
|
616
|
+
**落库格式的关键点**(由 `sys-xform/components/ide/store/viewModel/view/pureUtils.ts#getRenderLayout` 决定):
|
|
617
|
+
|
|
618
|
+
1. `view.render.*` 中,**控件节点被折叠为 `{ key: <uuid> }`**(容器节点保留 `key/type/kind/controlProps/children`)。
|
|
619
|
+
2. 控件的真实定义放在 **`view.controlMappings`**(平台 → 控件包元数据)与**字段的 `fdAttribute.config`** 中。
|
|
620
|
+
3. 前端加载时 `cacheConfig[attr.uuid] = attr.config`,再按 `{ key }` 回填 —— **`fdAttribute` 缺失或结构不符,控件就会丢失**。
|
|
621
|
+
|
|
622
|
+
```jsonc
|
|
623
|
+
{
|
|
624
|
+
"dataModel": [
|
|
625
|
+
{
|
|
626
|
+
"fdTableName": "mk_model_xxx",
|
|
627
|
+
"fdType": "main",
|
|
628
|
+
"fdFields": [
|
|
629
|
+
{
|
|
630
|
+
"fdName": "fd_col_text01",
|
|
631
|
+
"fdLabel": "单行文本",
|
|
632
|
+
"fdLabelLangKey": "!{...}",
|
|
633
|
+
"fdType": "text",
|
|
634
|
+
"fdDataType": "varchar",
|
|
635
|
+
"fdDictType": "textDict",
|
|
636
|
+
"fdLength": 200,
|
|
637
|
+
"fdIsSystem": false,
|
|
638
|
+
"fdDisplay": true,
|
|
639
|
+
"fdState": "effective",
|
|
640
|
+
"fdFontExtendData": "{\"passValue\":false,\"trace\":false,\"encrypt\":false,\"defaultValueType\":\"formula\",\"encryptDefinition\":{}}",
|
|
641
|
+
// ↓ 关键:控件配置唯一来源
|
|
642
|
+
"fdAttribute": "{\"uuid\":\"fd_col_text01\",\"env\":[\"xform\"],\"config\":{\"key\":\"@elem/xform-input~xxxxxx\",\"type\":\"text\",\"kind\":\"control\",\"label\":\"!{...}\",\"controlProps\":{\"aiFill\":false,\"showText\":false,\"passValue\":false,\"trace\":false,\"encrypt\":false,\"defaultValueType\":\"formula\",\"placeholder\":\"!{...}\",\"maskFormatType\":\"********\",\"encryptMonth\":9999,\"failureRule\":\"ANONYMIZE\",\"id\":\"@elem/xform-input~xxxxxx\",\"desktop\":{\"type\":\"@elem/xform-input\"},\"mobile\":{\"type\":\"@elem/xform-m-input\"},\"name\":\"fd_col_text01\",\"uuid\":\"fd_col_text01\",\"title\":\"!{...}\",\"span\":12,\"$$tableType\":\"main\",\"$$tableName\":\"mk_model_xxx\",\"maxLength\":200},\"labelProps\":{\"desktop\":{},\"mobile\":{},\"title\":\"!{...}\",\"showText\":false,\"trace\":false}}}"
|
|
643
|
+
}
|
|
644
|
+
]
|
|
645
|
+
}
|
|
646
|
+
],
|
|
647
|
+
"auth": [ /* 新增/编辑/查看 权限(按表按字段) */ ],
|
|
648
|
+
"attribute": { "formAttr": "{\"subjectRule\":{\"type\":\"Eval\",\"script\":\"${data.biz.fd_doc_subject}\",\"vo\":{\"mode\":\"formula\",\"content\":\"$<模型名>.<标题>$\"}},\"formRule\":{\"pattern\":{}},\"dataUnique\":{},\"controlAction\":{},\"currentTableName\":\"<主表名>\"}" },
|
|
649
|
+
"error": "{}",
|
|
650
|
+
"lang": "{ \"!{labelKey}\": {\"prop\":\"label\",\"name\":\"fd_col_text01\",\"type\":\"input\",\"content\":{\"Cn\":\"单行文本\"}}, \"!{phKey}\": {\"prop\":\"placeholder\",...} }",
|
|
651
|
+
"authFilter": { "detailAuthDefine": {} },
|
|
652
|
+
"extendMap": {},
|
|
653
|
+
"sign": { "formula": {} },
|
|
654
|
+
"viewModel": [
|
|
655
|
+
{
|
|
656
|
+
"fdCode": "SCENE_DEFAULT",
|
|
657
|
+
"fdName": "默认",
|
|
658
|
+
"fdStatus": "draft",
|
|
659
|
+
"fdLockMode": "none",
|
|
660
|
+
"fdOrder": 0,
|
|
661
|
+
"dynamicProps": {},
|
|
662
|
+
"needDelete": false,
|
|
663
|
+
// ↑ 同样是 JSON 字符串
|
|
664
|
+
"fdConfig": "{\"view\":{\"render\":{\"desktop\":[{\"key\":\"@elem/xform-appearance\",\"type\":\"@elem/xform-appearance\",\"kind\":\"container\",\"controlProps\":{\"$$tableName\":\"mk_model_xxx\"},\"children\":[{\"key\":\"main\",\"type\":\"main\",\"kind\":\"container\",\"children\":[{\"key\":\"@elem/xform-row~xxxxxx\",\"type\":\"@elem/xform-row\",\"kind\":\"container\",\"controlProps\":{\"id\":\"@elem/xform-row~xxxxxx\",\"spans\":[12]},\"children\":[{\"key\":\"fd_col_text01\"}]}]}]}],\"mobile\":[...]},\"controlMappings\":{\"desktop\":[{\"name\":\"@elem/xform-input\",\"platform\":\"desktop\",\"xform\":{\"type\":\"text\",\"dataType\":\"varchar\",\"dictType\":\"textDict\",\"span\":12,\"env\":[\"xform\"],...}}],\"mobile\":[{\"name\":\"@elem/xform-m-input\",...}]}},\"theme\":{\"desktop\":{\"name\":\"default\",\"status\":\"done\",\"viewAttr\":{...}},\"mobile\":{...}},\"controlStyle\":{\"fd_col_text01\":{\"desktop\":{...}}}}"
|
|
665
|
+
}
|
|
666
|
+
]
|
|
667
|
+
}
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
要点:
|
|
671
|
+
- 外层 `fdConfig`、内层 `viewModel[].fdConfig`、`lang`、`error` 都是 JSON **字符串**。
|
|
672
|
+
- 渲染树为 `@elem/xform-appearance` → `main` → `@elem/xform-row` → `{ key: <uuid> }`。
|
|
673
|
+
- 系统字段(`fdIsSystem: true`)默认**不渲染**到表单上,可用 `--include-system` 打开。
|
|
674
|
+
- `id/name/tableName/entityName/entityCode` 会被后端 `DesginConfigVO` 丢弃,前端加载 IDE 时从 VO 回填(正常行为)。
|
|
675
|
+
|
|
676
|
+
### 新增字段
|
|
677
|
+
|
|
678
|
+
```bash
|
|
679
|
+
llc form create --name 请假单 --app-id <appId> --add-field "fd_col_text01:单行文本" --publish
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
`--add-field` 格式:`name:label[:dataType[:controlType]]`,可重复。只给 label 时自动生成 `fd_col_xxxxxx`。
|
|
683
|
+
字段会写入 `dataModel[].fdFields`,发布时由后端创建真实数据库列。
|
|
684
|
+
|
|
685
|
+
## 六、控件元数据与类型映射
|
|
686
|
+
|
|
687
|
+
控件类型/字典类型/默认长度/默认属性等**不来自静态映射表**,而是运行时读取控件包的 `config.json`:
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
{origin}/web/sys/artifact/elements/{pkg}/config.json
|
|
691
|
+
例:http://host/web/sys/artifact/elements/xform-input/config.json
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
CLI 会按需拉取并缓存到 `~/.llc/widgets-cache.json`。从中获取:
|
|
695
|
+
- `xform`:`type/dataType/dictType/defaultLength/span/order/kind/for/isStored/...`
|
|
696
|
+
- `env`:运行环境(`["xform"]`)
|
|
697
|
+
- `config[].default`:控件默认属性(`aiFill/showText/passValue/encrypt/maskFormatType/encryptMonth/failureRule` 等)
|
|
698
|
+
|
|
699
|
+
`placeholder` 通过 `POST {baseUrl}/sys-lang/getFrontResource`(key 约定 `{pkg}###langs###placeholder`)获取并写入 `lang`。
|
|
700
|
+
|
|
701
|
+
内置的 `fdDataType → 控件包` 入口映射(见 `src/constants.ts`),可通过项目级 `lcode.config.json` 覆盖:
|
|
702
|
+
|
|
703
|
+
```json
|
|
704
|
+
{
|
|
705
|
+
"baseUrl": "http://mkdev01.ywork.me/data",
|
|
706
|
+
"controlMap": {
|
|
707
|
+
"clob": {
|
|
708
|
+
"desktop": "@elem/xform-rich-text",
|
|
709
|
+
"mobile": "@elem/xform-m-rich-text",
|
|
710
|
+
"logicalType": "rich-text"
|
|
711
|
+
},
|
|
712
|
+
"myType": {
|
|
713
|
+
"desktop": "@elem/xform-custom",
|
|
714
|
+
"mobile": "@elem/xform-m-custom",
|
|
715
|
+
"logicalType": "custom"
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
| fdDataType | desktop 控件 | mobile 控件 | logicalType |
|
|
722
|
+
|---|---|---|---|
|
|
723
|
+
| varchar | `@elem/xform-input` | `@elem/xform-m-input` | text |
|
|
724
|
+
| number | `@elem/xform-number` | `@elem/xform-m-number` | numbertext |
|
|
725
|
+
| boolean | `@elem/xform-switch` | `@elem/xform-m-switch` | switch |
|
|
726
|
+
| timestamp | `@elem/xform-datetime` | `@elem/xform-m-datetime` | timestamp |
|
|
727
|
+
| address | `@elem/xform-address` | `@elem/xform-m-address` | address |
|
|
728
|
+
| attach | `@elem/xform-attachment` | `@elem/xform-m-attachment` | attachment |
|
|
729
|
+
| clob | `@elem/xform-textarea` | `@elem/xform-m-textarea` | textarea |
|
|
730
|
+
| relation | `@elem/xform-relation` | `@elem/xform-m-relation` | relation |
|
|
731
|
+
|
|
732
|
+
> 输出约定:除 `--json` 的结果外,所有日志/表格输出到 **stderr**,便于 `llc ... --json > out.json`。
|
|
733
|
+
|
|
734
|
+
## 七、目录结构
|
|
735
|
+
|
|
736
|
+
```
|
|
737
|
+
low-code-cli/
|
|
738
|
+
├── bin/llc.js # 可执行入口
|
|
739
|
+
├── src/
|
|
740
|
+
│ ├── index.ts # commander 入口与命令注册
|
|
741
|
+
│ ├── client.ts # HTTP 客户端(fetch + X-AUTH-TOKEN)
|
|
742
|
+
│ ├── config.ts # 配置解析与持久化
|
|
743
|
+
│ ├── constants.ts # 表单类型 / 控件映射常量
|
|
744
|
+
│ ├── types.ts # 类型定义(对齐后端 DTO)
|
|
745
|
+
│ ├── widgets.ts # 控件元数据注册表(拉取 config.json + 控件多语言,落盘缓存)
|
|
746
|
+
│ ├── api/formDefine.ts # 后台接口封装(modeling / general / design 三族)
|
|
747
|
+
│ ├── generator/index.ts # 表单配置生成器(自动完善字段核心)
|
|
748
|
+
│ ├── commands/ # config / app / form / field 子命令
|
|
749
|
+
│ └── utils/ # 日志与工具函数
|
|
750
|
+
└── package.json
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
## 八、常见问题(前端报错)
|
|
754
|
+
|
|
755
|
+
### 进入表单编辑器报 `SyntaxError: "undefined" is not valid JSON`
|
|
756
|
+
|
|
757
|
+
**原因**:`sys-modeling` 表单编辑页存在如下写法(`manage/pages/sysModelingForm/edit/content.tsx`):
|
|
758
|
+
|
|
759
|
+
```ts
|
|
760
|
+
fdIcon: JSON.parse(`${fdIcon}` || '{}')
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
当 `fdIcon` 为 `undefined` 时,`` `${fdIcon}` `` 会得到**真值字符串 `"undefined"`**,`|| '{}'` 兜底失效 →
|
|
764
|
+
`JSON.parse("undefined")` 抛错;而 `init()` 是 async 且未被 await/catch → `Uncaught (in promise)`。
|
|
765
|
+
|
|
766
|
+
**修复**:
|
|
767
|
+
|
|
768
|
+
- 新建:CLI 已默认写入图标,无需处理;
|
|
769
|
+
- 已有表单:执行一次 `llc form autofill --id <fdId> --apply`(会自动补默认图标),
|
|
770
|
+
或 `llc form autofill --id <fdId> --icon <图标名> --apply` 指定图标。
|
|
771
|
+
|
|
772
|
+
> 图标必须写入 `modeling_xform` 镜像表,所以走 `sysModelingXForm/saveBase`(`saveDesign` 只写表单引擎表,不生效)。
|
|
773
|
+
|
|
774
|
+
### 界面上标题/提示显示成 `!{46573e93-82ef-4def-b184-33f74b2681e6}` 这类原文
|
|
775
|
+
|
|
776
|
+
**原因**:多语言 messageKey 的格式不合法。
|
|
777
|
+
|
|
778
|
+
前端识别多语言标记统一使用正则 `/\!\{([\w\.]*)\}/gi`
|
|
779
|
+
(`sys-xform/src/components/ide/store/i18n/syncApi.ts#isCustomI18n`、`components/runtime/utils.ts`),
|
|
780
|
+
`\w` = `[A-Za-z0-9_]`,**不包含连字符 `-`**。
|
|
781
|
+
若用 RFC4122 UUID(带 `-`)作 key,`isCustomI18n()` 判定为 false,前端就不会做替换,直接原样显示。
|
|
782
|
+
|
|
783
|
+
正确的 key 由前端 `sys-xform/src/util/runtimeUtil.ts#uuid` 生成:
|
|
784
|
+
|
|
785
|
+
```ts
|
|
786
|
+
Date.now().toString(36) + Math.random().toString(36).slice(2) // 纯 base36,形如 mv0dg6b08kjn1fost7o
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
**修复**:CLI 已按上式生成 key(`src/utils/random.ts#generateMessageKey`),
|
|
790
|
+
并会对「不符合 `[\w.]` 的历史 key」自动重建。
|
|
791
|
+
|
|
792
|
+
- 新建:无需处理;
|
|
793
|
+
- 已有表单:`llc form autofill --id <fdId> --apply --publish`。
|
|
794
|
+
|
|
795
|
+
### 表单能打开但控件不显示 / 报“找不到默认视图”
|
|
796
|
+
|
|
797
|
+
一般是 `fdConfig` 结构不对(用了 IDE 内存格式而非落库格式),
|
|
798
|
+
执行 `llc form autofill --id <fdId> --apply` 重新生成即可(见第五章)。
|
|
799
|
+
|
|
800
|
+
## 九、参考源码
|
|
801
|
+
|
|
802
|
+
接口契约依据以下后端源码整理(非本仓库,仅供核对):
|
|
803
|
+
|
|
804
|
+
**`mk-sys-xform`(表单引擎)**
|
|
805
|
+
- `SysGeneralFormDefineService#beforeExecute`:`generalFormDefine` 仅接受 `fdFormDefineType=General`
|
|
806
|
+
- `SysXFormBaseDefineService#init`:生成 `fdId/fdEntityId/fdEntityName/fdRunEntityName/fdTableName`
|
|
807
|
+
- `SysXFormDesignController` / `SysXFormDesignService#voCreate`:表单引擎原始创建接口
|
|
808
|
+
- `FormDefineType`:表单类型枚举(1-6)
|
|
809
|
+
|
|
810
|
+
**`mk-sys-modeling`(业务建模/低代码应用)**
|
|
811
|
+
- `SysModelingXFormController#create/saveDesign/saveDesignAndPublish/publish/generateTableName`
|
|
812
|
+
- `SysModelingXFormService#create`:写死 `fdEntityId=表单id`、`fdEntityName=fdRunEntityName='sys-modeling'`,并按 `fdAppId` 归属应用
|
|
813
|
+
- `SysModelingApplication`(表 `modeling_application`):应用实体,`fdAppCode` 为 URL 段标识
|
|
814
|
+
- `SysModelingDataModelService#buildMainTableName`:`mk_model_yyyyMMdd` + 随机 5 位
|