cloud-web-corejs 1.1.0-dev.20 → 1.1.0-dev.21
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/package.json +1 -1
- package/src/components/xform/form-designer/designer.js +0 -15
- package/src/components/xform/form-designer/form-widget/field-widget/fieldMixin.js +2 -2
- package/src/components/xform/form-designer/setting-panel/form-dynamicField-setting.vue +163 -136
- package/src/components/xform/form-designer/setting-panel/form-setting.vue +74 -9
- package/src/components/xform/form-render/container-item/data-table-mixin.js +3 -5
- package/src/components/xform/form-render/container-item/dynamicFieldMixin.js +4 -4
- package/src/components/xform/form-render/container-item/tab-item.vue +1 -1
- package/src/components/xform/form-render/fieldControlEngine.js +18 -0
- package/src/components/xform/form-render/fieldControlMixin.js +39 -29
- package/src/components/xform/form-render/index.vue +7 -4
- package/src/components/xform/form-render/indexMixin.js +26 -15
- package/src/components/xform/utils/util.js +0 -1
- package/src/views/user/home/default.vue +6 -3
- package/src/views/user/home/wjl/content.vue +3 -2
- package/src/components/xform/form-render/container-item/dynamicFieldEngine.js +0 -285
- package/src/components/xform/form-render/formDynamicFieldMixin.js +0 -133
package/package.json
CHANGED
|
@@ -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.
|
|
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.
|
|
1050
|
+
if (formRef && formRef.isFieldControlEnabled() &&
|
|
1051
1051
|
!formRef.isFieldControlFieldVisible(this.field)) {
|
|
1052
1052
|
this.clearFieldRules();
|
|
1053
1053
|
return;
|
|
@@ -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
|
-
<
|
|
6
|
-
|
|
7
|
-
</
|
|
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
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<el-option label="
|
|
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
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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="
|
|
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,
|
|
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
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
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
|
-
<
|
|
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
|
|
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="
|
|
416
|
+
<el-form-item :label="i18nt('其他标签页配置')" class="stacked-setting other-tabs-setting">
|
|
410
417
|
<div>
|
|
411
418
|
<draggable
|
|
412
419
|
tag="ul"
|
|
413
|
-
class="
|
|
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>
|
|
@@ -1442,10 +1442,8 @@ modules = {
|
|
|
1442
1442
|
const formRef = this.getFormRef();
|
|
1443
1443
|
if (!formRef || formRef.designState) return;
|
|
1444
1444
|
this.$nextTick(() => {
|
|
1445
|
-
if (formRef.syncFieldControlAfterStructure
|
|
1446
|
-
|
|
1447
|
-
formRef.hanldeCommonWidgetForTableColumns(tableColumns);
|
|
1448
|
-
}
|
|
1445
|
+
if (formRef.syncFieldControlAfterStructure()) return;
|
|
1446
|
+
formRef.hanldeCommonWidgetForTableColumns(tableColumns);
|
|
1449
1447
|
});
|
|
1450
1448
|
},
|
|
1451
1449
|
/** @returns {Boolean} 首次初始化是否跳过动态列加载。 */
|
|
@@ -4539,7 +4537,7 @@ modules = {
|
|
|
4539
4537
|
try {
|
|
4540
4538
|
// 行内保存只提交当前行,校验范围同步收敛到当前行:其他行与表外字段
|
|
4541
4539
|
// 的必填不该拦住单行保存(整体保存仍走 formRef.validate 的全量校验)
|
|
4542
|
-
const controlled = formRef.
|
|
4540
|
+
const controlled = formRef.isFieldControlEnabled();
|
|
4543
4541
|
const rowValid = controlled ? await this.validateEditRowAsync(obj.row) : this.validateEditRow(obj.row);
|
|
4544
4542
|
if (!rowValid) return false;
|
|
4545
4543
|
const fieldControlSnapshot = controlled ? formRef.captureFieldControlSubmission() : null;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
/**
|
|
11
11
|
* 表格布局容器(table/h5-table)专用混入。
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* 提供两类「布局表格」特有能力(动态字段状态控制由表单级 fieldControlMixin 统一处理):
|
|
14
14
|
* 1. 动态字段(dynamicSchemaSourceType):字段定义由脚本或接口下发,运行时生成并插入到行布局中。
|
|
15
15
|
* 2. 行折叠(默认行为):整行字段均隐藏时折叠该行(响应式,随字段显隐自动更新)。
|
|
16
16
|
*
|
|
@@ -108,7 +108,7 @@ const dynamicFieldMixin = {
|
|
|
108
108
|
}
|
|
109
109
|
return Promise.resolve(true);
|
|
110
110
|
} catch (e) {
|
|
111
|
-
if (formRef.
|
|
111
|
+
if (formRef.isFieldControlEnabled()) return Promise.reject(e);
|
|
112
112
|
return Promise.resolve(false);
|
|
113
113
|
}
|
|
114
114
|
},
|
|
@@ -118,7 +118,7 @@ const dynamicFieldMixin = {
|
|
|
118
118
|
if (!this.supportsRowLayout()) return;
|
|
119
119
|
if (this.getDynamicSchemaSourceType() === "none") return;
|
|
120
120
|
const formRef = this.getFormRef();
|
|
121
|
-
if (formRef && formRef.
|
|
121
|
+
if (formRef && formRef.isFieldControlEnabled()) {
|
|
122
122
|
const task = this.$nextTick().then(() => this.resolveShouldInitDynamicSchema())
|
|
123
123
|
.then(shouldInit => shouldInit ? this.loadControlledDynamicSchema() : undefined);
|
|
124
124
|
return formRef.trackFieldControlSchema(task, () => this.loadDynamicSchema(), this);
|
|
@@ -176,7 +176,7 @@ const dynamicFieldMixin = {
|
|
|
176
176
|
const formRef = this.getFormRef && this.getFormRef();
|
|
177
177
|
if (!this.designState && this.supportsRowLayout() &&
|
|
178
178
|
this.getDynamicSchemaSourceType() !== "none" &&
|
|
179
|
-
formRef && formRef.
|
|
179
|
+
formRef && formRef.isFieldControlEnabled()) {
|
|
180
180
|
return formRef.trackFieldControlSchema(this.loadControlledDynamicSchema(),
|
|
181
181
|
() => this.loadDynamicSchema(), this);
|
|
182
182
|
}
|
|
@@ -99,7 +99,7 @@ export default {
|
|
|
99
99
|
watch: {
|
|
100
100
|
visibleTabs(tabs) {
|
|
101
101
|
const formRef = this.getFormRef();
|
|
102
|
-
if (formRef && formRef.
|
|
102
|
+
if (formRef && formRef.isFieldControlEnabled() &&
|
|
103
103
|
!tabs.some(tab => tab.options.name === this.activeTabName)) {
|
|
104
104
|
this.activeTabName = tabs.length ? tabs[0].options.name : "";
|
|
105
105
|
}
|
|
@@ -99,6 +99,24 @@ export function normalizeLocalRules(rules) {
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
export function commitLocalFieldRules(rules, widgetList) {
|
|
103
|
+
const list = Array.isArray(rules) ? rules : [];
|
|
104
|
+
if (!list.length) return [];
|
|
105
|
+
const options = fieldControlTreeOptions(widgetList || []);
|
|
106
|
+
const targets = new Set(options.map(item => item.value));
|
|
107
|
+
const fields = new Set(options.filter(item => !item.isContainer).map(item => item.value));
|
|
108
|
+
const normalized = normalizeLocalRules(list);
|
|
109
|
+
normalized.forEach(rule => {
|
|
110
|
+
rule.conditions.forEach(condition => {
|
|
111
|
+
if (!fields.has(condition.field)) throw new Error("条件字段不存在或不支持:" + condition.field);
|
|
112
|
+
});
|
|
113
|
+
rule.targets.forEach(target => {
|
|
114
|
+
if (!targets.has(target.field)) throw new Error("目标不存在或不支持:" + target.field);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
export function evaluateCondition(condition, model) {
|
|
103
121
|
if (!condition || !condition.field) throw new Error("请选择动态规则条件字段");
|
|
104
122
|
const actual = model[condition.field];
|