cloud-web-corejs 1.1.0-dev.20 → 1.1.0-dev.22

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 (27) hide show
  1. package/package.json +1 -1
  2. package/src/components/excelExport/conditionExportConfig.js +112 -0
  3. package/src/components/excelExport/exportType.js +8 -0
  4. package/src/components/excelExport/index.vue +7 -1
  5. package/src/components/excelExport/mixins.js +410 -259
  6. package/src/components/xform/form-designer/designer.js +0 -15
  7. package/src/components/xform/form-designer/form-widget/field-widget/fieldMixin.js +2 -2
  8. package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +2 -1
  9. package/src/components/xform/form-designer/form-widget/field-widget/table-export-button-widget.vue +2 -1
  10. package/src/components/xform/form-designer/setting-panel/form-dynamicField-setting.vue +163 -136
  11. package/src/components/xform/form-designer/setting-panel/form-setting.vue +74 -9
  12. package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/empty-number-input.vue +51 -0
  13. package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +27 -2
  14. package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/table-export-button-editor.vue +33 -3
  15. package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +6 -0
  16. package/src/components/xform/form-render/container-item/data-table-mixin.js +6 -6
  17. package/src/components/xform/form-render/container-item/dynamicFieldMixin.js +4 -4
  18. package/src/components/xform/form-render/container-item/tab-item.vue +1 -1
  19. package/src/components/xform/form-render/fieldControlEngine.js +18 -0
  20. package/src/components/xform/form-render/fieldControlMixin.js +39 -29
  21. package/src/components/xform/form-render/index.vue +7 -4
  22. package/src/components/xform/form-render/indexMixin.js +26 -15
  23. package/src/components/xform/utils/util.js +0 -1
  24. package/src/views/user/home/default.vue +6 -3
  25. package/src/views/user/home/wjl/content.vue +3 -2
  26. package/src/components/xform/form-render/container-item/dynamicFieldEngine.js +0 -285
  27. package/src/components/xform/form-render/formDynamicFieldMixin.js +0 -133
@@ -106,7 +106,6 @@ let chartContainers = [],
106
106
  globalConfig: null,
107
107
  // 表单级动态字段规则
108
108
  dynamicFieldEnabled: false,
109
- dynamicFieldRuleVersion: 2,
110
109
  dynamicFieldRunMode: "auto",
111
110
  dynamicFieldAllowValue: false,
112
111
  dynamicFieldSourceType: "local",
@@ -282,13 +281,6 @@ let chartContainers = [],
282
281
  modifiedFlag = true;
283
282
  }
284
283
  if (!!formJson && !!formJson.formConfig) {
285
- // 旧模板缺少版本时不能继承新建模板的 V2 默认值。
286
- this.vueInstance.$set(this.formConfig, "dynamicFieldRuleVersion",
287
- formJson.formConfig.dynamicFieldRuleVersion || 1);
288
- this.vueInstance.$set(this.formConfig, "dynamicFieldRunMode",
289
- formJson.formConfig.dynamicFieldRunMode || "auto");
290
- this.vueInstance.$set(this.formConfig, "dynamicFieldAllowValue",
291
- !!formJson.formConfig.dynamicFieldAllowValue);
292
284
  //this.formConfig = importObj.formConfig
293
285
  baseRefUtil.overwriteObj(
294
286
  this.formConfig,
@@ -1970,13 +1962,6 @@ let chartContainers = [],
1970
1962
  "form__config__backup"
1971
1963
  );
1972
1964
  if (!!formConfigBackup) {
1973
- const restoredConfig = JSON.parse(formConfigBackup);
1974
- this.vueInstance.$set(this.formConfig, "dynamicFieldRuleVersion",
1975
- restoredConfig.dynamicFieldRuleVersion || 1);
1976
- this.vueInstance.$set(this.formConfig, "dynamicFieldRunMode",
1977
- restoredConfig.dynamicFieldRunMode || "auto");
1978
- this.vueInstance.$set(this.formConfig, "dynamicFieldAllowValue",
1979
- !!restoredConfig.dynamicFieldAllowValue);
1980
1965
  //this.formConfig = JSON.parse(formConfigBackup)
1981
1966
  baseRefUtil.overwriteObj(
1982
1967
  this.formConfig,
@@ -120,7 +120,7 @@ modules = {
120
120
  },
121
121
  mounted() {
122
122
  const formRef = this.getFormRef && this.getFormRef();
123
- if (formRef && formRef.isFieldControlV2 && formRef.isFieldControlV2()) {
123
+ if (formRef && formRef.isFieldControlEnabled()) {
124
124
  this.initFieldAttrs();
125
125
  formRef.syncFieldControlValidation();
126
126
  }
@@ -1047,7 +1047,7 @@ modules = {
1047
1047
  },
1048
1048
  buildFieldRules() {
1049
1049
  const formRef = this.getFormRef && this.getFormRef();
1050
- if (formRef && formRef.isFieldControlV2 && formRef.isFieldControlV2() &&
1050
+ if (formRef && formRef.isFieldControlEnabled() &&
1051
1051
  !formRef.isFieldControlFieldVisible(this.field)) {
1052
1052
  this.clearFieldRules();
1053
1053
  return;
@@ -44,6 +44,7 @@ import i18n from "../../../utils/i18n";
44
44
  import fieldMixin from "./fieldMixin";
45
45
  import StaticContentWrapper from "./static-content-wrapper.vue";
46
46
  import { EXPORT_TYPE } from "../../../../excelExport/exportType";
47
+ import { pickConditionExportOverrides } from "@base/components/excelExport/conditionExportConfig";
47
48
 
48
49
  export default {
49
50
  name: "select-export-item-button-widget",
@@ -101,8 +102,8 @@ export default {
101
102
  let opt = {
102
103
  title: this.field.options.exportFileName || null,
103
104
  targetRef: this.field.options.tableRef || null,
104
- pageSize: this.field.options.exportPageSize || null,
105
105
  showImageAtTable: this.field.options.showImageAtTable || null,
106
+ ...pickConditionExportOverrides(this.field.options),
106
107
  // 明细导出的列 / 脚本编码 / 取数参数三项各自独立:按钮上维护了哪项就以哪项为准,
107
108
  // 留空的那项沿用数据表格属性上那套。参数脚本原样下发,由数据表格求值(this 是
108
109
  // 表格组件,与配在表格属性上时同义)
@@ -32,6 +32,7 @@ import emitter from "../../../../../components/xform/utils/emitter";
32
32
  import i18n from "../../../../../components/xform/utils/i18n";
33
33
  import fieldMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/fieldMixin";
34
34
  import StaticContentWrapper from "../../../../../components/xform/form-designer/form-widget/field-widget/static-content-wrapper.vue";
35
+ import { pickConditionExportOverrides } from "@base/components/excelExport/conditionExportConfig";
35
36
 
36
37
  export default {
37
38
  name: "table-export-button-widget",
@@ -81,8 +82,8 @@ export default {
81
82
  let opt = {
82
83
  title: this.field.options.exportFileName || null,
83
84
  targetRef: this.field.options.tableRef || null,
84
- pageSize: this.field.options.exportPageSize || null,
85
85
  showImageAtTable: this.field.options.showImageAtTable || null,
86
+ ...pickConditionExportOverrides(this.field.options),
86
87
  };
87
88
  let tableExportParam = this.handleCustomEvent(this.field.options.tableExportParam);
88
89
  let options = { ...opt, ...tableExportParam, type: type };
@@ -2,123 +2,48 @@
2
2
  <div class="form-dynamic-field-setting">
3
3
  <el-form-item label="启用动态字段">
4
4
  <el-switch v-model="formConfig.dynamicFieldEnabled"></el-switch>
5
- <div class="tip-text">
6
- 根据表单数据/后台脚本动态控制整个表单内任意字段、容器的显隐等状态
7
- </div>
5
+ <el-tooltip content="根据表单数据动态控制字段、容器的显隐、必填、只读和禁用状态。" placement="left" popper-class="xform-setting-help">
6
+ <i class="el-icon-info setting-help-icon" tabindex="0" aria-label="动态字段说明"></i>
7
+ </el-tooltip>
8
8
  </el-form-item>
9
9
 
10
10
  <template v-if="formConfig.dynamicFieldEnabled">
11
- <el-form-item label="执行规则">
12
- <el-select :value="formConfig.dynamicFieldRuleVersion || 1" size="mini"
13
- @input="$set(formConfig, 'dynamicFieldRuleVersion', $event)">
14
- <el-option label="新版:动态规则后执行流程规则" :value="2" />
15
- <el-option label="历史兼容(待迁移)" :value="1" />
11
+ <div v-if="fieldControlTreeState.error" class="tip-text tree-options-error">{{ fieldControlTreeState.error }}</div>
12
+ <el-form-item label="执行方式">
13
+ <el-select :value="formConfig.dynamicFieldRunMode || 'auto'" size="mini"
14
+ @input="$set(formConfig, 'dynamicFieldRunMode', $event)">
15
+ <el-option label="按场景默认" value="auto" />
16
+ <el-option label="仅初始化" value="initialOnly" />
17
+ <el-option label="持续生效" value="continuous" />
16
18
  </el-select>
19
+ <el-tooltip content="默认:有流程仅初始化,无流程持续联动。仅初始化保留首次结果;持续模式每轮均由流程规则收尾。" placement="left" popper-class="xform-setting-help">
20
+ <i class="el-icon-info setting-help-icon" tabindex="0" aria-label="执行方式说明"></i>
21
+ </el-tooltip>
17
22
  </el-form-item>
18
- <div v-if="fieldControlTreeState.error" class="tip-text tree-options-error">{{ fieldControlTreeState.error }}</div>
19
- <template v-if="formConfig.dynamicFieldRuleVersion === 2">
20
- <el-form-item label="执行方式">
21
- <el-select :value="formConfig.dynamicFieldRunMode || 'auto'" size="mini"
22
- @input="$set(formConfig, 'dynamicFieldRunMode', $event)">
23
- <el-option label="按场景默认" value="auto" />
24
- <el-option label="仅初始化" value="initialOnly" />
25
- <el-option label="持续生效" value="continuous" />
26
- </el-select>
27
- <div class="tip-text">默认:有流程仅初始化,无流程持续联动。仅初始化保留首次结果;持续模式每轮均由流程规则收尾。</div>
28
- </el-form-item>
29
- <el-form-item label="允许自动赋值" v-if="formConfig.dynamicFieldSourceType === 'script'">
30
- <el-switch :value="!!formConfig.dynamicFieldAllowValue"
31
- @input="$set(formConfig, 'dynamicFieldAllowValue', $event)" />
32
- <div class="tip-text">开启前需确认后台 value 覆盖条件;规则未返回 value 时保留用户输入。</div>
33
- </el-form-item>
34
- </template>
35
- <div v-else class="tip-text">历史模板保持原执行顺序。迁移前请核对流程放开、持续联动与后台状态快照。</div>
36
- <el-form-item label="数据来源" class="form-item-label-top">
37
- <el-radio-group v-model="formConfig.dynamicFieldSourceType" size="mini">
38
- <el-radio-button label="local">本地规则</el-radio-button>
39
- <el-radio-button label="script">后台脚本</el-radio-button>
40
- </el-radio-group>
23
+ <el-form-item label="字段规则" class="el-form-item-second">
24
+ <el-button
25
+ type="primary"
26
+ plain
27
+ size="mini"
28
+ icon="el-icon-setting"
29
+ @click="openRuleDialog"
30
+ >
31
+ 配置规则({{ (formConfig.dynamicFieldRules || []).length }})
32
+ </el-button>
41
33
  </el-form-item>
42
-
43
- <template v-if="formConfig.dynamicFieldSourceType === 'local'">
44
- <el-form-item label="字段规则" class="el-form-item-second">
45
- <el-button
46
- type="primary"
47
- plain
48
- size="mini"
49
- icon="el-icon-setting"
50
- @click="openRuleDialog"
51
- >
52
- 配置规则({{ (formConfig.dynamicFieldRules || []).length }})
53
- </el-button>
54
- </el-form-item>
55
- </template>
56
-
57
- <template v-if="formConfig.dynamicFieldSourceType === 'script'">
58
- <el-form-item class="form-item-label-top el-form-item-second" label="脚本编码">
59
- <el-input
60
- v-model="formConfig.dynamicFieldScriptCode"
61
- size="mini"
62
- placeholder="scriptCode 或 formCode/scriptCode"
63
- ></el-input>
64
- </el-form-item>
65
- <el-form-item label="额外参数" class="el-form-item-second">
66
- <a
67
- href="javascript:void(0);"
68
- class="a-link link-oneLind"
69
- @click="editDynamicFieldScriptParam"
70
- >
71
- <span>{{ formConfig.dynamicFieldScriptParam }}</span>
72
- <i class="el-icon-edit"></i>
73
- </a>
74
- <div class="tip-text">
75
- 格式: return { stage:
76
- this.formModel.status }
77
- </div>
78
- </el-form-item>
79
- <el-form-item class="form-item-label-top el-form-item-second" label="触发字段">
80
- <el-select
81
- v-model="formConfig.dynamicFieldTriggerFields"
82
- multiple
83
- filterable
84
- size="mini"
85
- style="width: 100%"
86
- placeholder="字段值变化时重新请求后台"
87
- >
88
- <el-option
89
- v-for="(n, idx) in treeOptions"
90
- :key="n.value + '#' + idx"
91
- :value="n.value"
92
- :label="optPlainLabel(n)"
93
- :disabled="n.isContainer"
94
- >
95
- <span
96
- :style="{ paddingLeft: n.depth * 14 + 'px' }"
97
- :class="{ 'opt-container': n.isContainer }"
98
- >
99
- <span v-if="n.isContainer" class="opt-tag"
100
- >[{{ containerTypeLabel(n.type) }}]</span
101
- >{{ n.baseLabel }}
102
- </span>
103
- </el-option>
104
- </el-select>
105
- <div class="tip-text">未配置数据触发字段时,编辑数据不会自动请求;新版持续模式在流程上下文刷新时仍会重算。</div>
106
- </el-form-item>
107
- <div class="tip-text">
108
- 后台返回 fieldStates 的 key
109
- 可为字段名,也可为「命名容器」名以控制其显隐(容器仅 visible 生效)
110
- </div>
111
- </template>
112
34
  </template>
113
35
 
114
36
  <el-dialog
115
37
  title="表单动态字段规则"
116
38
  :visible.sync="ruleDialogVisible"
117
39
  :append-to-body="true"
118
- width="760px"
40
+ width="880px"
41
+ top="6vh"
119
42
  custom-class="dynamic-field-rule-dialog"
120
43
  >
44
+ <div class="rule-dialog-summary">配置触发条件与字段状态,规则按排列顺序执行。</div>
121
45
  <div class="rule-list">
46
+ <div v-if="!editingRules.length" class="rule-empty">暂无规则,点击下方「添加规则」开始配置</div>
122
47
  <div
123
48
  v-for="(rule, rIdx) in editingRules"
124
49
  :key="rule.id"
@@ -147,13 +72,13 @@
147
72
  <div
148
73
  v-for="(cond, cIdx) in rule.conditions"
149
74
  :key="cIdx"
150
- class="rule-row"
75
+ class="rule-row condition-row"
151
76
  >
152
77
  <el-select
153
78
  v-model="cond.field"
154
79
  filterable
155
80
  size="mini"
156
- placeholder="字段"
81
+ placeholder="选择条件字段"
157
82
  class="cell-field"
158
83
  >
159
84
  <el-option
@@ -189,14 +114,15 @@
189
114
  <el-input
190
115
  v-model="cond.value"
191
116
  size="mini"
192
- placeholder=""
117
+ placeholder="输入比较值"
193
118
  class="cell-value"
194
119
  :disabled="op_noValue(cond.operator)"
195
120
  ></el-input>
196
121
  <el-button
197
122
  type="text"
198
123
  icon="el-icon-remove-outline"
199
- class="danger-text"
124
+ class="danger-text row-remove"
125
+ aria-label="删除条件"
200
126
  @click="removeCondition(rule, cIdx)"
201
127
  ></el-button>
202
128
  </div>
@@ -294,7 +220,8 @@
294
220
  <el-button
295
221
  type="text"
296
222
  icon="el-icon-remove-outline"
297
- class="danger-text"
223
+ class="danger-text row-remove"
224
+ aria-label="删除目标字段"
298
225
  @click="removeTarget(rule, tIdx)"
299
226
  ></el-button>
300
227
  </div>
@@ -319,7 +246,8 @@
319
246
  </el-button>
320
247
  </div>
321
248
 
322
- <div slot="footer">
249
+ <div slot="footer" class="rule-dialog-footer">
250
+ <span class="rule-count">共 {{ editingRules.length }} 条规则</span>
323
251
  <el-button size="mini" @click="ruleDialogVisible = false"
324
252
  >取消</el-button
325
253
  >
@@ -372,9 +300,8 @@
372
300
  </template>
373
301
 
374
302
  <script>
375
- import { fieldControlTreeOptions, normalizeLocalRules } from "@base/components/xform/form-render/fieldControlEngine";
303
+ import { fieldControlTreeOptions, commitLocalFieldRules } from "@base/components/xform/form-render/fieldControlEngine";
376
304
  import i18n from "../../../../components/xform/utils/i18n";
377
- import { buildWidgetTreeOptions } from "../../../../components/xform/form-render/container-item/dynamicFieldEngine";
378
305
 
379
306
  const NO_VALUE_OPERATORS = ["empty", "notEmpty"];
380
307
 
@@ -409,9 +336,6 @@ export default {
409
336
  computed: {
410
337
  fieldControlTreeState() {
411
338
  const list = (this.designer && this.designer.widgetList) || [];
412
- if (this.formConfig.dynamicFieldRuleVersion !== 2) {
413
- return { options: buildWidgetTreeOptions(list), error: "" };
414
- }
415
339
  try {
416
340
  return { options: fieldControlTreeOptions(list), error: "" };
417
341
  } catch (error) {
@@ -531,29 +455,11 @@ export default {
531
455
  rule.targets.splice(idx, 1);
532
456
  },
533
457
  saveRules() {
534
- if (this.formConfig.dynamicFieldRuleVersion === 2) {
535
- try {
536
- const options = fieldControlTreeOptions(this.designer?.widgetList || []);
537
- const targets = new Set(options.map(item => item.value));
538
- const fields = new Set(options.filter(item => !item.isContainer).map(item => item.value));
539
- const normalized = normalizeLocalRules(this.editingRules);
540
- normalized.forEach(rule => {
541
- rule.conditions.forEach(condition => {
542
- if (!fields.has(condition.field)) throw new Error("条件字段不存在或不支持:" + condition.field);
543
- });
544
- rule.targets.forEach(target => {
545
- if (!targets.has(target.field)) throw new Error("目标不存在或不支持:" + target.field);
546
- });
547
- });
548
- this.formConfig.dynamicFieldRules = normalized;
549
- this.ruleDialogVisible = false;
550
- } catch (error) { this.$message.error(error.message); }
551
- return;
552
- }
553
- this.formConfig.dynamicFieldRules = JSON.parse(
554
- JSON.stringify(this.editingRules)
555
- );
556
- this.ruleDialogVisible = false;
458
+ try {
459
+ this.formConfig.dynamicFieldRules = commitLocalFieldRules(
460
+ this.editingRules, this.designer?.widgetList || []);
461
+ this.ruleDialogVisible = false;
462
+ } catch (error) { this.$message.error(error.message); }
557
463
  },
558
464
  },
559
465
  };
@@ -658,3 +564,124 @@ export default {
658
564
  margin-right: 4px;
659
565
  }
660
566
  </style>
567
+
568
+ <!-- 弹框挂载到 body,以独立类名隔离样式,并覆盖设置面板的控件宽度。 -->
569
+ <style lang="scss">
570
+ .el-dialog.dynamic-field-rule-dialog {
571
+ display: flex;
572
+ flex-direction: column;
573
+ max-width: calc(100vw - 32px);
574
+ max-height: 88vh;
575
+ margin-bottom: 0;
576
+ border-radius: 8px;
577
+
578
+ > .el-dialog__header {
579
+ flex: none;
580
+ padding: 20px 24px;
581
+ border-bottom: 1px solid #ebeef5;
582
+ }
583
+
584
+ > .el-dialog__body {
585
+ display: flex;
586
+ flex-direction: column;
587
+ min-height: 0;
588
+ padding: 16px 24px;
589
+ overflow: hidden;
590
+ }
591
+
592
+ > .el-dialog__footer {
593
+ flex: none;
594
+ padding: 14px 24px;
595
+ border-top: 1px solid #ebeef5;
596
+ }
597
+
598
+ .rule-dialog-summary {
599
+ flex: none;
600
+ margin-bottom: 14px;
601
+ color: #909399;
602
+ font-size: 13px;
603
+ line-height: 20px;
604
+ }
605
+
606
+ .rule-list {
607
+ min-height: 0;
608
+ max-height: none;
609
+ overflow-y: auto;
610
+ overflow-x: hidden;
611
+ padding-right: 4px;
612
+ }
613
+
614
+ .rule-empty {
615
+ padding: 40px 12px;
616
+ text-align: center;
617
+ color: #909399;
618
+ }
619
+
620
+ .rule-card {
621
+ padding: 0 16px 16px;
622
+ margin-bottom: 16px;
623
+ border: 1px solid #e4e7ed;
624
+ border-radius: 6px;
625
+ background: #fff;
626
+ }
627
+
628
+ .rule-card-header {
629
+ min-height: 44px;
630
+ margin: 0 -16px 14px;
631
+ padding: 0 16px;
632
+ background: #f5f7fa;
633
+ border-bottom: 1px solid #ebeef5;
634
+ border-radius: 6px 6px 0 0;
635
+ }
636
+
637
+ .rule-title { font-size: 14px; color: #303133; }
638
+ .rule-section + .rule-section { margin-top: 14px; padding-top: 14px; border-top: 1px dashed #e4e7ed; }
639
+ .rule-section-title { margin-bottom: 12px; gap: 12px; }
640
+
641
+ .rule-row {
642
+ display: grid;
643
+ gap: 10px;
644
+ margin-bottom: 10px;
645
+ min-width: 0;
646
+ }
647
+
648
+ .condition-row { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr) 28px; }
649
+ .target-row {
650
+ grid-template-columns: repeat(4, minmax(0, 1fr)) 28px;
651
+ padding: 12px;
652
+ background: #fafbfd;
653
+ border: 1px solid #ebeef5;
654
+ border-radius: 4px;
655
+ }
656
+
657
+ .target-row > .cell-field { grid-column: 1 / 5; }
658
+ .target-row > .row-remove { grid-column: 5; grid-row: 1; }
659
+ .target-attr { display: flex; flex-direction: column; align-items: stretch; gap: 6px; min-width: 0; }
660
+ .target-attr .attr-label { color: #606266; font-size: 12px; line-height: 18px; }
661
+
662
+ .rule-row .el-select,
663
+ .rule-row .el-input,
664
+ .rule-row .cell-field,
665
+ .rule-row .cell-op,
666
+ .rule-row .cell-value,
667
+ .rule-row .cell-tri { width: 100% !important; min-width: 0; margin: 0; }
668
+
669
+ .row-remove { width: 28px; margin: 0; padding: 8px 0; }
670
+ .rule-dialog-footer { display: flex; align-items: center; gap: 10px; }
671
+ .rule-dialog-footer .el-button { margin: 0; }
672
+ .rule-count { margin-right: auto; font-size: 13px; color: #909399; }
673
+
674
+ @media (max-width: 600px) {
675
+ > .el-dialog__body { padding: 12px; }
676
+ .condition-row { grid-template-columns: minmax(0, 1fr) 28px; }
677
+ .condition-row > .cell-field { grid-column: 1; }
678
+ .condition-row > .row-remove { grid-column: 2; grid-row: 1; }
679
+ .condition-row > .cell-op, .condition-row > .cell-value { grid-column: 1; }
680
+ .target-row { grid-template-columns: repeat(2, minmax(0, 1fr)) 28px; }
681
+ .target-row > .cell-field { grid-column: 1 / 3; }
682
+ .target-row > .row-remove { grid-column: 3; }
683
+ .target-attr:nth-of-type(odd) { grid-column: 1; }
684
+ .target-attr:nth-of-type(even) { grid-column: 2; }
685
+ }
686
+ }
687
+ </style>
@@ -5,7 +5,7 @@
5
5
  size="mini"
6
6
  label-position="left"
7
7
  label-width="120px"
8
- class="setting-form"
8
+ class="setting-form form-settings-panel"
9
9
  @submit.native.prevent
10
10
  >
11
11
  <el-collapse v-model="formActiveCollapseNames" class="setting-collapse">
@@ -359,9 +359,12 @@
359
359
  </el-collapse-item>
360
360
  <el-collapse-item name="4" title="列表标签页信息(仅列表表单生效)">
361
361
  <el-form-item label-width="0">
362
- <span style="color:rgba(0,0,0,0.45); font-size: 12px; line-height: 1.6;display:block;">
362
+ <el-tooltip placement="left" popper-class="xform-setting-help">
363
+ <span slot="content">
363
364
  本组配置只从「查询列表页」所用的表单读取,在详情/编辑表单里设置不会生效
364
365
  </span>
366
+ <span>适用范围<i class="el-icon-info setting-help-icon" tabindex="0"></i></span>
367
+ </el-tooltip>
365
368
  </el-form-item>
366
369
  <el-form-item :label="i18nt('列表启用详情多标签')">
367
370
  <el-switch v-model="formConfig.multiTabEnabled"></el-switch>
@@ -379,17 +382,21 @@
379
382
  >
380
383
  <el-switch v-model="formConfig.addTabEnabled"></el-switch>
381
384
  <span style="margin-left: 8px; color: #999; font-size: 12px">
382
- 开启后新增打开独立可关闭页签,需配置「标签名称字段」
385
+ <el-tooltip content="开启后新增打开独立可关闭页签,需配置标签名称字段。" placement="left" popper-class="xform-setting-help">
386
+ <i class="el-icon-info setting-help-icon" tabindex="0" aria-label="新增页签说明"></i>
387
+ </el-tooltip>
383
388
  </span>
384
389
  </el-form-item>
385
- <el-form-item :label="i18nt('流程启动后行为')" class="form-item-label-top">
390
+ <el-form-item class="stacked-setting submit-behavior-setting">
391
+ <span slot="label">{{ i18nt('流程启动后行为') }}
392
+ <el-tooltip content="详情页保存并提交、直接启动流程成功后的行为,不填默认刷新当前页签。" placement="left" popper-class="xform-setting-help">
393
+ <i class="el-icon-info setting-help-icon" tabindex="0" aria-label="流程启动后行为说明"></i>
394
+ </el-tooltip>
395
+ </span>
386
396
  <el-radio-group v-model="formConfig.submitBehavior">
387
397
  <el-radio label="closeToList">关闭页签并回列表刷新</el-radio>
388
398
  <el-radio label="refreshCurrent">刷新当前页签</el-radio>
389
399
  </el-radio-group>
390
- <div style="color: #999; font-size: 12px; line-height: 1.6">
391
- 详情页「保存并提交」「直接启动流程」成功后的行为,不填默认「刷新当前页签」
392
- </div>
393
400
  </el-form-item>
394
401
  </el-collapse-item>
395
402
  <el-collapse-item name="5" title="其他标签页信息">
@@ -406,11 +413,11 @@
406
413
  <el-form-item :label="i18nt('隐藏常规标签')">
407
414
  <el-switch v-model="formConfig.hideNormalTab"></el-switch>
408
415
  </el-form-item>
409
- <el-form-item :label="i18nt('其他标签页配置')" class="form-item-label-top" label-width="0">
416
+ <el-form-item :label="i18nt('其他标签页配置')" class="stacked-setting other-tabs-setting">
410
417
  <div>
411
418
  <draggable
412
419
  tag="ul"
413
- class="draggable-box"
420
+ class="other-tabs-list"
414
421
  :list="formConfig.otherTabList"
415
422
  v-bind="{
416
423
  group: 'optionsGroup',
@@ -1792,3 +1799,61 @@ $\{wf.starterName\}提交的$\{pm_product_project.product_code\}$\{pm_product_pr
1792
1799
  word-break: break-all;
1793
1800
  }
1794
1801
  </style>
1802
+
1803
+ <style lang="scss">
1804
+ .form-settings-panel.setting-form {
1805
+ .el-form-item {
1806
+ min-width: 0;
1807
+ }
1808
+ .el-form-item > .el-form-item__label {
1809
+ flex-shrink: 0;
1810
+ white-space: normal !important;
1811
+ overflow-wrap: anywhere;
1812
+ line-height: 20px;
1813
+ text-align: left;
1814
+ }
1815
+ .el-form-item > .el-form-item__content {
1816
+ min-width: 0;
1817
+ line-height: 28px;
1818
+ }
1819
+ .el-form-item__content > .el-input,
1820
+ .el-form-item__content > .el-select,
1821
+ .el-form-item__content > .el-textarea { width: 100% !important; min-width: 0; }
1822
+ .el-form-item__content > .el-select { width: calc(100% - 28px) !important; }
1823
+ .el-form-item__content > a { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
1824
+ .el-radio { margin: 0 12px 4px 0; white-space: normal; line-height: 22px; }
1825
+ .el-collapse-item__header { height: auto; min-height: 42px; line-height: 22px; padding: 8px 0; }
1826
+ .el-collapse-item__arrow { flex-shrink: 0; }
1827
+ .el-form-item.stacked-setting {
1828
+ display: block !important;
1829
+ > .el-form-item__label {
1830
+ float: none;
1831
+ display: block !important;
1832
+ width: 100% !important;
1833
+ padding: 0 0 8px;
1834
+ }
1835
+ > .el-form-item__content { margin-left: 0 !important; width: 100%; }
1836
+ }
1837
+ .submit-behavior-setting .el-radio-group { display: flex; flex-direction: column; gap: 8px; }
1838
+ .submit-behavior-setting .el-radio { display: flex; align-items: baseline; margin: 0; }
1839
+ .other-tabs-list { padding: 0; margin: 0; width: 100%; }
1840
+ .other-tabs-list > li {
1841
+ display: grid;
1842
+ grid-template-columns: 18px minmax(0, 1fr) 28px;
1843
+ align-items: center;
1844
+ gap: 8px;
1845
+ padding: 10px 8px;
1846
+ margin-bottom: 10px;
1847
+ list-style: none;
1848
+ background: #f5f7fa;
1849
+ border-radius: 4px;
1850
+ }
1851
+ .other-tabs-list > li > .el-input { grid-column: 2; width: 100% !important; min-width: 0; margin: 0; }
1852
+ .other-tabs-list .drag-option { grid-column: 1; grid-row: 1 / 3; cursor: move; color: #909399; }
1853
+ .other-tabs-list .col-delete-button { grid-column: 3; grid-row: 1 / 3; margin: 0; padding: 6px; }
1854
+ .tree-options-error { overflow-wrap: anywhere; margin-bottom: 8px; }
1855
+ }
1856
+ .setting-help-icon { margin-left: 8px; color: #909399; cursor: help; font-size: 14px; }
1857
+ .setting-help-icon:hover, .setting-help-icon:focus { color: #409eff; }
1858
+ .el-tooltip__popper.xform-setting-help { max-width: 300px; line-height: 1.7; overflow-wrap: anywhere; }
1859
+ </style>
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <base-input-number
3
+ :value="innerValue"
4
+ v-bind="$attrs"
5
+ v-on="listeners"
6
+ @input="onInput"
7
+ />
8
+ </template>
9
+
10
+ <script>
11
+ /**
12
+ * 未配置(null / undefined / 非正数)时显示空白,而不是 el-input-number 默认的 0。
13
+ * 清空后回写 null,运行时会回落到全局逻辑参数。
14
+ */
15
+ function toDisplayNumber(value) {
16
+ if (value == null || value === "") return undefined;
17
+ let num = Number(value);
18
+ if (!Number.isFinite(num) || num <= 0) return undefined;
19
+ return num;
20
+ }
21
+
22
+ function toStoredNumber(value) {
23
+ if (value == null || value === "") return null;
24
+ let num = Number(value);
25
+ if (!Number.isFinite(num) || num <= 0) return null;
26
+ return num;
27
+ }
28
+
29
+ export default {
30
+ name: "empty-number-input",
31
+ inheritAttrs: false,
32
+ props: {
33
+ value: {},
34
+ },
35
+ computed: {
36
+ innerValue() {
37
+ return toDisplayNumber(this.value);
38
+ },
39
+ listeners() {
40
+ let listeners = Object.assign({}, this.$listeners);
41
+ delete listeners.input;
42
+ return listeners;
43
+ },
44
+ },
45
+ methods: {
46
+ onInput(val) {
47
+ this.$emit("input", toStoredNumber(val));
48
+ },
49
+ },
50
+ };
51
+ </script>