lan-low-code-cli 2.2.0 → 2.3.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.
package/README.md CHANGED
@@ -25,6 +25,11 @@ pnpm link --global # 可选:全局注册 llc 命令
25
25
  > 请勿混用 npm/yarn,以免生成多余的 `package-lock.json` / `yarn.lock`。
26
26
  > 常用脚本:`pnpm build`、`pnpm typecheck`、`pnpm start`、`pnpm run rebuild`(clean + build,注意 `pnpm rebuild` 是 pnpm 内置命令,脚本需用 `pnpm run rebuild`)。
27
27
  > 非交互式 CI 可使用 `pnpm install --frozen-lockfile`。
28
+ >
29
+ > **打包分发**:`pnpm run pack`(`scripts/pack.js`,注意与 `rebuild` 一样要用 `run`,`pnpm pack` 是 pnpm 内置命令)把 CLI 与 skill 打成压缩包,输出到 `release/`(`dist/` 只放构建产物),
30
+ > 文件名拼接版本号:`lan-low-code-cli-<version>.tgz`、`lan-low-code-cli-skill-<version>.tgz`,
31
+ > 外加 `--with-deps` 的解压即用包(`-standalone`)。默认 tgz(npm 可直接 `npm i -g ./xxx.tgz`),
32
+ > `--format zip|both` 可切换;`--target cli|skill` 只打其一,`--list` 预览文件清单,`--no-build` 跳过构建。
28
33
 
29
34
  ## 二、鉴权与服务端地址
30
35
 
@@ -286,9 +291,11 @@ llc form autofill --id <fdId> --apply --add-field "fd_owner:责任人:address"
286
291
  `fdDictType=querySourceDict`、`fdLength=200`,核心配置在 `controlProps` 与 `fdFontExtendData`:
287
292
 
288
293
  ```
289
- controlProps.relationCfg = { appCode, xformName, modelId, tableName, showFields, refFieldName, fdFormType }
294
+ controlProps.relationCfg = { appCode, xformName, modelId, tableName, refFieldName, fdFormType }
295
+ // refFieldName 是 `$<字段名>$` 引用(如 `$fd_material_name$`),运行时解析为所选记录的显示值;
296
+ // 不能写成 `$<表名>.<字段名>$`(解析不到会把字面量显示出来),relationCfg 也没有 showFields 键
290
297
  controlProps.datasource = { columns:[{name,label}], queryCondition, tree, relationConditions }
291
- controlProps.outParams = { params:[{ sourceField:{fdName,tableName,tableType}, targetField:{…} }] }
298
+ controlProps.outParams = { params:[{ sourceField:{fdName,tableName,tableType}, targetField:{…} }] }(可选)
292
299
  controlProps.mappedType / multi / renderMode / direction / rowCount / isForwardView / modelId / modelName
293
300
  ```
294
301
 
@@ -334,7 +341,7 @@ llc form autofill --id <fdId> --apply \
334
341
  |---|---|---|
335
342
  | `字段名` | 目标字段物理名(主表或明细表字段,命中后自动改写为 `relation` 控件) | — |
336
343
  | `目标表单` | 表单名或 fdId;按名匹配到多份时优先当前表单所属应用,仍歧义则报错列出候选 | — |
337
- | `显示值=字段` | 存入 `relationCfg.refFieldName`/`showFields`(多项用逗号,写 `$字段名$`/`$标题$`) | 目标表首个文本类业务字段 |
344
+ | `显示值=字段` | 存入 `relationCfg.refFieldName`(写 `$字段名$`,多项用逗号拼接) | 目标表首个文本类业务字段 |
338
345
  | `显示项=字段1,字段2` | 存入 `datasource.columns`(设计器强制必填) | 目标表**全部**业务字段 |
339
346
 
340
347
  解析后会写入:`relationCfg`(业务对象)、`datasource`(数据源骨架 + 显示项 + 筛选项 + 树设置)、
@@ -207,7 +207,7 @@ function parseActionFile(file) {
207
207
  /** 打印业务关联解析结果(字段 → 业务对象、显示值、显示项数量) */
208
208
  function logRelations(specs) {
209
209
  for (const spec of specs) {
210
- logger_1.logger.info(` 业务关联:${spec.fieldName} → ${spec.target.xformName}(显示值 ${spec.showFields.replace(/\$/g, '')},` +
210
+ logger_1.logger.info(` 业务关联:${spec.fieldName} → ${spec.target.xformName}(显示值 ${spec.refFieldName.replace(/\$/g, '')},` +
211
211
  `显示项 ${spec.columns.length} 项:${spec.columns.map((c) => c.label).join('/')})`);
212
212
  }
213
213
  }
@@ -217,16 +217,21 @@ function resolveActions(opts) {
217
217
  const fromFile = parseActionFile(opts.actionFile);
218
218
  return [...specs, ...fromFile];
219
219
  }
220
- /** 加载已有表单的 formAttr / viewModel / lang(autofill 时用于合并保留) */
220
+ /** 加载已有表单的 attribute / formAttr / viewModel / lang(autofill 时用于合并保留) */
221
221
  async function loadPrevDesign(client, family, formId) {
222
222
  try {
223
223
  const vo = family === 'modeling'
224
224
  ? await formDefine_1.modelingXFormApi.loadDesign(client, formId)
225
225
  : await formDefine_1.formDefineApi.get(client, formId).catch(() => formDefine_1.designApi.load(client, formId));
226
226
  const cfg = typeof vo.fdConfig === 'string' ? JSON.parse(vo.fdConfig) : vo.fdConfig;
227
- const formAttr = cfg?.attribute?.formAttr;
227
+ // attribute 除 formAttr 外还有 dataUnique / subjectRule 等顶层键,整体保留
228
+ const attribute = cfg?.attribute;
229
+ const formAttr = attribute?.formAttr;
228
230
  const lang = cfg?.lang;
229
231
  return {
232
+ prevAttribute: attribute && typeof attribute === 'object'
233
+ ? JSON.stringify(attribute)
234
+ : undefined,
230
235
  prevFormAttr: typeof formAttr === 'string' ? formAttr : undefined,
231
236
  prevViewModel: Array.isArray(cfg?.viewModel) &&
232
237
  cfg.viewModel.length
@@ -1177,6 +1182,7 @@ function registerFormCommand(program) {
1177
1182
  actions: actionSpecs,
1178
1183
  relations: relationSpecs.length ? relationSpecs : undefined,
1179
1184
  prevFormAttr: prev.prevFormAttr,
1185
+ prevAttribute: prev.prevAttribute,
1180
1186
  prevViewModel: prev.prevViewModel,
1181
1187
  prevLang: prev.prevLang,
1182
1188
  });
@@ -1295,7 +1301,7 @@ function registerFormCommand(program) {
1295
1301
  }
1296
1302
  /** 按接口族发布表单 */
1297
1303
  async function doPublish(client, family, fdId, base, desc = '') {
1298
- logger_1.logger.step(`发布表单(${FAMILY_LABEL[family]}/publish)`);
1304
+ logger_1.logger.step(`发布表单(${FAMILY_LABEL[family]}/${family === 'modeling' ? 'saveDesignAndPublish' : 'publish'})`);
1299
1305
  if (family === 'general') {
1300
1306
  const fresh = await formDefine_1.formDefineApi.get(client, fdId);
1301
1307
  await formDefine_1.formDefineApi.publish(client, {
@@ -1307,9 +1313,15 @@ async function doPublish(client, family, fdId, base, desc = '') {
1307
1313
  });
1308
1314
  }
1309
1315
  else if (family === 'modeling') {
1310
- await formDefine_1.modelingXFormApi.publish(client, {
1316
+ // 必须走 saveDesignAndPublish:`sysModelingXForm/publish` 只把表单置为发布态,
1317
+ // 不会生成「前台默认视图」(默认列表视图 + 应用前台导航菜单)。
1318
+ // 版本/发布态由 saveDesignAndPublish 一并处理,故发布前先取回完整设计数据。
1319
+ const design = await formDefine_1.modelingXFormApi.loadDesign(client, fdId);
1320
+ await formDefine_1.modelingXFormApi.saveDesignAndPublish(client, {
1311
1321
  ...base,
1322
+ ...design,
1312
1323
  fdId,
1324
+ fdBuildNew: true,
1313
1325
  fdDescribe: desc,
1314
1326
  });
1315
1327
  }
package/dist/constants.js CHANGED
@@ -3,8 +3,8 @@
3
3
  * 常量定义:与 sys-xform 前端 util/constant.ts 中的约定保持一致。
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DEFAULT_MOBILE_THEME = exports.DEFAULT_DESKTOP_THEME = exports.DEFAULT_FORM_ICON_JSON = exports.DEFAULT_FORM_ICON = exports.FIELD_NAME_PREFIX = exports.LOCALE_PATTERN = exports.LOCALE_ALL = exports.LOCALES = exports.DEFAULT_LOCALE = exports.DEFAULT_SPAN = exports.OPTION_DICT_TYPE = exports.OPTION_CONTROL_TYPES = exports.DETAIL_CONTROL_DEFAULTS = exports.DETAIL_ROW_FLAGS = exports.DETAIL_OPERATIONS = exports.DETAIL_SYSTEM_FIELDS = exports.DETAIL_CONTROL = exports.CONTROL_DESIGNER_NOTES = exports.CONTROL_NOTE_WITHOUT_ERRORS = exports.RELATION_FRONT_EXTEND_PATHS = exports.CONTROL_DEFAULT_PROPS = exports.CONTROL_SEMANTIC_RULES = exports.PLACEHOLDER_LANG_KEY_CANDIDATES = exports.CONTROL_PLACEHOLDER_LANG_KEYS = exports.CONTAINER_CONTROL_TYPES = exports.CONTROL_TYPE_MAP = exports.FALLBACK_CONTROL = exports.DEFAULT_CONTROL_MAP = exports.ELEMENT_ARTIFACT_PREFIX = exports.DEFAULT_SCENE_NAME = exports.DEFAULT_SCENE_CODE = exports.MODELING_ENTITY_CODE = exports.MODELING_ENTITY_NAME = exports.ENTITY_CODE = exports.ENTITY_NAME = exports.MODULE = exports.REQUIRED_PROP_DEFAULTS = exports.I18N_PROP_TABS = exports.TAB_PANE_MOBILE = exports.TAB_PANE = exports.TABS_MOBILE = exports.TABS = exports.TAB_APPEARANCE_MOBILE = exports.TAB_APPEARANCE = exports.LAYOUT_GRID_ITEM = exports.LAYOUT_GRID = exports.LAYOUT = exports.ROW = exports.APPEARANCE = exports.MAIN = void 0;
7
- exports.DEFAULT_DETAIL_CONTROL_STYLE = exports.DEFAULT_CONTROL_STYLE = void 0;
6
+ exports.FIELD_NAME_PREFIX = exports.LOCALE_PATTERN = exports.LOCALE_ALL = exports.LOCALES = exports.DEFAULT_LOCALE = exports.DEFAULT_SPAN = exports.OPTION_DICT_TYPE = exports.OPTION_CONTROL_TYPES = exports.DETAIL_CONTROL_DEFAULTS = exports.DETAIL_MAIN_FIELD_BASE = exports.DETAIL_MAIN_FIELD_OPERATIONS = exports.DETAIL_ROW_FLAGS = exports.DETAIL_OPERATIONS = exports.DETAIL_SYSTEM_FIELDS = exports.DETAIL_CONTROL = exports.CONTROL_DESIGNER_DEFAULTS = exports.CONTROL_DESIGNER_NOTES = exports.CONTROL_NOTE_WITHOUT_ERRORS = exports.RELATION_FRONT_EXTEND_PATHS = exports.CONTROL_DEFAULT_PROPS = exports.CONTROL_SEMANTIC_RULES = exports.PLACEHOLDER_PANEL_PKGS = exports.PLACEHOLDER_LANG_KEY_CANDIDATES = exports.CONTROL_PLACEHOLDER_LANG_KEYS = exports.CONTAINER_CONTROL_TYPES = exports.CONTROL_TYPE_MAP = exports.FALLBACK_CONTROL = exports.DEFAULT_CONTROL_MAP = exports.ELEMENT_ARTIFACT_PREFIX = exports.DEFAULT_SCENE_NAME = exports.DEFAULT_SCENE_CODE = exports.MODELING_ENTITY_CODE = exports.MODELING_ENTITY_NAME = exports.ENTITY_CODE = exports.ENTITY_NAME = exports.MODULE = exports.REQUIRED_PROP_DEFAULTS = exports.I18N_PROP_TABS = exports.TAB_PANE_MOBILE = exports.TAB_PANE = exports.TABS_MOBILE = exports.TABS = exports.TAB_APPEARANCE_MOBILE = exports.TAB_APPEARANCE = exports.LAYOUT_GRID_ITEM = exports.LAYOUT_GRID = exports.LAYOUT = exports.ROW = exports.APPEARANCE = exports.MAIN = void 0;
7
+ exports.DEFAULT_DETAIL_CONTROL_STYLE = exports.DEFAULT_CONTROL_STYLE = exports.DEFAULT_MOBILE_THEME = exports.DEFAULT_DESKTOP_THEME = exports.DEFAULT_FORM_ICON_JSON = exports.DEFAULT_FORM_ICON = void 0;
8
8
  /** 设计器主容器 key */
9
9
  exports.MAIN = 'main';
10
10
  /** 外观容器 */
@@ -43,7 +43,8 @@ exports.I18N_PROP_TABS = 'tabs';
43
43
  * 保持为空并在发布校验时提示(与设计器行为一致,可用 `--force` 跳过)。
44
44
  */
45
45
  exports.REQUIRED_PROP_DEFAULTS = {
46
- '@elem/xform-textarea': { height: '3' },
46
+ // height 用数字 3(设计器落库为数字;此前误写字符串 '3')
47
+ '@elem/xform-textarea': { height: 3 },
47
48
  '@elem/xform-rate': { max: 5 },
48
49
  '@elem/xform-slider': { min: 0, max: 100 },
49
50
  '@elem/xform-rich-text': { height: 300 },
@@ -100,12 +101,12 @@ exports.REQUIRED_PROP_DEFAULTS = {
100
101
  trace: false,
101
102
  },
102
103
  '@elem/xform-dynamic': { direction: 'column', rowCount: 3 },
104
+ // calculate 的 statisticMode/defaultValueType 由 CONTROL_DESIGNER_DEFAULTS 提供
105
+ // (设计器新建默认 FORMULA / defalut——平台原样拼写),此处不再覆盖
103
106
  '@elem/xform-calculate': {
104
- statisticMode: 'SUM',
105
107
  statisticData: [],
106
108
  showText: false,
107
109
  passValue: false,
108
- defaultValueType: 'empty',
109
110
  },
110
111
  '@elem/xform-cfg': {
111
112
  renderMode: 'select',
@@ -223,8 +224,22 @@ exports.CONTROL_TYPE_MAP = {
223
224
  subject: { desktop: '@elem/xform-subject', mobile: '@elem/xform-m-subject', logicalType: 'subject', dataType: 'varchar' },
224
225
  hyperlinks: { desktop: '@elem/xform-hyperlinks', mobile: '@elem/xform-m-hyperlinks', logicalType: 'hyperlinks', dataType: 'clob' },
225
226
  timeZone: { desktop: '@elem/xform-time-zone', mobile: '@elem/xform-m-time-zone', logicalType: 'timeZone', dataType: 'varchar' },
226
- relation: { desktop: '@elem/xform-relation', mobile: '@elem/xform-m-relation', logicalType: 'relation', dataType: 'relation' },
227
+ // relation 的 fdLength:设计器创建的关联字段为 200(环境真实字段一致),不能为 0
228
+ relation: { desktop: '@elem/xform-relation', mobile: '@elem/xform-m-relation', logicalType: 'relation', dataType: 'relation', defaultLength: 200 },
227
229
  relationQuery: { desktop: '@elem/xform-relation-query', mobile: '@elem/xform-relation-query', logicalType: 'relationQuery', dataType: 'relation' },
230
+ // ---------- 取自「手动新建表单」真实落库数据(多选下拉 / 内部主体 / 配置类 / 外观容器) ----------
231
+ 'select~multi': { desktop: '@elem/xform-select~multi', mobile: '@elem/xform-m-select~multi', logicalType: 'select~multi', dataType: 'varchar', dictType: 'optionDict' },
232
+ internalCompany: { desktop: '@elem/xform-internal-company', mobile: '@elem/xform-m-internal-company', logicalType: 'internalCompany', dataType: 'other', dictType: 'internalCompany', defaultLength: 200 },
233
+ cfgCurrency: { desktop: '@elem/xform-subject-currency', mobile: '@elem/xform-m-subject-currency', logicalType: 'cfgCurrency', dataType: 'other', dictType: 'cfgCurrency', defaultLength: 200 },
234
+ cfgExchangeRate: { desktop: '@elem/xform-exchange-rate', mobile: '@elem/xform-m-exchange-rate', logicalType: 'cfgExchangeRate', dataType: 'number', dictType: 'cfgExchangeRate', defaultLength: 200 },
235
+ cfgVolume: { desktop: '@elem/xform-volume-unit', mobile: '@elem/xform-m-volume-unit', logicalType: 'cfgVolume', dataType: 'other', dictType: 'cfgVolume', defaultLength: 200 },
236
+ cfgLength: { desktop: '@elem/xform-length-unit', mobile: '@elem/xform-m-length-unit', logicalType: 'cfgLength', dataType: 'other', dictType: 'cfgLength', defaultLength: 200 },
237
+ cfgMass: { desktop: '@elem/xform-mass-unit', mobile: '@elem/xform-m-mass-unit', logicalType: 'cfgMass', dataType: 'other', dictType: 'cfgMass', defaultLength: 200 },
238
+ cfgArea: { desktop: '@elem/xform-area-unit', mobile: '@elem/xform-m-area-unit', logicalType: 'cfgArea', dataType: 'other', dictType: 'cfgArea', defaultLength: 200 },
239
+ cfgTemperature: { desktop: '@elem/xform-temperature-unit', mobile: '@elem/xform-m-temperature-unit', logicalType: 'cfgTemperature', dataType: 'other', dictType: 'cfgTemperature', defaultLength: 200 },
240
+ collapseAppearance: { desktop: '@elem/xform-collapse-appearance', mobile: '@elem/xform-m-collapse-appearance', logicalType: 'collapseAppearance', dataType: 'varchar', isStored: false, kind: 'container' },
241
+ tabApproveAppearance: { desktop: '@elem/xform-tab-approve-appearance', mobile: '@elem/xform-tab-approve-appearance', logicalType: 'tabApproveAppearance', dataType: 'varchar', dictType: 'simpleDict', defaultLength: 2000, isStored: true, kind: 'container' },
242
+ tabAppearance: { desktop: '@elem/xform-tab-appearance', mobile: '@elem/xform-m-tab-appearance', logicalType: 'tabAppearance', dataType: 'varchar', isStored: false, kind: 'container' },
228
243
  // ---------- 高级控件 ----------
229
244
  // 下列条目的 dataType / dictType / defaultLength / isStored 均取自真实环境:
230
245
  // 控件包 `config.json` 的 xform 元数据(`llc control list` 可查)+ 真实表单落库数据核对。
@@ -304,6 +319,25 @@ exports.PLACEHOLDER_LANG_KEY_CANDIDATES = [
304
319
  'enter',
305
320
  'pleaseSelect',
306
321
  ];
322
+ /**
323
+ * 面板由设计器拼装(config.json 未声明 placeholder 配置项)、但设计器新建控件时
324
+ * **同样会写提示文字**的控件包(桌面端;移动端包同名前缀 m- 一并覆盖)→ 兜底文案。
325
+ *
326
+ * 依据:「手动新建表单」(设计器拖入不改动直接发布)的落库数据——这些控件均有
327
+ * placeholder,文案为通用默认(选择类=请选择、输入类=请输入),并非控件自带资源;
328
+ * 而 radio/checkbox/button/分割线等确实没有。仅凭资源探测会多写(radio 等也被探测到)。
329
+ */
330
+ exports.PLACEHOLDER_PANEL_PKGS = {
331
+ '@elem/xform-select~multi': '请选择',
332
+ '@elem/xform-internal-company': '请选择',
333
+ '@elem/xform-subject-currency': '请选择',
334
+ '@elem/xform-exchange-rate': '请输入',
335
+ '@elem/xform-volume-unit': '请选择',
336
+ '@elem/xform-length-unit': '请选择',
337
+ '@elem/xform-mass-unit': '请选择',
338
+ '@elem/xform-area-unit': '请选择',
339
+ '@elem/xform-phone-number': '请输入',
340
+ };
307
341
  /** 业务关联(relation)的属性面板由平台拼装,故语义规则在此声明 */
308
342
  exports.CONTROL_SEMANTIC_RULES = {
309
343
  relation: [
@@ -402,6 +436,7 @@ exports.RELATION_FRONT_EXTEND_PATHS = [
402
436
  'datasource.isForwardView',
403
437
  'datasource.conditionSetting',
404
438
  'renderMode',
439
+ 'trace',
405
440
  'outParams',
406
441
  ];
407
442
  /**
@@ -443,6 +478,388 @@ exports.CONTROL_DESIGNER_NOTES = {
443
478
  attdemo: '附件(模板):需在设计器中指定默认附件',
444
479
  imageDemo: '图片(模板):需在设计器中指定默认图片',
445
480
  };
481
+ /**
482
+ * 设计器**新建控件时的默认属性**(逐键取自「手动新建表单」——设计器拖入控件不改动直接发布的落库数据)。
483
+ *
484
+ * CLI 生成的字段此前缺少这些键(如 defaultValueType=formula、日期格式、图片/附件限制、
485
+ * 单位控件的 fdCode/meteringSystem、选项类控件的 $$init 脚本等),导致与设计器创建的控件
486
+ * 行为不一致。合并顺序:config.json 默认值 → CONTROL_DEFAULT_PROPS → **本表** →
487
+ * REQUIRED_PROP_DEFAULTS → 已有属性沿用。
488
+ *
489
+ * 不含:身份键(id/desktop/mobile/name/uuid/title)、placeholder 与 options(由生成器
490
+ * 按多语言机制生成)、span、maxLength(随 fdLength)。
491
+ */
492
+ exports.CONTROL_DESIGNER_DEFAULTS = {
493
+ "address": {
494
+ "multi": false,
495
+ "org": { "orgTypeArr": ["8"], "defaultValueType": "null" },
496
+ "orgAvailable": false,
497
+ "passValue": false,
498
+ "preSelectType": "fixed",
499
+ "range": "all",
500
+ "showAvatar": false,
501
+ "showOrgType": 0,
502
+ "showText": false,
503
+ "trace": false,
504
+ },
505
+ "area": {
506
+ "defaultValueType": "null",
507
+ "passValue": false,
508
+ "precisionRegion": "county",
509
+ "selectLevel": "allLevel",
510
+ "showHierarchy": "all",
511
+ "showText": false,
512
+ },
513
+ "attachment": {
514
+ "anonymous": false,
515
+ "customCount": 1,
516
+ "itemDisplayConfig": ["showCreated", "showCreator", "showOrder", "showSize"],
517
+ "maxCount": 0,
518
+ "printContent": "nameOnly",
519
+ "printLayout": "horizontal",
520
+ "showText": false,
521
+ "singleMaxSize": 5242880,
522
+ },
523
+ "barcode": {
524
+ "createEnv": "xform",
525
+ "defaultValueType": "formula",
526
+ "height": 40,
527
+ "saveEnv": true,
528
+ "showText": false,
529
+ },
530
+ "button": {
531
+ "showText": false,
532
+ },
533
+ "calculate": {
534
+ "defaultValueType": "defalut",
535
+ "passValue": false,
536
+ "showText": false,
537
+ "statisticMode": "FORMULA",
538
+ },
539
+ "cfgArea": {
540
+ "defaultUnit": { "value": "null", "type": "fdUnit" },
541
+ "fdCode": "area",
542
+ "meteringSystem": "Metric",
543
+ "passValue": false,
544
+ "showText": false,
545
+ "trace": false,
546
+ },
547
+ "cfgCurrency": {
548
+ "currencyShowType": { "label": "货币符号", "value": "fdFlag", "splicing": ["fdFlag"] },
549
+ "defaultValOpt": "none",
550
+ "enableRelation": false,
551
+ "passValue": true,
552
+ "relationOption": "base",
553
+ "showSearch": false,
554
+ "showText": false,
555
+ "trace": false,
556
+ },
557
+ "cfgExchangeRate": {
558
+ "isGetRate": false,
559
+ "passValue": false,
560
+ "showText": false,
561
+ "sourceCurrency": null,
562
+ "targetCurrency": null,
563
+ "trace": false,
564
+ },
565
+ "cfgLength": {
566
+ "defaultUnit": { "value": "null", "type": "fdUnit" },
567
+ "fdCode": "length",
568
+ "meteringSystem": "Metric",
569
+ "passValue": false,
570
+ "showText": false,
571
+ "trace": false,
572
+ },
573
+ "cfgMass": {
574
+ "defaultUnit": { "value": "null", "type": "fdUnit" },
575
+ "fdCode": "mass",
576
+ "meteringSystem": "Metric",
577
+ "passValue": false,
578
+ "showText": false,
579
+ "trace": false,
580
+ },
581
+ "cfgTemperature": {
582
+ "defaultUnit": { "value": "null", "type": "fdUnit" },
583
+ "fdCode": "temperature",
584
+ "meteringSystem": "Metric",
585
+ "passValue": false,
586
+ "showText": false,
587
+ "trace": false,
588
+ "value": null,
589
+ },
590
+ "cfgVolume": {
591
+ "defaultUnit": { "value": "null", "type": "fdUnit" },
592
+ "fdCode": "volume",
593
+ "meteringSystem": "Metric",
594
+ "passValue": false,
595
+ "showText": false,
596
+ "trace": false,
597
+ },
598
+ "checkbox": {
599
+ "$$init": "function(e){var t=e.controlProps||{},n=t.options,r=t.value;if((null==n?void 0:n.length)&&void 0===r){var o=n.filter((function(e){return e.checked}));if(null==o?void 0:o.length){var l=o.map((function(e){return e.value}));return e.controlProps.value=l,l}}}",
600
+ "defaultValueType": "fixed",
601
+ "direction": "column",
602
+ "multi": true,
603
+ "optionSource": "custom",
604
+ "passValue": false,
605
+ "rowCount": 3,
606
+ "serialType": "empty",
607
+ "showText": false,
608
+ "trace": false,
609
+ },
610
+ "collapseAppearance": {
611
+ "alignTitle": "left",
612
+ "canChangeSpan": false,
613
+ "isExpand": "expand",
614
+ "selectedNodes": [],
615
+ "visible": true,
616
+ },
617
+ "desc": {
618
+ "alignDesc": "left",
619
+ "controlTitleStyle": { "color": "#000000", "fontSize": 14 },
620
+ },
621
+ "dividing": {
622
+ "$$preset": { "styleSelect": { "default": { "titleStyle": { "color": "#000000" } }, "line": { "titleStyle": { "color": "#000000" } }, "flag-line": { "titleStyle": { "color": "#000000" } }, "italics-block": { "titleStyle": { "color": "#ffffff" } }, "custom-default": { "titleStyle": { "color": "#000000" } } } },
623
+ },
624
+ "hyperlinks": {
625
+ "defaultValueType": "fixed",
626
+ "largestSet": "infinit",
627
+ "showText": false,
628
+ },
629
+ "image": {
630
+ "anonymous": false,
631
+ "maxCount": 0,
632
+ "onlyMobileUpload": false,
633
+ "pcUpload": false,
634
+ "showImgSetting": { "type": ["dataSize", "attachName"] },
635
+ "showText": false,
636
+ "singleMaxSize": 5242880,
637
+ },
638
+ "internalCompany": {
639
+ "passValue": false,
640
+ "selectRange": 0,
641
+ "showText": false,
642
+ "trace": false,
643
+ },
644
+ "interval": {
645
+ "backgroundColor": "#F8F8F8",
646
+ "controlWidth": "default",
647
+ "height": 16,
648
+ "marginBottom": 16,
649
+ "marginTop": 16,
650
+ "maxColor": "#F8F8F8",
651
+ },
652
+ "location": {
653
+ "allowed": true,
654
+ "isLocationCenter": false,
655
+ "mapContent": { "address": "formattedAddress" },
656
+ "passValue": false,
657
+ "searchNearBy": { "isLocation": false, "checkboxvalue": false, "inputvalue": "300" },
658
+ "selectable": false,
659
+ "showText": false,
660
+ },
661
+ "mechnumber": {
662
+ "fdSysNumber": { "fdEntityName": "com.landray.sys.modeling.core.entity.main.SysModelingMainEntity", "fdContentClob": "[{\"name\":\"20200314\",\"type\":\"date\",\"error\":false,\"ruleData\":{\"zone\":\"中文(中国)\",\"format\":\"yyyyMMdd\"},\"id\":\"1\"}]", "fdVirtualNumberValue": "20200314", "fdName": "fd_col_kty5pq", "fdDefaultFlag": false, "fdTemplateFlag": true, "fdId": "1k4n6g2p5wcw7erbw21a52243ukdo6f1daw0" },
663
+ "fdType": "2",
664
+ "showText": false,
665
+ },
666
+ "moneytext": {
667
+ "defaultValueType": "formula",
668
+ "passValue": false,
669
+ "precision": 2,
670
+ "showCount": true,
671
+ "showText": false,
672
+ "symbol": "",
673
+ "trace": false,
674
+ },
675
+ "numbertext": {
676
+ "defaultValueType": "formula",
677
+ "numberFormat": { "formatType": "base", "percentage": null, "precision": null, "groupingUsed": null, "symbol": null, "unit": "" },
678
+ "passValue": false,
679
+ "showCount": true,
680
+ "showText": false,
681
+ "trace": false,
682
+ },
683
+ "phoneNumber": {
684
+ "defaultValueType": "formula",
685
+ "international": true,
686
+ "passValue": false,
687
+ "showText": false,
688
+ },
689
+ "qrcode": {
690
+ "createEnv": "xform",
691
+ "fdIsStored": false,
692
+ "modelName": "com.landray.sys.xform.core.entity.design.SysXFormDesign",
693
+ "pageType": 2,
694
+ "saveEnv": true,
695
+ "showText": false,
696
+ "size": "160px",
697
+ },
698
+ "radio": {
699
+ "$$init": "function(e){var t=e.controlProps||{},r=t.options,n=t.value;if((null==r?void 0:r.length)&&void 0===n){var o=r.find((function(e){return e.checked}));if(void 0!==o){var a=o.value;return e.controlProps.value=a,a}}}",
700
+ "defaultValueType": "fixed",
701
+ "direction": "column",
702
+ "optionSource": "custom",
703
+ "passValue": false,
704
+ "rowCount": 3,
705
+ "serialType": "empty",
706
+ "showText": false,
707
+ "trace": false,
708
+ },
709
+ "rate": {
710
+ "defaultValue": 0,
711
+ "defaultValueType": "fixed",
712
+ "max": 5,
713
+ "rateColor": { "option": "fix", "color": "#F6CD14" },
714
+ "rateIcon": "iconCommon_combine_30_gradeStar",
715
+ "rateSet": [],
716
+ "showCustomRes": false,
717
+ "showText": false,
718
+ },
719
+ "relation": {
720
+ "direction": "column",
721
+ "isForwardView": "no",
722
+ "modelName": "com.landray.sys.xform.core.entity.design.SysXFormDesign",
723
+ "multi": false,
724
+ "passValue": false,
725
+ "renderMode": "singlelist",
726
+ "rowCount": 3,
727
+ "showText": false,
728
+ "trace": false,
729
+ },
730
+ "rich-text": {
731
+ "defaultValueFormulaVO": {},
732
+ "defaultValueType": "formula",
733
+ "height": 400,
734
+ "passValue": false,
735
+ "resize": true,
736
+ "showText": false,
737
+ "trace": false,
738
+ "viewPageSet": { "isSystem": true, "displayMode": "adaptive" },
739
+ },
740
+ "select": {
741
+ "$$init": "function(e){var t=(e||{}).controlProps||{},r=t.value,n=t.multi,o=t.options;if(void 0===r&&(null==o?void 0:o.length)){if(n){var l=o.filter((function(e){return e.checked})),a=(null==l?void 0:l.length)?l.map((function(e){return e.value})):void 0;return e.controlProps.value=a,a}var i=o.find((function(e){return e.checked})),u=i?i.value:void 0;return e.controlProps.value=u,u}}",
742
+ "defaultValueType": "fixed",
743
+ "multi": false,
744
+ "optionSource": "custom",
745
+ "passValue": false,
746
+ "showSearch": false,
747
+ "showText": false,
748
+ "trace": false,
749
+ },
750
+ "select~multi": {
751
+ "$$init": "function(e){var t=(e||{}).controlProps||{},r=t.value,n=t.multi,o=t.options;if(void 0===r&&(null==o?void 0:o.length)){if(n){var l=o.filter((function(e){return e.checked})),a=(null==l?void 0:l.length)?l.map((function(e){return e.value})):void 0;return e.controlProps.value=a,a}var i=o.find((function(e){return e.checked})),u=i?i.value:void 0;return e.controlProps.value=u,u}}",
752
+ "defaultValueType": "fixed",
753
+ "multi": true,
754
+ "optionSource": "custom",
755
+ "passValue": false,
756
+ "showSearch": false,
757
+ "showText": false,
758
+ "trace": false,
759
+ },
760
+ "serial-number": {
761
+ "canChangeSpan": false,
762
+ },
763
+ "slider": {
764
+ "$$init": "function(e){var t=(e||{}).controlProps||{},r=t.value,n=t.min;if(void 0===r){var o=void 0!==n?n:0;return e.controlProps.value=o,o}}",
765
+ "color": "",
766
+ "columnWidth": "100",
767
+ "max": 100,
768
+ "min": 0,
769
+ "showText": false,
770
+ "step": 1,
771
+ "value": 0,
772
+ },
773
+ "switch": {
774
+ "$$init": "function(e){var t=e.controlProps||{},o=t.defaultValue,r=t.value;o&&void 0===r&&(e.controlProps.value=\"yes\"===o)}",
775
+ "closeCfg": { "colorMap": { "background": { "label": "背景", "color": "#c3c3c3" }, "font": { "label": "文字", "color": "#fff" } } },
776
+ "defaultValue": "yes",
777
+ "defaultValueType": "fixed",
778
+ "openCfg": { "colorMap": { "background": { "label": "背景", "color": "#4285F4" }, "font": { "label": "文字", "color": "#fff" } } },
779
+ "passValue": false,
780
+ "showText": false,
781
+ "trace": false,
782
+ },
783
+ "tabAppearance": {
784
+ "canChangeSpan": false,
785
+ },
786
+ "tabApproveAppearance": {
787
+ "canChangeSpan": false,
788
+ },
789
+ "text": {
790
+ "aiFill": false,
791
+ "defaultValueType": "formula",
792
+ "encrypt": false,
793
+ "encryptMonth": 9999,
794
+ "failureRule": "ANONYMIZE",
795
+ "maskFormatType": "********",
796
+ "passValue": false,
797
+ "showText": false,
798
+ "trace": false,
799
+ },
800
+ "textarea": {
801
+ "aiFill": false,
802
+ "defaultValueType": "formula",
803
+ "encrypt": false,
804
+ "encryptMonth": 9999,
805
+ "failureRule": "ANONYMIZE",
806
+ "height": 3,
807
+ "maskFormatType": "********",
808
+ "passValue": false,
809
+ "showText": false,
810
+ "trace": false,
811
+ "viewPageSet": { "isSystem": true, "displayMode": "adaptive" },
812
+ },
813
+ "timeAxis": {
814
+ "axisFieldsStyle": { "fontStyle": { "fontSize": 16 } },
815
+ "contentFields": ["fd_material_name", "fd_spec"],
816
+ "contentStyle": { "fontSize": 12, "color": "#666" },
817
+ "coordinateField": { "coordinateField": "fd_material_name", "fieldDataType": "text" },
818
+ "dataSheet": { "fdFormId": "1k4ihquulwdw2v2rw21ni5op3jhum26atdw0", "tableName": "mk_model_202610102twt1", "fdApp": { "fdName": "物料管理", "fdId": "1k4ihq0uowdw2u0sw1dfved73ul9gvcv1uw0", "fdAppCode": "material-mgmt" }, "modelId": "sys-modeling#1k4ihquulwdw2v2rw21ni5op3jhum26atdw0" },
819
+ "dataSource": "associated_table",
820
+ "displayDirection": "vertical",
821
+ "displayMethod": "tile",
822
+ "isForwardView": "no",
823
+ "maxHeight": 600,
824
+ "maxPageSize": 10,
825
+ "openWay": { "_target": "blank" },
826
+ "showText": false,
827
+ "sortOrder": "default",
828
+ "timeAxisContents": [{ "key": "coordinate1" }],
829
+ },
830
+ "timepicker": {
831
+ "dataPattern": "HH/mm",
832
+ "dataStep": 1,
833
+ "dateRange": { "startTime": 0, "endTime": 86399000 },
834
+ "defaultValueType": "null",
835
+ "displayPattern": "HH:mm",
836
+ "passValue": false,
837
+ "showText": false,
838
+ "timeRange": "fixed",
839
+ },
840
+ "timestamp": {
841
+ "$$init": "function(e){var t=(e||{}).controlProps||{},r=t.defaultValueType,n=t.value;if(\"now\"===r&&void 0===n){var o=(new Date).valueOf();return e.controlProps.value=o,o}}",
842
+ "dataPattern": "yyyy-MM-dd",
843
+ "defaultValueType": "null",
844
+ "displayPattern": "yyyy年MM月DD日",
845
+ "passValue": false,
846
+ "showText": false,
847
+ "trace": false,
848
+ },
849
+ "timeZone": {
850
+ "displayStyle": "button",
851
+ "passValue": true,
852
+ "showText": false,
853
+ "timeZoneplaceholder": "!{mv4retk3sy39207n5mi}",
854
+ },
855
+ "video": {
856
+ "anonymous": false,
857
+ "maxCount": 0,
858
+ "showText": false,
859
+ "singleMaxSize": 5242880,
860
+ "supportList": false,
861
+ },
862
+ };
446
863
  /** 明细表控件(数据项类型为 varchar,控件逻辑类型 detail) */
447
864
  exports.DETAIL_CONTROL = {
448
865
  desktop: '@elem/xform-detail-table',
@@ -468,6 +885,31 @@ exports.DETAIL_OPERATIONS = {
468
885
  };
469
886
  /** 明细表行操作开关(auth 顶层) */
470
887
  exports.DETAIL_ROW_FLAGS = { add: { canAddRow: true, canDeleteRow: true, canImport: true } };
888
+ /**
889
+ * 明细表在**主表** auth 条目中的行操作:
890
+ * `auth[0].{add|edit|view}[主表名].fields[明细表名].operations`。
891
+ *
892
+ * 设计器把明细表当作主表字段权限里的一个条目(`store/auth/utils.ts`),条目形如
893
+ * `{ visible, editable, required, hide, operations }`;运行时/渲染依赖其中的
894
+ * operations 渲染明细表顶部操作栏(添加行/删除行/导入/导出)。
895
+ * 注意 showType 与明细表自身条目(`DETAIL_OPERATIONS`,always)不同:
896
+ * add/edit 为 edit,view 为 onlyView——真实表单核对结论。
897
+ */
898
+ exports.DETAIL_MAIN_FIELD_OPERATIONS = {
899
+ add: [
900
+ { id: 'canAddRow', label: '添加行', messageKey: 'sys-xform:detail.operation.addRow', showType: 'edit', type: 'operation' },
901
+ { id: 'canDeleteRow', label: '删除行', messageKey: 'sys-xform:detail.operation.deleteRow', showType: 'edit', type: 'operation' },
902
+ { id: 'canImport', label: '导入', messageKey: 'sys-xform:detail.operation.import', showType: 'edit', type: 'operation' },
903
+ ],
904
+ view: [
905
+ { id: 'canExport', label: '导出', messageKey: 'sys-xform:detail.operation.export', showType: 'onlyView', type: 'view' },
906
+ ],
907
+ };
908
+ /** 明细表在主表 auth 条目中的基础权限(add/edit 与 view 键不同) */
909
+ exports.DETAIL_MAIN_FIELD_BASE = {
910
+ add: { visible: true, editable: true, required: false, hide: false },
911
+ view: { visible: true, hide: false },
912
+ };
471
913
  /**
472
914
  * 明细表控件的默认属性。
473
915
  *
@@ -21,8 +21,14 @@ const MODELING_MODEL_NAME = 'com.landray.sys.xform.core.entity.design.SysXFormDe
21
21
  /**
22
22
  * 构建业务关联的 `controlProps` 片段(`relationCfg` + `datasource` + 显示方式)。
23
23
  *
24
- * `datasource` 的骨架键取自真实表单(queryCondition/tree/filters/isListThrough…),
25
- * 这些是设计器「列表设置」弹窗的固有字段,缺失会导致设计器打开该控件时结构不完整。
24
+ * 骨架逐键对齐**设计器手动创建的真实字段**(物料入库单 `fd_col_9bg1ms`):
25
+ * - `refFieldName` 是 `$<字段名>$` 引用(运行时解析为所选记录的显示值)——
26
+ * 早期版本误写成 `$<表名>.<字段名>$`,运行时解析不到就会把字面量显示出来;
27
+ * - 不写 `showFields`(设计器不生成该键);
28
+ * - `datasource.queryCondition` 是 `{ linkType, query: {} }`——带 `conditionGroup` 的
29
+ * 完整条件结构会导致运行时**列表加载失败**;
30
+ * - `isDisplayMode` 必须为 `false`(true 是「仅展示」模式);
31
+ * - 不写 `queryCollection` / `sorters` / `querySorters`(设计器未配置时不生成)。
26
32
  */
27
33
  function buildRelationProps(spec) {
28
34
  const { target } = spec;
@@ -34,7 +40,6 @@ function buildRelationProps(spec) {
34
40
  appCode: target.appCode,
35
41
  xformName: target.xformName,
36
42
  modelId: target.modelId,
37
- showFields: spec.showFields,
38
43
  refFieldName: spec.refFieldName,
39
44
  tableType: 'main',
40
45
  tableName: target.tableName,
@@ -43,7 +48,7 @@ function buildRelationProps(spec) {
43
48
  datasource: {
44
49
  queryCondition: { linkType: '$and', query: {} },
45
50
  columns,
46
- filters: spec.filters ?? columns,
51
+ filters: spec.filters ?? [],
47
52
  tree: {
48
53
  treeLoop: true,
49
54
  querySorters: [],
@@ -52,17 +57,17 @@ function buildRelationProps(spec) {
52
57
  relationConditions: [{ operator: { value: '$eq' }, value: { format: 'field' } }],
53
58
  queryCondition: {
54
59
  linkType: '$and',
55
- query: { type: 'conditionGroup', orAndOperator: 'type', condition: [] },
60
+ query: { type: 'conditionGroup', condition: [] },
56
61
  },
57
62
  navigationMode: 'custom',
63
+ // 树导航的实体引用(sys-modeling#<表单fdId>),设计器创建的字段必有
64
+ entityName: `sys-modeling#${target.modelId}`,
58
65
  },
59
66
  isListThrough: true,
60
- isDisplayMode: true,
67
+ isDisplayMode: false,
61
68
  viewId: '',
62
69
  conditionSetting: false,
63
70
  isForwardView: true,
64
- queryCollection: {},
65
- sorters: [],
66
71
  },
67
72
  ...(spec.outParams ? { outParams: spec.outParams } : {}),
68
73
  };
@@ -343,6 +348,7 @@ async function resolveControl(field, options) {
343
348
  logicalType: preserved
344
349
  ? field.fdType || preserved.logicalType
345
350
  : meta?.xform?.type || entry.logicalType,
351
+ kind: entry.kind ?? 'control',
346
352
  meta,
347
353
  metaMobile,
348
354
  };
@@ -469,7 +475,12 @@ function buildFieldAttribute(params) {
469
475
  const prev = params.prevControlProps;
470
476
  const prevPkg = prev?.desktop?.type;
471
477
  if (prev && prevPkg === resolved.desktopPkg) {
478
+ // 业务关联重建时(extraControlProps 提供 relationCfg/datasource),旧字段可能带着
479
+ // 早期版本写入的空 outParams——设计器创建的字段没有这个键,不沿用
480
+ const skipStaleOutParams = params.extraControlProps != null && !('outParams' in params.extraControlProps);
472
481
  for (const [propKey, value] of Object.entries(prev)) {
482
+ if (skipStaleOutParams && propKey === 'outParams')
483
+ continue;
473
484
  if (!CONTROL_PROP_MANAGED_KEYS.has(propKey))
474
485
  carried[propKey] = value;
475
486
  }
@@ -480,6 +491,9 @@ function buildFieldAttribute(params) {
480
491
  ...(constants_1.CONTROL_DEFAULT_PROPS[resolved.desktopPkg] ?? {}),
481
492
  // 必填属性兜底默认值(config.json 声明 required 但无 default 的项)
482
493
  ...requiredDefaults,
494
+ // 设计器新建控件的默认属性(逐键取自设计器落库,见 CONTROL_DESIGNER_DEFAULTS)——
495
+ // 按控件逻辑类型匹配,修正 CLI 与设计器新建控件的默认值差异
496
+ ...(constants_1.CONTROL_DESIGNER_DEFAULTS[resolved.logicalType] ?? {}),
483
497
  ...carried,
484
498
  ...params.fontExtend,
485
499
  ...(params.extraControlProps ?? {}),
@@ -513,7 +527,7 @@ function buildFieldAttribute(params) {
513
527
  const config = {
514
528
  key,
515
529
  type: logicalType,
516
- kind: 'control',
530
+ kind: resolved.kind,
517
531
  label: langKey,
518
532
  controlProps,
519
533
  labelProps,
@@ -559,10 +573,9 @@ function enrichField(field, model, resolved) {
559
573
  passValue: false,
560
574
  trace: false,
561
575
  encrypt: false,
562
- // 初始值模式:config.json 默认 'null'(无初始值)。不能写 'formula'——
563
- // 公式模式下 defaultValueFormulaVO 必填,设计器提交会被拦截
564
- defaultValueType: 'null',
565
576
  encryptDefinition: {},
577
+ // 注意:不写 defaultValueType——由 CONTROL_DESIGNER_DEFAULTS 提供各控件
578
+ // 的设计器默认值(formula/fixed/defalut…),并在构建后回同步到此处
566
579
  });
567
580
  }
568
581
  if (!field.fdIsSystem && (field.fdOrder === undefined || field.fdOrder === null)) {
@@ -603,7 +616,11 @@ async function buildField(field, model, options, lang, locales) {
603
616
  // area=pleaseSelect,其余=placeholder),键名不对就取不到文案(日期控件提示文字缺失即此原因)。
604
617
  let placeholderKey;
605
618
  const registry = options.registry;
606
- if (registry && (0, widgets_1.hasConfigItem)(resolved.meta, 'placeholder')) {
619
+ // 门控:config.json 声明了 placeholder 的控件 + 面板由设计器拼装(config.json 未声明
620
+ // 但设计器新建时同样写提示文字)的控件。两者都不满足的(radio/checkbox/button 等)
621
+ // 设计器也不写提示文字——不能仅凭资源探测,否则会多写(已与设计器新建表单核对)
622
+ if (registry &&
623
+ ((0, widgets_1.hasConfigItem)(resolved.meta, 'placeholder') || constants_1.PLACEHOLDER_PANEL_PKGS[resolved.desktopPkg])) {
607
624
  const prevPlaceholder = prevAttr?.config?.controlProps?.placeholder;
608
625
  const prevLangEntry = typeof prevPlaceholder === 'string' ? options.prevLang?.[prevPlaceholder] : undefined;
609
626
  if (typeof prevPlaceholder === 'string' &&
@@ -636,6 +653,20 @@ async function buildField(field, model, options, lang, locales) {
636
653
  };
637
654
  break;
638
655
  }
656
+ // 拼装面板控件(config.json 未声明 placeholder):控件资源探测不到时使用
657
+ // 设计器的通用默认文案(选择类=请选择、输入类=请输入,见 PLACEHOLDER_PANEL_PKGS)
658
+ if (!placeholderKey) {
659
+ const fallbackText = constants_1.PLACEHOLDER_PANEL_PKGS[resolved.desktopPkg];
660
+ if (fallbackText) {
661
+ placeholderKey = (0, random_1.generateMessageKey)();
662
+ lang[placeholderKey] = {
663
+ prop: 'placeholder',
664
+ name: field.fdName,
665
+ type: 'input',
666
+ content: buildLangContent(locales, fallbackText, undefined, options.messages),
667
+ };
668
+ }
669
+ }
639
670
  }
640
671
  }
641
672
  // 新建选项(--option):写入 fdFontExtendData.options,作为选项的唯一来源
@@ -667,6 +698,21 @@ async function buildField(field, model, options, lang, locales) {
667
698
  label: item?.label,
668
699
  value: item?.value,
669
700
  }));
701
+ // 选项类控件缺省选项:对齐设计器新建时的默认选项(选项1/2/3,值 1/2/3,含多语言)。
702
+ // CLI 此前不写默认选项,下拉/单选/多选运行时是空选项(真实缺陷,已与设计器新建表单核对)
703
+ const defaultOptions = !prevOptions.length && !specified?.length &&
704
+ ['radio', 'checkbox', 'select', 'select~multi'].includes(String(field.fdType))
705
+ ? ['1', '2', '3'].map((value, i) => {
706
+ const key = (0, random_1.generateMessageKey)();
707
+ lang[key] = {
708
+ prop: 'option',
709
+ name: field.fdName,
710
+ type: 'input',
711
+ content: buildLangContent(locales, `选项${i + 1}`, undefined, options.messages),
712
+ };
713
+ return { label: key, value };
714
+ })
715
+ : undefined;
670
716
  const { attribute, config } = buildFieldAttribute({
671
717
  fieldUuid: field.uuid,
672
718
  langKey,
@@ -678,19 +724,34 @@ async function buildField(field, model, options, lang, locales) {
678
724
  resolved,
679
725
  placeholderKey,
680
726
  fontExtend: fontExtendOf(field),
681
- options: prevOptions.length ? prevOptions : undefined,
727
+ options: prevOptions.length ? prevOptions : defaultOptions,
682
728
  prevControlProps: prevAttr?.config?.controlProps,
683
729
  extraControlProps: relationSpec ? buildRelationProps(relationSpec) : undefined,
684
730
  });
685
731
  field.fdAttribute = attribute;
686
732
  // 前端扩展数据同步(如 address 的 orgTypeArr/multi/range)
687
733
  syncFontExtendData(field, resolved.meta, (config.controlProps ?? {}));
734
+ // fdFontExtendData.defaultValueType 与 controlProps 保持一致(设计器行为:
735
+ // 新建控件的默认初始值模式为 formula/fixed/defalut 等,见 CONTROL_DESIGNER_DEFAULTS)
736
+ {
737
+ const feObj = (0, random_1.safeJsonParse)(field.fdFontExtendData, {});
738
+ const cpObj = (config.controlProps ?? {});
739
+ if (cpObj.defaultValueType !== undefined && feObj.defaultValueType !== cpObj.defaultValueType) {
740
+ feObj.defaultValueType = cpObj.defaultValueType;
741
+ field.fdFontExtendData = JSON.stringify(feObj);
742
+ }
743
+ }
688
744
  // 业务关联的前端扩展数据(控件源码 JSDoc 声明的 @frontExtendData 路径):
689
745
  // modelId/refFieldName/tableType/tableName、datasource 各键、renderMode、outParams
690
746
  if (relationSpec) {
691
747
  const fontExtend = field.fdFontExtendData
692
748
  ? (0, random_1.safeJsonParse)(field.fdFontExtendData, {})
693
749
  : {};
750
+ // 早期版本生成、现在不再写的键:清掉,避免运行时拿到过期结构
751
+ for (const stale of ['queryCollection', 'querySorters', 'sorters'])
752
+ delete fontExtend[stale];
753
+ if (!relationSpec.outParams)
754
+ delete fontExtend.outParams;
694
755
  const props = (config.controlProps ?? {});
695
756
  for (const path of constants_1.RELATION_FRONT_EXTEND_PATHS) {
696
757
  const value = getByPath(props, path);
@@ -932,6 +993,9 @@ function wrapAppearance(tableName, children) {
932
993
  key: constants_1.MAIN,
933
994
  type: constants_1.MAIN,
934
995
  kind: 'container',
996
+ // 设计器保存时经 setMainCmpt 写入(ide/editor/runtime/business/feature.ts),
997
+ // 值为空也必须带键:CLI 曾缺失该属性,与设计器发布的视图不一致
998
+ controlProps: { importBtn: null, onDesktopImport: null },
935
999
  children,
936
1000
  },
937
1001
  ],
@@ -943,7 +1007,7 @@ function wrapAppearance(tableName, children) {
943
1007
  * 注意:栅格布局(`layout` / `@elem/layout-grid` / `GridItem`)**不写入**此处,
944
1008
  * 而多页签(`tab-appearance` / `tabs` / `tabpane`)**需要写入** —— 均为真实表单核对结论。
945
1009
  */
946
- function buildControlMappings(built, options = {}) {
1010
+ function buildControlMappings(built, options = {}, details = []) {
947
1011
  /** 布局控件的兜底元数据(控件包无 xform 时用,与真实表单的 xform.type 一致) */
948
1012
  const layoutDefaults = {
949
1013
  [constants_1.TAB_APPEARANCE]: 'tabAppearance',
@@ -953,11 +1017,13 @@ function buildControlMappings(built, options = {}) {
953
1017
  const build = (platform) => {
954
1018
  const seen = new Set();
955
1019
  const list = [];
956
- built.forEach((item) => {
1020
+ // **主表 + 明细字段**的控件都要进映射:运行时按 controlMappings 解析控件,
1021
+ // 明细字段的控件缺失时明细表渲染不完整(如顶部操作栏不出现)——真实缺陷已核对
1022
+ for (const item of [...built, ...details.flatMap((d) => d.fields)]) {
957
1023
  const pkg = platform === 'desktop' ? item.resolved.desktopPkg : item.resolved.mobilePkg;
958
1024
  const meta = platform === 'desktop' ? item.resolved.meta : item.resolved.metaMobile;
959
1025
  if (!pkg || seen.has(pkg))
960
- return;
1026
+ continue;
961
1027
  seen.add(pkg);
962
1028
  const xform = { ...(meta?.xform ?? {}), type: item.resolved.logicalType };
963
1029
  // 前端 handleFindXFormWidgets 会把包级 env 同步进 xform.env
@@ -966,7 +1032,7 @@ function buildControlMappings(built, options = {}) {
966
1032
  xform.env = meta.env;
967
1033
  }
968
1034
  list.push({ name: pkg, platform, xform });
969
- });
1035
+ }
970
1036
  if (options.layout === 'tabs') {
971
1037
  const pkgs = platform === 'desktop'
972
1038
  ? [constants_1.TAB_APPEARANCE, constants_1.TABS, constants_1.TAB_PANE]
@@ -1001,7 +1067,7 @@ function buildViewModel(built, mainTableName, options = {}, lang = {}, locales =
1001
1067
  });
1002
1068
  // 页签多语言只生成一次,供桌面端渲染树复用
1003
1069
  const panes = options.layout === 'tabs' ? resolveTabs(built, options, lang, locales) : [];
1004
- const mappings = buildControlMappings(built, options);
1070
+ const mappings = buildControlMappings(built, options, details);
1005
1071
  if (detailMappings?.desktop.length)
1006
1072
  mappings.desktop.push(...detailMappings.desktop);
1007
1073
  if (detailMappings?.mobile.length)
@@ -1076,7 +1142,7 @@ function buildAuth(models, options = {}) {
1076
1142
  hide: false,
1077
1143
  ...perm.edit?.[field.fdName],
1078
1144
  };
1079
- viewFields[field.fdName] = { visible: true, ...perm.view?.[field.fdName] };
1145
+ viewFields[field.fdName] = { visible: true, hide: false, ...perm.view?.[field.fdName] };
1080
1146
  });
1081
1147
  add[model.fdTableName] = {
1082
1148
  ...constants_1.DETAIL_ROW_FLAGS.add,
@@ -1113,7 +1179,28 @@ function buildAuth(models, options = {}) {
1113
1179
  hide: false,
1114
1180
  ...perm.edit?.[field.fdName],
1115
1181
  };
1116
- viewFields[field.fdName] = { visible: true, ...perm.view?.[field.fdName] };
1182
+ viewFields[field.fdName] = { visible: true, hide: false, ...perm.view?.[field.fdName] };
1183
+ });
1184
+ // 明细表在主表 auth 中以「字段条目」出现,携带行操作(添加行/删除行/导入/导出)。
1185
+ // 缺失时运行时明细表顶部操作栏不渲染(真实缺陷,设计器保存的结构已核对)
1186
+ models
1187
+ .filter((m) => m.fdType === 'detail')
1188
+ .forEach((detail) => {
1189
+ addFields[detail.fdTableName] = {
1190
+ ...constants_1.DETAIL_MAIN_FIELD_BASE.add,
1191
+ ...perm.add?.[detail.fdTableName],
1192
+ operations: constants_1.DETAIL_MAIN_FIELD_OPERATIONS.add,
1193
+ };
1194
+ editFields[detail.fdTableName] = {
1195
+ ...constants_1.DETAIL_MAIN_FIELD_BASE.add,
1196
+ ...perm.edit?.[detail.fdTableName],
1197
+ operations: constants_1.DETAIL_MAIN_FIELD_OPERATIONS.add,
1198
+ };
1199
+ viewFields[detail.fdTableName] = {
1200
+ ...constants_1.DETAIL_MAIN_FIELD_BASE.view,
1201
+ ...perm.view?.[detail.fdTableName],
1202
+ operations: constants_1.DETAIL_MAIN_FIELD_OPERATIONS.view,
1203
+ };
1117
1204
  });
1118
1205
  add[model.fdTableName] = { fields: addFields };
1119
1206
  edit[model.fdTableName] = { fields: editFields };
@@ -1476,6 +1563,54 @@ async function buildFdConfig(models, options = {}, stats) {
1476
1563
  ];
1477
1564
  }
1478
1565
  }
1566
+ // 沿用视图时同样补齐 `<main>` 节点的 controlProps(设计器保存时经 setMainCmpt 写入,
1567
+ // CLI 早期版本重建的视图缺失;详见 wrapAppearance 注释),并把 controlMappings
1568
+ // 与重建的映射做并集——旧视图的映射可能缺明细字段的控件(真实缺陷)
1569
+ const rebuiltMappings = buildControlMappings(built, options, details);
1570
+ for (const vm of viewModel) {
1571
+ const viewConfig = (0, random_1.safeJsonParse)(vm.fdConfig, {});
1572
+ const render = viewConfig?.view?.render;
1573
+ if (!render)
1574
+ continue;
1575
+ let patched = false;
1576
+ const patchMain = (nodes) => {
1577
+ for (const node of nodes) {
1578
+ if (!node || typeof node !== 'object')
1579
+ continue;
1580
+ if (node.type === constants_1.MAIN) {
1581
+ node.controlProps = {
1582
+ importBtn: null,
1583
+ onDesktopImport: null,
1584
+ ...(node.controlProps ?? {}),
1585
+ };
1586
+ patched = true;
1587
+ return true;
1588
+ }
1589
+ if (Array.isArray(node.children) && patchMain(node.children))
1590
+ return true;
1591
+ }
1592
+ return false;
1593
+ };
1594
+ for (const platform of Object.keys(render)) {
1595
+ if (Array.isArray(render[platform]))
1596
+ patchMain(render[platform]);
1597
+ }
1598
+ // controlMappings 并集:旧条目保留(如页签控件),重建条目按 name 覆盖(元数据最新)
1599
+ const cm = viewConfig.view?.controlMappings;
1600
+ if (cm) {
1601
+ for (const platform of ['desktop', 'mobile']) {
1602
+ const byName = new Map((Array.isArray(cm[platform]) ? cm[platform] : []).map((e) => [e.name, e]));
1603
+ for (const entry of rebuiltMappings[platform] ?? [])
1604
+ byName.set(entry.name, entry);
1605
+ for (const entry of detailMappings?.[platform] ?? [])
1606
+ byName.set(entry.name, entry);
1607
+ cm[platform] = [...byName.values()];
1608
+ patched = true;
1609
+ }
1610
+ }
1611
+ if (patched)
1612
+ vm.fdConfig = JSON.stringify(viewConfig);
1613
+ }
1479
1614
  }
1480
1615
  else {
1481
1616
  viewModel = buildViewModel(built, mainTableName, options, lang, locales, details, detailMappings);
@@ -1506,6 +1641,11 @@ async function buildFdConfig(models, options = {}, stats) {
1506
1641
  if (notes.size)
1507
1642
  stats.controlWarnings = [...notes];
1508
1643
  }
1644
+ // attribute:formAttr 重建,其余顶层键(dataUnique / subjectRule 等)从已有设计整体保留
1645
+ let prevAttributeObj = {};
1646
+ if (options.prevAttribute)
1647
+ prevAttributeObj = (0, random_1.safeJsonParse)(options.prevAttribute, {});
1648
+ delete prevAttributeObj.formAttr;
1509
1649
  return {
1510
1650
  id: options.formId ?? '',
1511
1651
  name: options.formName ?? '',
@@ -1514,7 +1654,7 @@ async function buildFdConfig(models, options = {}, stats) {
1514
1654
  entityCode: options.entityCode ?? constants_1.ENTITY_CODE,
1515
1655
  dataModel: models,
1516
1656
  auth: buildAuth(models, options),
1517
- attribute: { formAttr: JSON.stringify(formAttr) },
1657
+ attribute: { ...prevAttributeObj, formAttr: JSON.stringify(formAttr) },
1518
1658
  error: JSON.stringify({}),
1519
1659
  lang: JSON.stringify(lang),
1520
1660
  authFilter: { detailAuthDefine: {} },
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ const field_1 = require("./commands/field");
9
9
  const form_1 = require("./commands/form");
10
10
  const locale_1 = require("./commands/locale");
11
11
  const logger_1 = require("./utils/logger");
12
- const VERSION = '2.2.0';
12
+ const VERSION = '2.3.1';
13
13
  const program = new commander_1.Command();
14
14
  exports.program = program;
15
15
  program
package/dist/relation.js CHANGED
@@ -122,7 +122,6 @@ async function resolveRelations(client, parsed, currentAppId) {
122
122
  fdFormType: form.fdType ?? 0,
123
123
  },
124
124
  refFieldName: refNames.map((n) => `$${n}$`).join(''),
125
- showFields: refNames.map((n) => `$${labelOf.get(n)}$`).join(''),
126
125
  columns: columnNames.map((n) => ({ name: n, label: labelOf.get(n) })),
127
126
  });
128
127
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lan-low-code-cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
4
4
  "description": "lan-low-code cli:低代码表单引擎命令行工具(创建表单、获取可用字段、自动完善表单字段)",
5
5
  "keywords": [
6
6
  "low-code",
@@ -23,7 +23,10 @@
23
23
  "typecheck": "tsc -p tsconfig.json --noEmit",
24
24
  "prepare": "pnpm run build",
25
25
  "bump": "node scripts/bump-version.js",
26
- "bump:check": "node scripts/bump-version.js --check"
26
+ "bump:check": "node scripts/bump-version.js --check",
27
+ "pack": "node scripts/pack.js",
28
+ "pack:cli": "node scripts/pack.js --target cli",
29
+ "pack:skill": "node scripts/pack.js --target skill"
27
30
  },
28
31
  "dependencies": {
29
32
  "commander": "^11.1.0"