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
|
@@ -30,7 +30,12 @@ export default {
|
|
|
30
30
|
computed: {
|
|
31
31
|
fieldControlBlocked() {
|
|
32
32
|
// 仅准备期隐藏,避免用户在流程限制生效前操作。error 要保留已填内容,提交由 ensure 拦截。
|
|
33
|
-
return this.
|
|
33
|
+
return this.isFieldControlEnabled() && this.fieldControlStatus === "preparing";
|
|
34
|
+
},
|
|
35
|
+
fieldControlInteractionBlocked() {
|
|
36
|
+
// 错误时保留表单内容可见,但不允许继续编辑或触发字段/按钮副作用。
|
|
37
|
+
return this.isFieldControlEnabled()
|
|
38
|
+
&& ["preparing", "error"].includes(this.fieldControlStatus);
|
|
34
39
|
},
|
|
35
40
|
fieldControlContextKey() {
|
|
36
41
|
const info = this.wfParam?.wfInfo || {};
|
|
@@ -43,7 +48,7 @@ export default {
|
|
|
43
48
|
watch: {
|
|
44
49
|
fieldControlContextKey() {
|
|
45
50
|
const runtime = this._fieldControl;
|
|
46
|
-
if (!runtime || !this.
|
|
51
|
+
if (!runtime || !this.isFieldControlEnabled()) return;
|
|
47
52
|
if (!this.fieldControlInitialized) {
|
|
48
53
|
if (runtime.mounting || runtime.task) runtime.revision++;
|
|
49
54
|
return;
|
|
@@ -52,7 +57,8 @@ export default {
|
|
|
52
57
|
runtime.mode = resolveRunMode(this.formConfig, !!this.wfParam?.hasWf);
|
|
53
58
|
this.stopFieldControlWatcher();
|
|
54
59
|
if (previousMode !== runtime.mode || runtime.mode === "continuous") {
|
|
55
|
-
|
|
60
|
+
// 流程节点是权限边界,不能在防抖/后台请求期间继续使用旧节点状态。
|
|
61
|
+
this.invalidateFieldControl({ immediate: true, blockInteraction: true });
|
|
56
62
|
} else {
|
|
57
63
|
runtime.revision++;
|
|
58
64
|
this.applyFieldControlStates(runtime.dynamicStates);
|
|
@@ -64,8 +70,8 @@ export default {
|
|
|
64
70
|
this.disposeFieldControl();
|
|
65
71
|
},
|
|
66
72
|
methods: {
|
|
67
|
-
|
|
68
|
-
return !!this.formConfig?.dynamicFieldEnabled
|
|
73
|
+
isFieldControlEnabled() {
|
|
74
|
+
return !!this.formConfig?.dynamicFieldEnabled;
|
|
69
75
|
},
|
|
70
76
|
getFieldControlRuntime() {
|
|
71
77
|
if (!this._fieldControl) this._fieldControl = createRuntime();
|
|
@@ -74,7 +80,7 @@ export default {
|
|
|
74
80
|
prepareFieldControlTargets() {
|
|
75
81
|
const runtime = this.getFieldControlRuntime();
|
|
76
82
|
const entries = collectFieldControlTargets(this.widgetList);
|
|
77
|
-
const widgets = this.getFieldControlWidgets
|
|
83
|
+
const widgets = this.getFieldControlWidgets();
|
|
78
84
|
runtime.entries = entries;
|
|
79
85
|
runtime.byWidget = new WeakMap();
|
|
80
86
|
entries.forEach(entry => runtime.byWidget.set(entry.widget, entry));
|
|
@@ -86,9 +92,9 @@ export default {
|
|
|
86
92
|
runtime.definitions.set(widget, state);
|
|
87
93
|
});
|
|
88
94
|
},
|
|
89
|
-
//
|
|
95
|
+
// 动态列/结构晚于首次采集时,先登记未改写的定义,再走动态→流程。
|
|
90
96
|
syncFieldControlAfterStructure() {
|
|
91
|
-
if (!this.
|
|
97
|
+
if (!this.isFieldControlEnabled()) return false;
|
|
92
98
|
this.prepareFieldControlTargets();
|
|
93
99
|
const runtime = this.getFieldControlRuntime();
|
|
94
100
|
if (this.fieldControlInitialized) {
|
|
@@ -107,7 +113,7 @@ export default {
|
|
|
107
113
|
const result = Object.create(null);
|
|
108
114
|
this.getFieldControlRuntime().entries.forEach(entry => {
|
|
109
115
|
const projected = this.createFieldControlProjection(entry.widget);
|
|
110
|
-
|
|
116
|
+
this.handleWidgetShowRule(projected);
|
|
111
117
|
result[entry.key] = readFieldState(projected);
|
|
112
118
|
});
|
|
113
119
|
return result;
|
|
@@ -192,7 +198,7 @@ export default {
|
|
|
192
198
|
if (runtime.schemaErrors.size) throw Array.from(runtime.schemaErrors.values())[0].error;
|
|
193
199
|
},
|
|
194
200
|
async initializeFieldControl() {
|
|
195
|
-
if (!this.
|
|
201
|
+
if (!this.isFieldControlEnabled()) return;
|
|
196
202
|
const runtime = this.getFieldControlRuntime();
|
|
197
203
|
if (runtime.destroyed) throw new Error("表单已关闭");
|
|
198
204
|
this.fieldControlStatus = "preparing";
|
|
@@ -247,18 +253,25 @@ export default {
|
|
|
247
253
|
if (!sameValue(runtime.lastDependency, this.fieldControlDependency())) this.invalidateFieldControl();
|
|
248
254
|
}, { deep: true, sync: true });
|
|
249
255
|
},
|
|
250
|
-
invalidateFieldControl() {
|
|
256
|
+
invalidateFieldControl(options = {}) {
|
|
251
257
|
const runtime = this.getFieldControlRuntime();
|
|
258
|
+
const immediate = options.immediate === true;
|
|
259
|
+
if (options.blockInteraction) {
|
|
260
|
+
this.fieldControlStatus = "preparing";
|
|
261
|
+
this.fieldControlError = "";
|
|
262
|
+
}
|
|
252
263
|
runtime.revision++;
|
|
253
264
|
runtime.dirty = true;
|
|
254
265
|
if (runtime.timer) clearTimeout(runtime.timer);
|
|
255
|
-
|
|
266
|
+
const refresh = () => {
|
|
256
267
|
runtime.timer = null;
|
|
257
268
|
this.refreshFieldControl().catch(error => this.failFieldControl(error, runtime));
|
|
258
|
-
}
|
|
269
|
+
};
|
|
270
|
+
if (immediate) refresh();
|
|
271
|
+
else runtime.timer = setTimeout(refresh, 120);
|
|
259
272
|
},
|
|
260
273
|
async refreshFieldControl() {
|
|
261
|
-
if (!this.
|
|
274
|
+
if (!this.isFieldControlEnabled()) return;
|
|
262
275
|
const runtime = this.getFieldControlRuntime();
|
|
263
276
|
if (runtime.timer) clearTimeout(runtime.timer);
|
|
264
277
|
runtime.timer = null;
|
|
@@ -389,14 +402,14 @@ export default {
|
|
|
389
402
|
},
|
|
390
403
|
applyFieldControlStates(states) {
|
|
391
404
|
const runtime = this.getFieldControlRuntime();
|
|
392
|
-
this.widgetEditOnWf = this.hanldeWfWidgetNew0
|
|
405
|
+
this.widgetEditOnWf = this.hanldeWfWidgetNew0();
|
|
393
406
|
let editable = false;
|
|
394
407
|
runtime.flowWidgets.forEach(widget => {
|
|
395
408
|
const entry = runtime.byWidget.get(widget);
|
|
396
409
|
const projected = this.createFieldControlProjection(widget);
|
|
397
|
-
|
|
410
|
+
this.handleWidgetShowRule(projected);
|
|
398
411
|
if (entry && states?.[entry.key]) writeStateOptions(projected.options, states[entry.key]);
|
|
399
|
-
|
|
412
|
+
this.applyWorkflowFieldControl(projected);
|
|
400
413
|
if (widget.formItemFlag && this.disabledMode) projected.options.disabled = true;
|
|
401
414
|
const effective = readFieldState(projected);
|
|
402
415
|
// 非输入按钮不在动态目标范围,但仍应用流程自身的 disabled。
|
|
@@ -407,7 +420,7 @@ export default {
|
|
|
407
420
|
applyFieldState(target, effective, name => this.getWidgetRef(name));
|
|
408
421
|
if (widget.formItemFlag && !projected.options.hidden && !projected.options.disabled && !projected.options.readonly) editable = true;
|
|
409
422
|
});
|
|
410
|
-
this.wfModifyEnabled = !!this.wfParam?.wfInfo?.toModify && editable && !this.getReadMode
|
|
423
|
+
this.wfModifyEnabled = !!this.wfParam?.wfInfo?.toModify && editable && !this.getReadMode();
|
|
411
424
|
this.syncFieldControlValidation();
|
|
412
425
|
},
|
|
413
426
|
syncFieldControlValidation() {
|
|
@@ -429,11 +442,14 @@ export default {
|
|
|
429
442
|
if (runtime.destroyed || runtime !== this.getFieldControlRuntime()) return;
|
|
430
443
|
this.fieldControlStatus = "error";
|
|
431
444
|
this.fieldControlError = error?.message || "字段规则执行失败,请重试";
|
|
432
|
-
//
|
|
433
|
-
|
|
445
|
+
// 即使动态重算失败,也要用最后一份可信动态状态重新收口当前流程限制。
|
|
446
|
+
// 交互由 fieldControlInteractionBlocked 独立阻断,不污染定义基线。
|
|
447
|
+
if (runtime.flowWidgets.length) {
|
|
448
|
+
try { this.applyFieldControlStates(runtime.dynamicStates); } catch (applyError) { /* 保留原始失败 */ }
|
|
449
|
+
}
|
|
434
450
|
},
|
|
435
451
|
async ensureFieldControlReady() {
|
|
436
|
-
if (!this.
|
|
452
|
+
if (!this.isFieldControlEnabled()) return;
|
|
437
453
|
const runtime = this.getFieldControlRuntime();
|
|
438
454
|
if (runtime.mountTask) await runtime.mountTask;
|
|
439
455
|
if (runtime.destroyed) throw new Error("表单已关闭");
|
|
@@ -457,7 +473,7 @@ export default {
|
|
|
457
473
|
}
|
|
458
474
|
},
|
|
459
475
|
guardFieldControlWorkflow(option) {
|
|
460
|
-
if (!this.
|
|
476
|
+
if (!this.isFieldControlEnabled()) return option;
|
|
461
477
|
const snapshots = {};
|
|
462
478
|
const wrapped = { ...option };
|
|
463
479
|
[["onStart", "onBeforeStartSubmit", "start"], ["onClickAgree", "onBeforeAgree", "agree"]]
|
|
@@ -485,7 +501,7 @@ export default {
|
|
|
485
501
|
return wrapped;
|
|
486
502
|
},
|
|
487
503
|
captureFieldControlSubmission() {
|
|
488
|
-
if (!this.
|
|
504
|
+
if (!this.isFieldControlEnabled()) return null;
|
|
489
505
|
return {
|
|
490
506
|
data: cloneDeep(this.formModel), context: this.fieldControlContextKey,
|
|
491
507
|
revision: this.getFieldControlRuntime().revision,
|
|
@@ -513,12 +529,6 @@ export default {
|
|
|
513
529
|
this.fieldControlInitialized = false;
|
|
514
530
|
this.fieldControlStatus = "idle";
|
|
515
531
|
this.fieldControlError = "";
|
|
516
|
-
// 同时清理 V1,支持 setFormJson 在两个版本之间切换。
|
|
517
|
-
if (this._fdfWatcher) this._fdfWatcher();
|
|
518
|
-
if (this._fdfTimer) clearTimeout(this._fdfTimer);
|
|
519
|
-
this._fdfWatcher = null;
|
|
520
|
-
this._fdfTimer = null;
|
|
521
|
-
this._fdfInited = false;
|
|
522
532
|
},
|
|
523
533
|
},
|
|
524
534
|
};
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
12
|
<div>
|
|
13
|
-
<el-alert v-if="
|
|
13
|
+
<el-alert v-if="fieldControlError" :title="fieldControlError" type="error" :closable="false" show-icon>
|
|
14
14
|
<el-button type="text" @click="retryFieldControl">重新计算字段规则</el-button>
|
|
15
15
|
</el-alert>
|
|
16
16
|
<div v-if="fieldControlBlocked" role="status">正在准备表单,请稍候…</div>
|
|
@@ -19,8 +19,12 @@
|
|
|
19
19
|
:size="size"
|
|
20
20
|
:class="[customClass, h5RootClass]"
|
|
21
21
|
class="render-form"
|
|
22
|
-
:style="fieldControlBlocked
|
|
22
|
+
:style="fieldControlBlocked
|
|
23
|
+
? { visibility: 'hidden' }
|
|
24
|
+
: (fieldControlInteractionBlocked ? { pointerEvents: 'none' } : null)"
|
|
25
|
+
:inert="fieldControlInteractionBlocked ? '' : null"
|
|
23
26
|
:aria-busy="fieldControlBlocked ? 'true' : 'false'"
|
|
27
|
+
:aria-disabled="fieldControlInteractionBlocked ? 'true' : 'false'"
|
|
24
28
|
:label-width="labelWidth"
|
|
25
29
|
:validate-on-rule-change="false"
|
|
26
30
|
:model="formDataModel"
|
|
@@ -119,7 +123,6 @@
|
|
|
119
123
|
import "./container-item/index";
|
|
120
124
|
import FieldComponents from "../../../components/xform/form-designer/form-widget/field-widget/index";
|
|
121
125
|
import indexMixin from "../../../components/xform/form-render/indexMixin";
|
|
122
|
-
import formDynamicFieldMixin from "../../../components/xform/form-render/formDynamicFieldMixin";
|
|
123
126
|
|
|
124
127
|
import fieldControlMixin from "@base/components/xform/form-render/fieldControlMixin";
|
|
125
128
|
|
|
@@ -144,7 +147,7 @@ export default {
|
|
|
144
147
|
compareDelList: () =>
|
|
145
148
|
import("../../../components/xform/form-render/compareDelList.vue"),
|
|
146
149
|
},
|
|
147
|
-
mixins: [indexMixin,
|
|
150
|
+
mixins: [indexMixin, fieldControlMixin],
|
|
148
151
|
};
|
|
149
152
|
</script>
|
|
150
153
|
|
|
@@ -386,7 +386,7 @@ modules = {
|
|
|
386
386
|
let formConfig = this.formConfig;
|
|
387
387
|
if (formConfig.isLoadEntity) {
|
|
388
388
|
this.loadDefaultEntityData(() => {
|
|
389
|
-
if (!
|
|
389
|
+
if (!this.isFieldControlEnabled()) {
|
|
390
390
|
this.handleCustomEvent(formConfig.formScriptSuccess);
|
|
391
391
|
}
|
|
392
392
|
});
|
|
@@ -574,7 +574,7 @@ modules = {
|
|
|
574
574
|
: null;
|
|
575
575
|
},
|
|
576
576
|
handleShowContent(callback) {
|
|
577
|
-
if (this.
|
|
577
|
+
if (this.isFieldControlEnabled()) return this.showControlledForm(callback);
|
|
578
578
|
// this.buildFormModel(!this.formJsonObj ? null : this.formJsonObj.widgetList);
|
|
579
579
|
this.handleBeforeMounted().then(() => {
|
|
580
580
|
this.showFormContent = true;
|
|
@@ -742,8 +742,14 @@ modules = {
|
|
|
742
742
|
})*/
|
|
743
743
|
},
|
|
744
744
|
hanldeCommonWidget2() {
|
|
745
|
-
if (this.
|
|
746
|
-
|
|
745
|
+
if (this.isFieldControlEnabled()) {
|
|
746
|
+
// 渲染前仍先补齐列 widget,但配置异常不能跳出受控初始化:
|
|
747
|
+
// showControlledForm 会再次采集并把错误落到 error/重试界面。
|
|
748
|
+
try {
|
|
749
|
+
this.prepareFieldControlTargets();
|
|
750
|
+
} catch (error) {
|
|
751
|
+
this.failFieldControl(error);
|
|
752
|
+
}
|
|
747
753
|
return;
|
|
748
754
|
}
|
|
749
755
|
let wfParam = this.wfParam || {};
|
|
@@ -1561,7 +1567,7 @@ modules = {
|
|
|
1561
1567
|
if (wfConfig1) {
|
|
1562
1568
|
resOption = extendDeeply(resOption, wfConfig1);
|
|
1563
1569
|
}
|
|
1564
|
-
return this.guardFieldControlWorkflow
|
|
1570
|
+
return this.guardFieldControlWorkflow(resOption);
|
|
1565
1571
|
};
|
|
1566
1572
|
}
|
|
1567
1573
|
return this.loadFormData({
|
|
@@ -2093,7 +2099,7 @@ modules = {
|
|
|
2093
2099
|
!i.formConfig || !i.widgetList)
|
|
2094
2100
|
)
|
|
2095
2101
|
return void this.$message.error("Invalid format of form json.");
|
|
2096
|
-
|
|
2102
|
+
this.resetFieldControl();
|
|
2097
2103
|
this.clearFormDataModel(),
|
|
2098
2104
|
this.buildFormModel(i.widgetList),
|
|
2099
2105
|
this.$set(this.formJsonObj, "formConfig", i.formConfig),
|
|
@@ -2103,11 +2109,8 @@ modules = {
|
|
|
2103
2109
|
this.insertCustomStyleAndScriptNode(),
|
|
2104
2110
|
this.$nextTick(function () {
|
|
2105
2111
|
t.initFormObject(!1);
|
|
2106
|
-
if (t.
|
|
2107
|
-
else
|
|
2108
|
-
t.handleOnMounted();
|
|
2109
|
-
if (t.initFormDynamicFields) t.initFormDynamicFields();
|
|
2110
|
-
}
|
|
2112
|
+
if (t.isFieldControlEnabled()) t.showControlledForm();
|
|
2113
|
+
else t.handleOnMounted();
|
|
2111
2114
|
});
|
|
2112
2115
|
} else this.$message.error("Set form json failed.");
|
|
2113
2116
|
},
|
|
@@ -2120,7 +2123,7 @@ modules = {
|
|
|
2120
2123
|
},
|
|
2121
2124
|
getFormData: function () {
|
|
2122
2125
|
const validateData = arguments.length === 0 || arguments[0] === undefined || arguments[0];
|
|
2123
|
-
if (validateData && this.
|
|
2126
|
+
if (validateData && this.isFieldControlEnabled()) {
|
|
2124
2127
|
return this.ensureFieldControlReady().then(() => new Promise((resolve, reject) => {
|
|
2125
2128
|
const snapshot = this.captureFieldControlSubmission();
|
|
2126
2129
|
this.validateCurrentForm(async valid => {
|
|
@@ -2275,7 +2278,7 @@ modules = {
|
|
|
2275
2278
|
this.$refs.renderForm.clearValidate(e);
|
|
2276
2279
|
},
|
|
2277
2280
|
validateForm: function (e) {
|
|
2278
|
-
if (this.
|
|
2281
|
+
if (this.isFieldControlEnabled()) return this.validate(e);
|
|
2279
2282
|
|
|
2280
2283
|
this.$refs["renderForm"].$baseValidate((valid) => {
|
|
2281
2284
|
if (!valid) {
|
|
@@ -4662,6 +4665,8 @@ modules = {
|
|
|
4662
4665
|
saveForm(callback) {
|
|
4663
4666
|
this.validateForm((valid) => {
|
|
4664
4667
|
if (!valid) return;
|
|
4668
|
+
// 从校验通过起锁定数据/规则版本;getSubData 和确认框都是异步窗口。
|
|
4669
|
+
const fieldControlSnapshot = this.captureFieldControlSubmission();
|
|
4665
4670
|
this.getSubData().then((formData) => {
|
|
4666
4671
|
let reportTemplate = this.reportTemplate || {};
|
|
4667
4672
|
let formConfig = this.formConfig;
|
|
@@ -4676,7 +4681,13 @@ modules = {
|
|
|
4676
4681
|
data: realFormData,
|
|
4677
4682
|
};
|
|
4678
4683
|
|
|
4679
|
-
this.$baseConfirm("您确定要保存吗?").then(() => {
|
|
4684
|
+
this.$baseConfirm("您确定要保存吗?").then(async () => {
|
|
4685
|
+
try {
|
|
4686
|
+
await this.assertFieldControlSubmission(fieldControlSnapshot);
|
|
4687
|
+
} catch (error) {
|
|
4688
|
+
this.$message.error(error.message);
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4680
4691
|
let saveConfig = formConfig.saveConfig || {};
|
|
4681
4692
|
this.formHttp({
|
|
4682
4693
|
options: saveConfig,
|
|
@@ -4932,7 +4943,7 @@ modules = {
|
|
|
4932
4943
|
}
|
|
4933
4944
|
},
|
|
4934
4945
|
validate(callback) {
|
|
4935
|
-
if (this.
|
|
4946
|
+
if (this.isFieldControlEnabled()) {
|
|
4936
4947
|
return this.ensureFieldControlReady().then(() => new Promise(resolve => {
|
|
4937
4948
|
const snapshot = this.captureFieldControlSubmission();
|
|
4938
4949
|
this.validateCurrentForm(async valid => {
|
|
@@ -1135,7 +1135,6 @@ export function getDefaultFormConfig() {
|
|
|
1135
1135
|
globalConfig: null,
|
|
1136
1136
|
// 表单级动态字段规则:按本地规则/后台脚本动态控制整个表单内任意字段/容器的显隐/必填/只读/禁用/取值
|
|
1137
1137
|
dynamicFieldEnabled: false,
|
|
1138
|
-
dynamicFieldRuleVersion: 2,
|
|
1139
1138
|
dynamicFieldRunMode: "auto",
|
|
1140
1139
|
dynamicFieldAllowValue: false,
|
|
1141
1140
|
dynamicFieldSourceType: "local",
|
|
@@ -737,15 +737,18 @@ body #app .index-home {
|
|
|
737
737
|
.time {
|
|
738
738
|
color: #b9b9b9;
|
|
739
739
|
font-size: 12px;
|
|
740
|
-
right: 12px;
|
|
740
|
+
right: 12px;
|
|
741
|
+
background: #FFF;
|
|
742
|
+
padding-left: 8px;
|
|
741
743
|
}
|
|
742
744
|
|
|
743
745
|
&:hover {
|
|
744
746
|
color: $baseColor;
|
|
745
|
-
background-color:
|
|
747
|
+
background-color: #F8FAFC;
|
|
746
748
|
|
|
747
749
|
.time {
|
|
748
|
-
color: $baseColor;
|
|
750
|
+
color: $baseColor;
|
|
751
|
+
background-color: #F8FAFC;
|
|
749
752
|
}
|
|
750
753
|
}
|
|
751
754
|
|
|
@@ -483,7 +483,8 @@ export default {
|
|
|
483
483
|
let userInfo = res.objx;
|
|
484
484
|
this.headPhotoUrl = userInfo.headPhotoUrl
|
|
485
485
|
? userInfo.headPhotoUrl
|
|
486
|
-
:
|
|
486
|
+
: require("@/resources/images/default-header.png").default ||
|
|
487
|
+
require("@/resources/images/default-header.png");
|
|
487
488
|
|
|
488
489
|
this.userInfo = userInfo;
|
|
489
490
|
this.initServiceProviderRole();
|
|
@@ -709,7 +710,7 @@ export default {
|
|
|
709
710
|
this.showDealDialog = true;
|
|
710
711
|
},
|
|
711
712
|
openOrderView(row) {
|
|
712
|
-
let dataId = row.
|
|
713
|
+
let dataId = row.order_id;
|
|
713
714
|
if (dataId == null) {
|
|
714
715
|
this.$message.warning(this.$t1("未找到工单"));
|
|
715
716
|
return;
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 动态字段规则引擎(纯逻辑,无 Vue 上下文)。
|
|
3
|
-
*
|
|
4
|
-
* 供「表单级动态规则(form-setting)」与「容器级动态字段(container-item)」共用:
|
|
5
|
-
* - 目标收集:字段 + 命名容器,建立 目标key -> { widget, refKey, isContainer } 映射与设计基线
|
|
6
|
-
* - 规则计算:本地条件/逻辑求值,输出每个目标的最终状态
|
|
7
|
-
* - 状态落地:通过 getWidgetRef 应用到运行时组件,无 ref 时回退改 schema
|
|
8
|
-
*/
|
|
9
|
-
import {
|
|
10
|
-
traverseFieldWidgets,
|
|
11
|
-
traverseContainerWidgets,
|
|
12
|
-
traverseFieldWidgetsOfContainer,
|
|
13
|
-
} from "../../../../components/xform/utils/util";
|
|
14
|
-
|
|
15
|
-
// 布局内格容器,不作为可控目标
|
|
16
|
-
const EXCLUDED_CONTAINER_TYPES = ["grid-col", "table-cell", "h5-table-cell"];
|
|
17
|
-
|
|
18
|
-
export function getModelKey(w) {
|
|
19
|
-
return (w.options.keyNameEnabled && w.options.keyName) || w.options.name;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function addFieldTo(map, baseline, w) {
|
|
23
|
-
if (!w || !w.options) return;
|
|
24
|
-
const key = getModelKey(w);
|
|
25
|
-
if (!key) return;
|
|
26
|
-
map[key] = { widget: w, refKey: w.options.name, isContainer: false };
|
|
27
|
-
baseline[key] = {
|
|
28
|
-
visible: !w.options.hidden,
|
|
29
|
-
required: !!w.options.required,
|
|
30
|
-
readonly: !!w.options.readonly,
|
|
31
|
-
disabled: !!w.options.disabled,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function addContainerTo(map, baseline, w) {
|
|
36
|
-
if (!w || !w.options || !w.options.name) return;
|
|
37
|
-
if (EXCLUDED_CONTAINER_TYPES.indexOf(w.type) > -1) return;
|
|
38
|
-
const key = w.options.name;
|
|
39
|
-
if (map[key]) return;
|
|
40
|
-
map[key] = { widget: w, refKey: key, isContainer: true };
|
|
41
|
-
baseline[key] = { visible: !w.options.hidden };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 整个表单范围:字段 + 命名容器(跳过弹窗/抽屉内部)
|
|
45
|
-
export function buildFormTargetMap(widgetList) {
|
|
46
|
-
const map = {};
|
|
47
|
-
const baseline = {};
|
|
48
|
-
traverseFieldWidgets(widgetList || [], (w) => addFieldTo(map, baseline, w));
|
|
49
|
-
traverseContainerWidgets(
|
|
50
|
-
widgetList || [],
|
|
51
|
-
(w) => addContainerTo(map, baseline, w),
|
|
52
|
-
true
|
|
53
|
-
);
|
|
54
|
-
return { map, baseline };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 单个容器范围:容器内字段 + 命名子容器
|
|
58
|
-
export function buildContainerTargetMap(container) {
|
|
59
|
-
const map = {};
|
|
60
|
-
const baseline = {};
|
|
61
|
-
traverseFieldWidgetsOfContainer(container, (w) => addFieldTo(map, baseline, w));
|
|
62
|
-
collectNamedContainersInContainer(container).forEach((w) =>
|
|
63
|
-
addContainerTo(map, baseline, w)
|
|
64
|
-
);
|
|
65
|
-
return { map, baseline };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// 递归收集指定容器内「命名的子容器」
|
|
69
|
-
export function collectNamedContainersInContainer(root) {
|
|
70
|
-
const out = [];
|
|
71
|
-
const walk = (w, isRoot) => {
|
|
72
|
-
if (!w || w.category !== "container") return;
|
|
73
|
-
if (
|
|
74
|
-
!isRoot
|
|
75
|
-
&& w.options
|
|
76
|
-
&& w.options.name
|
|
77
|
-
&& EXCLUDED_CONTAINER_TYPES.indexOf(w.type) === -1
|
|
78
|
-
) {
|
|
79
|
-
out.push(w);
|
|
80
|
-
}
|
|
81
|
-
if (Array.isArray(w.rows)) {
|
|
82
|
-
w.rows.forEach((row) => {
|
|
83
|
-
(row.cols || []).forEach((cell) => walk(cell, false));
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
["cols", "tabs", "widgetList", "panes", "buttonWidgetList"].forEach((k) => {
|
|
87
|
-
if (Array.isArray(w[k])) w[k].forEach((c) => walk(c, false));
|
|
88
|
-
});
|
|
89
|
-
};
|
|
90
|
-
walk(root, true);
|
|
91
|
-
return out;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/* ------------------- 层级下拉选项(供设计器) ------------------- */
|
|
95
|
-
// 构建带层级的目标候选(字段 + 容器),按表单树 DFS 顺序输出,附带 depth。
|
|
96
|
-
// 布局内格(grid-col/table-cell 等)不单独成节点,仅作为透明层向下展开。
|
|
97
|
-
function makeTreeBuilder() {
|
|
98
|
-
const nodes = [];
|
|
99
|
-
const visitList = (list, depth) => {
|
|
100
|
-
(list || []).forEach((w) => visit(w, depth));
|
|
101
|
-
};
|
|
102
|
-
const visitChildren = (w, depth) => {
|
|
103
|
-
if (Array.isArray(w.rows)) {
|
|
104
|
-
w.rows.forEach((row) => visitList((row && row.cols) || [], depth));
|
|
105
|
-
}
|
|
106
|
-
["cols", "tabs", "widgetList", "panes", "buttonWidgetList"].forEach((k) => {
|
|
107
|
-
if (Array.isArray(w[k])) visitList(w[k], depth);
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
const visit = (w, depth) => {
|
|
111
|
-
if (!w) return;
|
|
112
|
-
if (w.category === "container") {
|
|
113
|
-
// 布局内格:透明展开,深度不变
|
|
114
|
-
if (EXCLUDED_CONTAINER_TYPES.indexOf(w.type) > -1) {
|
|
115
|
-
visitChildren(w, depth);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const name = w.options && w.options.name;
|
|
119
|
-
nodes.push({
|
|
120
|
-
value: name || "__c_" + w.id,
|
|
121
|
-
baseLabel: (w.options && (w.options.label || name)) || w.type,
|
|
122
|
-
depth,
|
|
123
|
-
isContainer: true,
|
|
124
|
-
hasName: !!name,
|
|
125
|
-
type: w.type,
|
|
126
|
-
});
|
|
127
|
-
visitChildren(w, depth + 1);
|
|
128
|
-
} else if (w.formItemFlag) {
|
|
129
|
-
const key = getModelKey(w);
|
|
130
|
-
if (!key) return;
|
|
131
|
-
nodes.push({
|
|
132
|
-
value: key,
|
|
133
|
-
baseLabel: (w.options.label || key) + " (" + key + ")",
|
|
134
|
-
depth,
|
|
135
|
-
isContainer: false,
|
|
136
|
-
hasName: true,
|
|
137
|
-
type: w.type,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
return { nodes, visitList, visitChildren };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// 整个表单范围的层级候选
|
|
145
|
-
export function buildWidgetTreeOptions(rootList) {
|
|
146
|
-
const b = makeTreeBuilder();
|
|
147
|
-
b.visitList(rootList || [], 0);
|
|
148
|
-
return b.nodes;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// 单个容器范围的层级候选(不含容器自身,从其子级开始)
|
|
152
|
-
export function buildContainerTreeOptions(container) {
|
|
153
|
-
const b = makeTreeBuilder();
|
|
154
|
-
if (container) b.visitChildren(container, 0);
|
|
155
|
-
return b.nodes;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/* ------------------- 规则计算 ------------------- */
|
|
159
|
-
export function computeLocalStates(rules, baseline, formModel) {
|
|
160
|
-
const list = rules || [];
|
|
161
|
-
const states = {};
|
|
162
|
-
const ensure = (key) => {
|
|
163
|
-
if (!states[key]) {
|
|
164
|
-
const base = baseline[key] || { visible: true };
|
|
165
|
-
states[key] = Object.assign({}, base);
|
|
166
|
-
}
|
|
167
|
-
return states[key];
|
|
168
|
-
};
|
|
169
|
-
// 先把所有规则涉及的目标置为基线,未命中时即还原
|
|
170
|
-
list.forEach((rule) => {
|
|
171
|
-
(rule.targets || []).forEach((t) => t.field && ensure(t.field));
|
|
172
|
-
});
|
|
173
|
-
list.forEach((rule) => {
|
|
174
|
-
if (!evalRule(rule, formModel)) return;
|
|
175
|
-
(rule.targets || []).forEach((t) => {
|
|
176
|
-
if (!t.field) return;
|
|
177
|
-
const s = ensure(t.field);
|
|
178
|
-
if (t.visible !== undefined && t.visible !== null) s.visible = !!t.visible;
|
|
179
|
-
if (t.required !== undefined && t.required !== null) {
|
|
180
|
-
s.required = !!t.required;
|
|
181
|
-
}
|
|
182
|
-
if (t.readonly !== undefined && t.readonly !== null) {
|
|
183
|
-
s.readonly = !!t.readonly;
|
|
184
|
-
}
|
|
185
|
-
if (t.disabled !== undefined && t.disabled !== null) {
|
|
186
|
-
s.disabled = !!t.disabled;
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
return states;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function evalRule(rule, model) {
|
|
194
|
-
const conds = (rule && rule.conditions) || [];
|
|
195
|
-
if (!conds.length) return true;
|
|
196
|
-
if (rule.logic === "or") {
|
|
197
|
-
return conds.some((c) => evalCondition(c, model));
|
|
198
|
-
}
|
|
199
|
-
return conds.every((c) => evalCondition(c, model));
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export function evalCondition(cond, model) {
|
|
203
|
-
if (!cond || !cond.field) return false;
|
|
204
|
-
const actual = model ? model[cond.field] : undefined;
|
|
205
|
-
const expected = cond.value;
|
|
206
|
-
const isEmpty = (v) =>
|
|
207
|
-
v === undefined
|
|
208
|
-
|| v === null
|
|
209
|
-
|| v === ""
|
|
210
|
-
|| (Array.isArray(v) && v.length === 0);
|
|
211
|
-
const toList = (v) =>
|
|
212
|
-
String(v == null ? "" : v)
|
|
213
|
-
.split(",")
|
|
214
|
-
.map((s) => s.trim())
|
|
215
|
-
.filter((s) => s !== "");
|
|
216
|
-
switch (cond.operator) {
|
|
217
|
-
case "eq":
|
|
218
|
-
return String(actual) === String(expected);
|
|
219
|
-
case "ne":
|
|
220
|
-
return String(actual) !== String(expected);
|
|
221
|
-
case "gt":
|
|
222
|
-
return Number(actual) > Number(expected);
|
|
223
|
-
case "lt":
|
|
224
|
-
return Number(actual) < Number(expected);
|
|
225
|
-
case "ge":
|
|
226
|
-
return Number(actual) >= Number(expected);
|
|
227
|
-
case "le":
|
|
228
|
-
return Number(actual) <= Number(expected);
|
|
229
|
-
case "in":
|
|
230
|
-
return toList(expected).includes(String(actual));
|
|
231
|
-
case "nin":
|
|
232
|
-
return !toList(expected).includes(String(actual));
|
|
233
|
-
case "includes":
|
|
234
|
-
return Array.isArray(actual)
|
|
235
|
-
? actual.map(String).includes(String(expected))
|
|
236
|
-
: String(actual == null ? "" : actual).indexOf(String(expected)) > -1;
|
|
237
|
-
case "empty":
|
|
238
|
-
return isEmpty(actual);
|
|
239
|
-
case "notEmpty":
|
|
240
|
-
return !isEmpty(actual);
|
|
241
|
-
default:
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/* ------------------- 状态落地 ------------------- */
|
|
247
|
-
// entry: { widget, refKey, isContainer };getWidgetRef: (name) => 运行时组件ref
|
|
248
|
-
export function applyTargetState(entry, state, getWidgetRef) {
|
|
249
|
-
if (!entry || !state) return;
|
|
250
|
-
const widget = entry.widget;
|
|
251
|
-
const isContainer = entry.isContainer;
|
|
252
|
-
const ref = getWidgetRef ? getWidgetRef(entry.refKey) : null;
|
|
253
|
-
const hasVisible = state.visible !== undefined && state.visible !== null;
|
|
254
|
-
if (ref) {
|
|
255
|
-
if (hasVisible && ref.setHidden) ref.setHidden(!state.visible);
|
|
256
|
-
if (isContainer) return;
|
|
257
|
-
if (state.required !== undefined && state.required !== null && ref.setRequired) {
|
|
258
|
-
ref.setRequired(!!state.required);
|
|
259
|
-
}
|
|
260
|
-
if (state.readonly !== undefined && state.readonly !== null && ref.setReadonly) {
|
|
261
|
-
ref.setReadonly(!!state.readonly);
|
|
262
|
-
}
|
|
263
|
-
if (state.disabled !== undefined && state.disabled !== null && ref.setDisabled) {
|
|
264
|
-
ref.setDisabled(!!state.disabled);
|
|
265
|
-
}
|
|
266
|
-
if (state.options !== undefined && state.options !== null && ref.setOptions) {
|
|
267
|
-
ref.setOptions(state.options);
|
|
268
|
-
}
|
|
269
|
-
if (state.value !== undefined && ref.setValue) {
|
|
270
|
-
ref.setValue(state.value);
|
|
271
|
-
}
|
|
272
|
-
} else {
|
|
273
|
-
if (hasVisible) widget.options.hidden = !state.visible;
|
|
274
|
-
if (isContainer) return;
|
|
275
|
-
if (state.required !== undefined && state.required !== null) {
|
|
276
|
-
widget.options.required = !!state.required;
|
|
277
|
-
}
|
|
278
|
-
if (state.readonly !== undefined && state.readonly !== null) {
|
|
279
|
-
widget.options.readonly = !!state.readonly;
|
|
280
|
-
}
|
|
281
|
-
if (state.disabled !== undefined && state.disabled !== null) {
|
|
282
|
-
widget.options.disabled = !!state.disabled;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|