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.
- package/package.json +1 -1
- package/src/components/excelExport/conditionExportConfig.js +112 -0
- package/src/components/excelExport/exportType.js +8 -0
- package/src/components/excelExport/index.vue +7 -1
- package/src/components/excelExport/mixins.js +410 -259
- 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/form-widget/field-widget/select-export-item-button-widget.vue +2 -1
- package/src/components/xform/form-designer/form-widget/field-widget/table-export-button-widget.vue +2 -1
- 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-designer/setting-panel/property-editor/field-table-export-button/empty-number-input.vue +51 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +27 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/table-export-button-editor.vue +33 -3
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +6 -0
- package/src/components/xform/form-render/container-item/data-table-mixin.js +6 -6
- 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
|
@@ -19,10 +19,29 @@
|
|
|
19
19
|
></el-switch>
|
|
20
20
|
</el-form-item>
|
|
21
21
|
<el-form-item label="导出每页查询数量" class="form-item-label-top">
|
|
22
|
-
<
|
|
22
|
+
<empty-number-input
|
|
23
23
|
v-model="optionModel.exportPageSize"
|
|
24
24
|
:max="optionModel.showImageAtTable ? 150 : 1000"
|
|
25
|
-
|
|
25
|
+
:placeholder="'默认 ' + defaultPageSize"
|
|
26
|
+
></empty-number-input>
|
|
27
|
+
</el-form-item>
|
|
28
|
+
<el-form-item label="最大查询总数" class="form-item-label-top">
|
|
29
|
+
<empty-number-input
|
|
30
|
+
v-model="optionModel.maxQueryTotal"
|
|
31
|
+
:placeholder="'默认 ' + defaultMaxQueryTotal"
|
|
32
|
+
></empty-number-input>
|
|
33
|
+
<div class="export-item-columns-tip">
|
|
34
|
+
条件导出最多拉取的行数。留空则使用全局逻辑参数(默认 {{ defaultMaxQueryTotal }})
|
|
35
|
+
</div>
|
|
36
|
+
</el-form-item>
|
|
37
|
+
<el-form-item label="每个文件最大数据量" class="form-item-label-top">
|
|
38
|
+
<empty-number-input
|
|
39
|
+
v-model="optionModel.limitFileSize"
|
|
40
|
+
:placeholder="'默认 ' + defaultLimitFileSize"
|
|
41
|
+
></empty-number-input>
|
|
42
|
+
<div class="export-item-columns-tip">
|
|
43
|
+
单个 Excel 最多行数,超出则分多个文件。留空则使用全局逻辑参数(默认 {{ defaultLimitFileSize }})
|
|
44
|
+
</div>
|
|
26
45
|
</el-form-item>
|
|
27
46
|
<el-form-item label="导出参数" label-width="150px">
|
|
28
47
|
<a
|
|
@@ -80,12 +99,15 @@
|
|
|
80
99
|
import i18n from "../../../../utils/i18n";
|
|
81
100
|
import eventMixin from "../event-handler/eventMixin";
|
|
82
101
|
import exportItemColumnsDialog from "../container-data-table/exportItemColumns-dialog.vue";
|
|
102
|
+
import { DEFAULT_CONDITION_EXPORT_CONFIG } from "@base/components/excelExport/conditionExportConfig";
|
|
103
|
+
import emptyNumberInput from "./empty-number-input.vue";
|
|
83
104
|
|
|
84
105
|
export default {
|
|
85
106
|
name: "select-export-item-button-editor",
|
|
86
107
|
mixins: [i18n, eventMixin],
|
|
87
108
|
components: {
|
|
88
109
|
exportItemColumnsDialog,
|
|
110
|
+
emptyNumberInput,
|
|
89
111
|
},
|
|
90
112
|
props: {
|
|
91
113
|
designer: Object,
|
|
@@ -98,6 +120,9 @@ export default {
|
|
|
98
120
|
// 与数据表格属性面板同一套:脚本里可直接用 dataId / formCode
|
|
99
121
|
tableConfigParams: ["dataId", "formCode"],
|
|
100
122
|
showExportItemColumnsDialog: false,
|
|
123
|
+
defaultPageSize: DEFAULT_CONDITION_EXPORT_CONFIG.pageSize,
|
|
124
|
+
defaultMaxQueryTotal: DEFAULT_CONDITION_EXPORT_CONFIG.maxQueryTotal,
|
|
125
|
+
defaultLimitFileSize: DEFAULT_CONDITION_EXPORT_CONFIG.limitFileSize,
|
|
101
126
|
};
|
|
102
127
|
},
|
|
103
128
|
methods: {
|
|
@@ -13,8 +13,23 @@
|
|
|
13
13
|
<el-switch v-model="optionModel.showImageAtTable" @change="changeShowImageAtTable"></el-switch>
|
|
14
14
|
</el-form-item>
|
|
15
15
|
<el-form-item label="导出每页查询数量" class="form-item-label-top">
|
|
16
|
-
<
|
|
17
|
-
|
|
16
|
+
<empty-number-input v-model="optionModel.exportPageSize"
|
|
17
|
+
:max="optionModel.showImageAtTable?150:1000"
|
|
18
|
+
:placeholder="'默认 ' + defaultPageSize"></empty-number-input>
|
|
19
|
+
</el-form-item>
|
|
20
|
+
<el-form-item label="最大查询总数" class="form-item-label-top">
|
|
21
|
+
<empty-number-input v-model="optionModel.maxQueryTotal"
|
|
22
|
+
:placeholder="'默认 ' + defaultMaxQueryTotal"></empty-number-input>
|
|
23
|
+
<div class="export-limit-tip">
|
|
24
|
+
条件导出最多拉取的行数。留空则使用全局逻辑参数(默认 {{ defaultMaxQueryTotal }})
|
|
25
|
+
</div>
|
|
26
|
+
</el-form-item>
|
|
27
|
+
<el-form-item label="每个文件最大数据量" class="form-item-label-top">
|
|
28
|
+
<empty-number-input v-model="optionModel.limitFileSize"
|
|
29
|
+
:placeholder="'默认 ' + defaultLimitFileSize"></empty-number-input>
|
|
30
|
+
<div class="export-limit-tip">
|
|
31
|
+
单个 Excel 最多行数,超出则分多个文件。留空则使用全局逻辑参数(默认 {{ defaultLimitFileSize }})
|
|
32
|
+
</div>
|
|
18
33
|
</el-form-item>
|
|
19
34
|
<el-form-item label="导出参数" label-width="150px">
|
|
20
35
|
<a href="javascript:void(0);" class="a-link link-oneLind"
|
|
@@ -30,10 +45,15 @@
|
|
|
30
45
|
import i18n from "../../../../../../components/xform/utils/i18n";
|
|
31
46
|
import eventMixin
|
|
32
47
|
from "../../../../../../components/xform/form-designer/setting-panel/property-editor/event-handler/eventMixin";
|
|
48
|
+
import { DEFAULT_CONDITION_EXPORT_CONFIG } from "@base/components/excelExport/conditionExportConfig";
|
|
49
|
+
import emptyNumberInput from "./empty-number-input.vue";
|
|
33
50
|
|
|
34
51
|
export default {
|
|
35
52
|
name: "table-export-button-editor",
|
|
36
53
|
mixins: [i18n, eventMixin],
|
|
54
|
+
components: {
|
|
55
|
+
emptyNumberInput,
|
|
56
|
+
},
|
|
37
57
|
props: {
|
|
38
58
|
designer: Object,
|
|
39
59
|
selectedWidget: Object,
|
|
@@ -42,6 +62,9 @@ export default {
|
|
|
42
62
|
data() {
|
|
43
63
|
return {
|
|
44
64
|
eventParams: [],
|
|
65
|
+
defaultPageSize: DEFAULT_CONDITION_EXPORT_CONFIG.pageSize,
|
|
66
|
+
defaultMaxQueryTotal: DEFAULT_CONDITION_EXPORT_CONFIG.maxQueryTotal,
|
|
67
|
+
defaultLimitFileSize: DEFAULT_CONDITION_EXPORT_CONFIG.limitFileSize,
|
|
45
68
|
};
|
|
46
69
|
},
|
|
47
70
|
methods: {
|
|
@@ -57,4 +80,11 @@ export default {
|
|
|
57
80
|
};
|
|
58
81
|
</script>
|
|
59
82
|
|
|
60
|
-
<style scoped
|
|
83
|
+
<style scoped>
|
|
84
|
+
.export-limit-tip {
|
|
85
|
+
line-height: 18px;
|
|
86
|
+
color: #909399;
|
|
87
|
+
font-size: 12px;
|
|
88
|
+
margin-top: 4px;
|
|
89
|
+
}
|
|
90
|
+
</style>
|
|
@@ -3287,6 +3287,9 @@ export const advancedFields = [
|
|
|
3287
3287
|
tableRef: "",
|
|
3288
3288
|
tableExportParam: "",
|
|
3289
3289
|
showImageAtTable: false,
|
|
3290
|
+
exportPageSize: null,
|
|
3291
|
+
maxQueryTotal: null,
|
|
3292
|
+
limitFileSize: null,
|
|
3290
3293
|
tableExportFlag: 1,
|
|
3291
3294
|
|
|
3292
3295
|
onCreated: "",
|
|
@@ -3351,6 +3354,9 @@ export const advancedFields = [
|
|
|
3351
3354
|
tableRef: "",
|
|
3352
3355
|
tableExportParam: "",
|
|
3353
3356
|
showImageAtTable: false,
|
|
3357
|
+
exportPageSize: null,
|
|
3358
|
+
maxQueryTotal: null,
|
|
3359
|
+
limitFileSize: null,
|
|
3354
3360
|
selectExportItemFlag: 1,
|
|
3355
3361
|
exportItemConditionEnabled: !1,
|
|
3356
3362
|
// 按钮级明细导出配置:三项各自独立,留空的那项沿用数据表格属性上维护的
|
|
@@ -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} 首次初始化是否跳过动态列加载。 */
|
|
@@ -2800,7 +2798,9 @@ modules = {
|
|
|
2800
2798
|
if (
|
|
2801
2799
|
customParam?.exportParam?.type !== EXPORT_TYPE.ITEM_SELECTED
|
|
2802
2800
|
) {
|
|
2803
|
-
formData =
|
|
2801
|
+
formData = customParam?.exportParam?.exportQuerySnapshot !== undefined
|
|
2802
|
+
? this.$baseLodash.cloneDeep(customParam.exportParam.exportQuerySnapshot)
|
|
2803
|
+
: tableOption.param ? tableOption.param() || {} : {};
|
|
2804
2804
|
}
|
|
2805
2805
|
const queryParams = Object.assign({}, formData);
|
|
2806
2806
|
|
|
@@ -4539,7 +4539,7 @@ modules = {
|
|
|
4539
4539
|
try {
|
|
4540
4540
|
// 行内保存只提交当前行,校验范围同步收敛到当前行:其他行与表外字段
|
|
4541
4541
|
// 的必填不该拦住单行保存(整体保存仍走 formRef.validate 的全量校验)
|
|
4542
|
-
const controlled = formRef.
|
|
4542
|
+
const controlled = formRef.isFieldControlEnabled();
|
|
4543
4543
|
const rowValid = controlled ? await this.validateEditRowAsync(obj.row) : this.validateEditRow(obj.row);
|
|
4544
4544
|
if (!rowValid) return false;
|
|
4545
4545
|
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];
|
|
@@ -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;
|