cloud-web-corejs 1.0.54-dev.684 → 1.0.54-dev.686
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/api/user.js +15 -2
- package/src/components/VabUpload/fileLibraryDialog.vue +296 -0
- package/src/components/VabUpload/index.js +22 -2
- package/src/components/VabUpload/index.vue +9 -1
- package/src/components/VabUpload/mixins/fileLibraryDialog.js +1112 -0
- package/src/components/VabUpload/mixins.js +106 -47
- package/src/components/baseArea/index.vue +23 -1
- package/src/components/xform/form-designer/designer.js +7 -0
- package/src/components/xform/form-designer/setting-panel/form-dynamicField-setting.vue +601 -0
- package/src/components/xform/form-designer/setting-panel/form-setting.vue +9 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/container-table/table-dynamicField-editor.vue +306 -0
- package/src/components/xform/form-designer/setting-panel/propertyRegister.js +1 -0
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +18 -0
- package/src/components/xform/form-render/container-item/dynamicFieldEngine.js +285 -0
- package/src/components/xform/form-render/container-item/dynamicFieldMixin.js +322 -0
- package/src/components/xform/form-render/container-item/table-item.vue +3 -5
- package/src/components/xform/form-render/formDynamicFieldMixin.js +131 -0
- package/src/components/xform/form-render/index.vue +2 -1
- package/src/components/xform/mixins/defaultHandle.js +33 -0
- package/src/components/xform/utils/util.js +7 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { generateId } from "../../../../components/xform/utils/util";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 表格布局容器(table/h5-table)专用混入。
|
|
5
|
+
*
|
|
6
|
+
* 提供两类「布局表格」特有能力(动态字段状态控制已统一收敛到表单设置,见 formDynamicFieldMixin):
|
|
7
|
+
* 1. 后台字段定义(dynamicSchemaEnabled):字段定义由后台查询下发,运行时生成并插入到行布局中。
|
|
8
|
+
* 2. 行折叠(默认行为):整行字段均隐藏时折叠该行(响应式,随字段显隐自动更新)。
|
|
9
|
+
*
|
|
10
|
+
* 依赖宿主组件已混入:containerItemMixin(formModel/formHttp/handleCustomEvent/designState)
|
|
11
|
+
* 与 refMixin(getFormRef)。
|
|
12
|
+
*/
|
|
13
|
+
const dynamicFieldMixin = {
|
|
14
|
+
data() {
|
|
15
|
+
return {
|
|
16
|
+
// anchor=replace 时被隐藏的占位行 id(响应式,驱动 rowHiddenMap 重算)
|
|
17
|
+
anchorHiddenRowId: null,
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
created() {
|
|
21
|
+
// 后台动态生成的行 id 集合(用于去重/清理)
|
|
22
|
+
this._generatedRowIds = [];
|
|
23
|
+
},
|
|
24
|
+
mounted() {
|
|
25
|
+
this.initDynamicSchema();
|
|
26
|
+
},
|
|
27
|
+
computed: {
|
|
28
|
+
// 行折叠状态:rowIdx -> true(折叠/隐藏)。响应式依赖字段 hidden 与 anchorHiddenRowId
|
|
29
|
+
// 行折叠为默认行为:整行字段均隐藏时自动折叠,避免布局空洞
|
|
30
|
+
rowHiddenMap() {
|
|
31
|
+
const map = {};
|
|
32
|
+
if (!this.supportsRowLayout()) return map;
|
|
33
|
+
const rows = this.widget.rows || [];
|
|
34
|
+
rows.forEach((row, rowIdx) => {
|
|
35
|
+
if (this.anchorHiddenRowId && row.id === this.anchorHiddenRowId) {
|
|
36
|
+
map[rowIdx] = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const fields = [];
|
|
40
|
+
(row.cols || []).forEach((cell) => {
|
|
41
|
+
if (cell.merged) return;
|
|
42
|
+
this.collectFieldsDeep(cell.widgetList || [], fields);
|
|
43
|
+
});
|
|
44
|
+
if (!fields.length) {
|
|
45
|
+
map[rowIdx] = false;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
map[rowIdx] = fields.every((w) => !!w.options.hidden);
|
|
49
|
+
});
|
|
50
|
+
return map;
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
methods: {
|
|
54
|
+
// 容器是否为行布局(table/h5-table)
|
|
55
|
+
supportsRowLayout() {
|
|
56
|
+
return Array.isArray(this.widget && this.widget.rows);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
isRowVisible(rowIdx) {
|
|
60
|
+
return !this.rowHiddenMap[rowIdx];
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/* ------------------- 后台字段定义模式(行布局容器) ------------------- */
|
|
64
|
+
initDynamicSchema() {
|
|
65
|
+
if (this.designState || !this.widget) return;
|
|
66
|
+
const options = this.widget.options || {};
|
|
67
|
+
if (!options.dynamicSchemaEnabled || !this.supportsRowLayout()) return;
|
|
68
|
+
this.$nextTick(() => {
|
|
69
|
+
this.loadDynamicSchema();
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
loadDynamicSchema() {
|
|
74
|
+
const options = this.widget.options;
|
|
75
|
+
if (
|
|
76
|
+
this.designState
|
|
77
|
+
|| !options.dynamicSchemaEnabled
|
|
78
|
+
|| !options.dynamicSchemaScriptCode
|
|
79
|
+
|| !this.supportsRowLayout()
|
|
80
|
+
) {
|
|
81
|
+
return Promise.resolve();
|
|
82
|
+
}
|
|
83
|
+
const extra = this.handleCustomEvent(options.dynamicSchemaScriptParam) || {};
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
this.formHttp({
|
|
86
|
+
scriptCode: options.dynamicSchemaScriptCode,
|
|
87
|
+
isLoading: false,
|
|
88
|
+
data: {
|
|
89
|
+
formData: this.formModel,
|
|
90
|
+
...extra,
|
|
91
|
+
},
|
|
92
|
+
success: (res) => {
|
|
93
|
+
const defs = this.resolveSchemaDefs(res);
|
|
94
|
+
this.buildDynamicRows(defs);
|
|
95
|
+
this.$nextTick(() => resolve());
|
|
96
|
+
},
|
|
97
|
+
fail: () => resolve(),
|
|
98
|
+
error: () => resolve(),
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
resolveSchemaDefs(res) {
|
|
104
|
+
const options = this.widget.options;
|
|
105
|
+
let defs = [];
|
|
106
|
+
if (options.dynamicSchemaConvert) {
|
|
107
|
+
const result = this.handleCustomEvent(
|
|
108
|
+
options.dynamicSchemaConvert,
|
|
109
|
+
["res"],
|
|
110
|
+
[res]
|
|
111
|
+
);
|
|
112
|
+
if (Array.isArray(result)) {
|
|
113
|
+
defs = result;
|
|
114
|
+
} else if (result && Array.isArray(result.fields)) {
|
|
115
|
+
defs = result.fields;
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
const objx = res && res.objx;
|
|
119
|
+
if (Array.isArray(objx)) {
|
|
120
|
+
defs = objx;
|
|
121
|
+
} else if (objx && Array.isArray(objx.fields)) {
|
|
122
|
+
defs = objx.fields;
|
|
123
|
+
} else if (objx && Array.isArray(objx.columns)) {
|
|
124
|
+
defs = objx.columns;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return defs || [];
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
buildDynamicRows(defs) {
|
|
131
|
+
const options = this.widget.options;
|
|
132
|
+
const formRef = this.getFormRef ? this.getFormRef() : null;
|
|
133
|
+
if (!formRef || !Array.isArray(defs) || !Array.isArray(this.widget.rows)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.removeGeneratedRows();
|
|
138
|
+
this.anchorHiddenRowId = null;
|
|
139
|
+
|
|
140
|
+
const widgets = [];
|
|
141
|
+
defs.forEach((def) => {
|
|
142
|
+
const w = this.createFieldWidgetFromDef(def, formRef);
|
|
143
|
+
if (w) widgets.push({ widget: w, colspan: def.colspan || 1 });
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const mode = options.dynamicSchemaMode || "append";
|
|
147
|
+
let anchorIdx = -1;
|
|
148
|
+
let cellTemplates = null;
|
|
149
|
+
if (mode === "anchor" && options.dynamicSchemaAnchorRowId) {
|
|
150
|
+
anchorIdx = (this.widget.rows || []).findIndex(
|
|
151
|
+
(r) => r.id === options.dynamicSchemaAnchorRowId
|
|
152
|
+
);
|
|
153
|
+
if (anchorIdx > -1 && options.dynamicSchemaInheritLayout) {
|
|
154
|
+
const anchorRow = this.widget.rows[anchorIdx];
|
|
155
|
+
cellTemplates = (anchorRow.cols || []).filter((c) => !c.merged);
|
|
156
|
+
if (!cellTemplates.length) cellTemplates = null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const rows = cellTemplates
|
|
161
|
+
? this.layoutByTemplate(widgets, cellTemplates)
|
|
162
|
+
: this.layoutByColumns(
|
|
163
|
+
widgets,
|
|
164
|
+
Math.max(1, parseInt(options.dynamicSchemaColumns, 10) || 4)
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
if (mode === "replace") {
|
|
168
|
+
this.widget.rows.splice(0, this.widget.rows.length, ...rows);
|
|
169
|
+
} else if (mode === "anchor" && anchorIdx > -1) {
|
|
170
|
+
const position = options.dynamicSchemaAnchorPosition || "replace";
|
|
171
|
+
if (position === "before") {
|
|
172
|
+
this.widget.rows.splice(anchorIdx, 0, ...rows);
|
|
173
|
+
} else if (position === "after") {
|
|
174
|
+
this.widget.rows.splice(anchorIdx + 1, 0, ...rows);
|
|
175
|
+
} else {
|
|
176
|
+
this.anchorHiddenRowId = this.widget.rows[anchorIdx].id;
|
|
177
|
+
this.widget.rows.splice(anchorIdx + 1, 0, ...rows);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
this.widget.rows.push(...rows);
|
|
181
|
+
}
|
|
182
|
+
this._generatedRowIds = rows.map((r) => r.id);
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
layoutByColumns(widgets, colCount) {
|
|
186
|
+
const rows = [];
|
|
187
|
+
let current = null;
|
|
188
|
+
let used = 0;
|
|
189
|
+
widgets.forEach((item) => {
|
|
190
|
+
const span = Math.min(colCount, item.colspan || 1);
|
|
191
|
+
if (!current || used + span > colCount) {
|
|
192
|
+
current = {
|
|
193
|
+
id: "table-row-dyn-" + generateId(),
|
|
194
|
+
merged: false,
|
|
195
|
+
cols: [],
|
|
196
|
+
};
|
|
197
|
+
rows.push(current);
|
|
198
|
+
used = 0;
|
|
199
|
+
}
|
|
200
|
+
current.cols.push(this.buildDynCell(item.widget, { colspan: span }));
|
|
201
|
+
used += span;
|
|
202
|
+
});
|
|
203
|
+
return rows;
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
layoutByTemplate(widgets, cellTemplates) {
|
|
207
|
+
const rows = [];
|
|
208
|
+
const perRow = cellTemplates.length;
|
|
209
|
+
for (let i = 0; i < widgets.length; i += perRow) {
|
|
210
|
+
const row = {
|
|
211
|
+
id: "table-row-dyn-" + generateId(),
|
|
212
|
+
merged: false,
|
|
213
|
+
cols: [],
|
|
214
|
+
};
|
|
215
|
+
for (let j = 0; j < perRow; j++) {
|
|
216
|
+
const tpl = cellTemplates[j];
|
|
217
|
+
const item = widgets[i + j];
|
|
218
|
+
row.cols.push(
|
|
219
|
+
this.buildDynCell(item ? item.widget : null, {
|
|
220
|
+
colspan: (tpl.options && tpl.options.colspan) || 1,
|
|
221
|
+
cellWidth: (tpl.options && tpl.options.cellWidth) || "",
|
|
222
|
+
cellHeight: (tpl.options && tpl.options.cellHeight) || "",
|
|
223
|
+
customClass: (tpl.options && tpl.options.customClass) || "",
|
|
224
|
+
})
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
rows.push(row);
|
|
228
|
+
}
|
|
229
|
+
return rows;
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
buildDynCell(fieldWidget, opt) {
|
|
233
|
+
const cellId = "table-cell-dyn-" + generateId();
|
|
234
|
+
return {
|
|
235
|
+
id: cellId,
|
|
236
|
+
type: "table-cell",
|
|
237
|
+
category: "container",
|
|
238
|
+
internal: true,
|
|
239
|
+
merged: false,
|
|
240
|
+
widgetList: fieldWidget ? [fieldWidget] : [],
|
|
241
|
+
options: {
|
|
242
|
+
name: cellId,
|
|
243
|
+
cellWidth: opt.cellWidth || "",
|
|
244
|
+
cellHeight: opt.cellHeight || "",
|
|
245
|
+
colspan: opt.colspan || 1,
|
|
246
|
+
rowspan: 1,
|
|
247
|
+
customClass: opt.customClass || "",
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
createFieldWidgetFromDef(def, formRef) {
|
|
253
|
+
if (!def) return null;
|
|
254
|
+
const type = def.type || "input";
|
|
255
|
+
const template = formRef.getFieldWidgetByType(type);
|
|
256
|
+
if (!template) return null;
|
|
257
|
+
const key = def.keyName || def.field || def.name;
|
|
258
|
+
if (!key) return null;
|
|
259
|
+
const widget = formRef.copyNewFieldWidget(template);
|
|
260
|
+
widget.options.name = key;
|
|
261
|
+
widget.options.keyName = key;
|
|
262
|
+
widget.options.keyNameEnabled = true;
|
|
263
|
+
if (def.label !== undefined) widget.options.label = def.label;
|
|
264
|
+
if (def.required !== undefined) widget.options.required = !!def.required;
|
|
265
|
+
if (def.readonly !== undefined) widget.options.readonly = !!def.readonly;
|
|
266
|
+
if (def.disabled !== undefined) widget.options.disabled = !!def.disabled;
|
|
267
|
+
if (def.hidden !== undefined) widget.options.hidden = !!def.hidden;
|
|
268
|
+
if (def.defaultValue !== undefined) {
|
|
269
|
+
widget.options.defaultValue = def.defaultValue;
|
|
270
|
+
}
|
|
271
|
+
if (def.placeholder !== undefined && "placeholder" in widget.options) {
|
|
272
|
+
widget.options.placeholder = def.placeholder;
|
|
273
|
+
}
|
|
274
|
+
if (Array.isArray(def.optionItems) && "optionItems" in widget.options) {
|
|
275
|
+
widget.options.optionItems = def.optionItems;
|
|
276
|
+
}
|
|
277
|
+
if (def.options && typeof def.options === "object") {
|
|
278
|
+
Object.keys(def.options).forEach((k) => {
|
|
279
|
+
widget.options[k] = def.options[k];
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
return widget;
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
removeGeneratedRows() {
|
|
286
|
+
if (!this._generatedRowIds || !this._generatedRowIds.length) return;
|
|
287
|
+
if (!Array.isArray(this.widget.rows)) {
|
|
288
|
+
this._generatedRowIds = [];
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const ids = this._generatedRowIds;
|
|
292
|
+
for (let i = this.widget.rows.length - 1; i >= 0; i--) {
|
|
293
|
+
if (ids.indexOf(this.widget.rows[i].id) > -1) {
|
|
294
|
+
this.widget.rows.splice(i, 1);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
this._generatedRowIds = [];
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
collectFieldsDeep(list, out) {
|
|
301
|
+
(list || []).forEach((w) => {
|
|
302
|
+
if (!w) return;
|
|
303
|
+
if (w.category === "container") {
|
|
304
|
+
if (Array.isArray(w.rows)) {
|
|
305
|
+
w.rows.forEach((row) =>
|
|
306
|
+
this.collectFieldsDeep((row && row.cols) || [], out)
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
["cols", "tabs", "widgetList", "panes", "buttonWidgetList"].forEach(
|
|
310
|
+
(k) => {
|
|
311
|
+
if (Array.isArray(w[k])) this.collectFieldsDeep(w[k], out);
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
} else if (w.formItemFlag) {
|
|
315
|
+
out.push(w);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
export default dynamicFieldMixin;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<table :ref="widget.id" class="table-layout table-d-box" :class="[customClass,widget.options.styleTableClass]"
|
|
7
7
|
:style="tableStyle">
|
|
8
8
|
<tbody>
|
|
9
|
-
<tr v-for="(row, rowIdx) in widget.rows" :key="row.id">
|
|
9
|
+
<tr v-for="(row, rowIdx) in widget.rows" :key="row.id" v-show="isRowVisible(rowIdx)">
|
|
10
10
|
<template v-for="(colWidget, colIdx) in row.cols">
|
|
11
11
|
<table-cell-item v-if="!colWidget.merged" :widget="colWidget" :key="colIdx" :parent-list="widget.cols"
|
|
12
12
|
:row-index="rowIdx" :col-index="colIdx" :parent-widget="widget" :tableParam="tableParam"
|
|
@@ -32,11 +32,12 @@ import refMixin from "../../../../components/xform/form-render/refMixin"
|
|
|
32
32
|
import ContainerItemWrapper from './container-item-wrapper'
|
|
33
33
|
import TableCellItem from './table-cell-item'
|
|
34
34
|
import containerItemMixin from "./containerItemMixin";
|
|
35
|
+
import dynamicFieldMixin from "./dynamicFieldMixin";
|
|
35
36
|
|
|
36
37
|
export default {
|
|
37
38
|
name: "table-item",
|
|
38
39
|
componentName: 'ContainerItem',
|
|
39
|
-
mixins: [emitter, i18n, refMixin, containerItemMixin],
|
|
40
|
+
mixins: [emitter, i18n, refMixin, containerItemMixin, dynamicFieldMixin],
|
|
40
41
|
components: {
|
|
41
42
|
ContainerItemWrapper,
|
|
42
43
|
TableCellItem,
|
|
@@ -52,9 +53,6 @@ export default {
|
|
|
52
53
|
},
|
|
53
54
|
created() {
|
|
54
55
|
this.initRefList()
|
|
55
|
-
},
|
|
56
|
-
mounted() {
|
|
57
|
-
|
|
58
56
|
},
|
|
59
57
|
beforeDestroy() {
|
|
60
58
|
this.unregisterFromRefList()
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 表单级「动态字段规则」运行时混入(挂载于 VFormRender 根组件)。
|
|
3
|
+
*
|
|
4
|
+
* 配置来源:formConfig.dynamicFieldEnabled / dynamicFieldSourceType / dynamicFieldRules /
|
|
5
|
+
* dynamicFieldScriptCode / dynamicFieldScriptParam(额外参数) / dynamicFieldTriggerFields
|
|
6
|
+
* 作用范围:整个表单内任意字段 / 命名容器的 显隐/必填/只读/禁用/取值。
|
|
7
|
+
*
|
|
8
|
+
* 依赖根组件(indexMixin)已提供:formConfig、widgetList、formModel、getWidgetRef、formHttp。
|
|
9
|
+
*/
|
|
10
|
+
import {
|
|
11
|
+
buildFormTargetMap,
|
|
12
|
+
computeLocalStates,
|
|
13
|
+
applyTargetState,
|
|
14
|
+
} from "./container-item/dynamicFieldEngine";
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
created() {
|
|
18
|
+
// 目标key -> { widget, refKey, isContainer }
|
|
19
|
+
this._fdfMap = {};
|
|
20
|
+
// 设计期基线,未命中规则时还原
|
|
21
|
+
this._fdfBaseline = {};
|
|
22
|
+
this._fdfWatcher = null;
|
|
23
|
+
this._fdfTimer = null;
|
|
24
|
+
this._fdfInited = false;
|
|
25
|
+
},
|
|
26
|
+
watch: {
|
|
27
|
+
showFormContent(val) {
|
|
28
|
+
// 表单内容渲染(字段ref注册)完成后再初始化
|
|
29
|
+
if (val && !this._fdfInited) {
|
|
30
|
+
this.$nextTick(() => this.initFormDynamicFields());
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
beforeDestroy() {
|
|
35
|
+
if (this._fdfWatcher) {
|
|
36
|
+
this._fdfWatcher();
|
|
37
|
+
this._fdfWatcher = null;
|
|
38
|
+
}
|
|
39
|
+
if (this._fdfTimer) {
|
|
40
|
+
clearTimeout(this._fdfTimer);
|
|
41
|
+
this._fdfTimer = null;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
methods: {
|
|
45
|
+
initFormDynamicFields() {
|
|
46
|
+
const cfg = this.formConfig || {};
|
|
47
|
+
if (!cfg.dynamicFieldEnabled) return;
|
|
48
|
+
this._fdfInited = true;
|
|
49
|
+
const { map, baseline } = buildFormTargetMap(this.widgetList);
|
|
50
|
+
this._fdfMap = map;
|
|
51
|
+
this._fdfBaseline = baseline;
|
|
52
|
+
this.applyFormDynamicFields();
|
|
53
|
+
this.setupFormDynamicWatcher();
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
applyFormDynamicFields() {
|
|
57
|
+
const cfg = this.formConfig || {};
|
|
58
|
+
if (!cfg.dynamicFieldEnabled) return;
|
|
59
|
+
if (cfg.dynamicFieldSourceType === "script") {
|
|
60
|
+
this.applyFormScriptStates();
|
|
61
|
+
} else {
|
|
62
|
+
const states = computeLocalStates(
|
|
63
|
+
cfg.dynamicFieldRules || [],
|
|
64
|
+
this._fdfBaseline,
|
|
65
|
+
this.formModel
|
|
66
|
+
);
|
|
67
|
+
Object.keys(states).forEach((key) =>
|
|
68
|
+
this.applyFormFieldState(key, states[key])
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
applyFormFieldState(targetKey, state) {
|
|
74
|
+
const entry = this._fdfMap[targetKey];
|
|
75
|
+
if (!entry) return;
|
|
76
|
+
applyTargetState(entry, state, (name) => this.getWidgetRef(name));
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
setupFormDynamicWatcher() {
|
|
80
|
+
const cfg = this.formConfig || {};
|
|
81
|
+
if (cfg.dynamicFieldSourceType === "script") {
|
|
82
|
+
const triggers = cfg.dynamicFieldTriggerFields || [];
|
|
83
|
+
if (!triggers.length) return;
|
|
84
|
+
this._fdfWatcher = this.$watch(
|
|
85
|
+
() =>
|
|
86
|
+
triggers
|
|
87
|
+
.map((f) => this.formModel && this.formModel[f])
|
|
88
|
+
.join("\u0001"),
|
|
89
|
+
() => this.debouncedFormApply()
|
|
90
|
+
);
|
|
91
|
+
} else {
|
|
92
|
+
this._fdfWatcher = this.$watch(
|
|
93
|
+
() => this.formModel,
|
|
94
|
+
() => this.debouncedFormApply(),
|
|
95
|
+
{ deep: true }
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
debouncedFormApply() {
|
|
101
|
+
if (this._fdfTimer) clearTimeout(this._fdfTimer);
|
|
102
|
+
this._fdfTimer = setTimeout(() => this.applyFormDynamicFields(), 120);
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
applyFormScriptStates() {
|
|
106
|
+
const cfg = this.formConfig || {};
|
|
107
|
+
if (!cfg.dynamicFieldScriptCode) return;
|
|
108
|
+
const extra = this.handleCustomEvent(cfg.dynamicFieldScriptParam) || {};
|
|
109
|
+
this.formHttp({
|
|
110
|
+
scriptCode: cfg.dynamicFieldScriptCode,
|
|
111
|
+
isLoading: false,
|
|
112
|
+
data: {
|
|
113
|
+
formData: this.formModel,
|
|
114
|
+
...extra,
|
|
115
|
+
},
|
|
116
|
+
success: (res) => {
|
|
117
|
+
const result = (res && res.objx) || {};
|
|
118
|
+
const fieldStates = result.fieldStates || {};
|
|
119
|
+
Object.keys(this._fdfBaseline).forEach((key) => {
|
|
120
|
+
if (!fieldStates[key]) {
|
|
121
|
+
this.applyFormFieldState(key, this._fdfBaseline[key]);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
Object.keys(fieldStates).forEach((key) =>
|
|
125
|
+
this.applyFormFieldState(key, fieldStates[key])
|
|
126
|
+
);
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
@@ -113,6 +113,7 @@
|
|
|
113
113
|
import "./container-item/index";
|
|
114
114
|
import FieldComponents from "../../../components/xform/form-designer/form-widget/field-widget/index";
|
|
115
115
|
import indexMixin from "../../../components/xform/form-render/indexMixin";
|
|
116
|
+
import formDynamicFieldMixin from "../../../components/xform/form-render/formDynamicFieldMixin";
|
|
116
117
|
|
|
117
118
|
export default {
|
|
118
119
|
name: "VFormRender",
|
|
@@ -135,7 +136,7 @@ export default {
|
|
|
135
136
|
"../../../components/xform/form-designer/form-widget/dialog/fileReferenceDialog.vue"
|
|
136
137
|
)
|
|
137
138
|
},
|
|
138
|
-
mixins: [indexMixin],
|
|
139
|
+
mixins: [indexMixin, formDynamicFieldMixin],
|
|
139
140
|
};
|
|
140
141
|
</script>
|
|
141
142
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import moment from "moment";
|
|
2
|
+
import { saveUserLog } from "@/api/user";
|
|
3
|
+
import settingConfig from "@/settings";
|
|
2
4
|
|
|
3
5
|
let modules = {};
|
|
4
6
|
modules = {
|
|
@@ -81,6 +83,32 @@ modules = {
|
|
|
81
83
|
};
|
|
82
84
|
return reqData;
|
|
83
85
|
},
|
|
86
|
+
onAfterSaveHandle(reqData, res, response) {
|
|
87
|
+
//保存成功后处理
|
|
88
|
+
this.writeSaveLog(reqData, res, response); //写入保存日志
|
|
89
|
+
},
|
|
90
|
+
writeSaveLog(reqData, res, response) {
|
|
91
|
+
//写入保存日志
|
|
92
|
+
if (settingConfig.formSaveLogEnabled && res.type === "success") {
|
|
93
|
+
let responseConfig = response.config || {};
|
|
94
|
+
let formRef = this.getFormRef ? this.getFormRef() : this;
|
|
95
|
+
let reportTemplate = formRef ? formRef.reportTemplate : null;
|
|
96
|
+
if (!reportTemplate) return;
|
|
97
|
+
let isAdd = !formRef.dataId;
|
|
98
|
+
let formName = reportTemplate?.formName;
|
|
99
|
+
let formCode = reportTemplate?.formCode;
|
|
100
|
+
let action = isAdd ? "新增成功" : "更新成功";
|
|
101
|
+
let content = `${formName}(${formCode}),${action}`;
|
|
102
|
+
let path = responseConfig.url.replace(responseConfig.baseURL, "");
|
|
103
|
+
saveUserLog({
|
|
104
|
+
data: {
|
|
105
|
+
path: path,
|
|
106
|
+
businessCode: content,
|
|
107
|
+
content: content,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
},
|
|
84
112
|
saveDefaultHandle(option) {
|
|
85
113
|
let formRef = this.getFormRef ? this.getFormRef() : this;
|
|
86
114
|
let formConfig = formRef.formConfig;
|
|
@@ -98,6 +126,10 @@ modules = {
|
|
|
98
126
|
formRef.validate((valid) => {
|
|
99
127
|
if (valid) {
|
|
100
128
|
let reqData = this.getReqFormData();
|
|
129
|
+
let callback = (res, response) => {
|
|
130
|
+
this.onAfterSaveHandle(reqData, res, response); //保存成功后处理
|
|
131
|
+
option?.callback && option.callback(res); //回调
|
|
132
|
+
};
|
|
101
133
|
this.formHttp({
|
|
102
134
|
// url: "/" + reportTemplate.serviceName + "/form_ins/saveUpdate",
|
|
103
135
|
scriptCode: scriptCode,
|
|
@@ -119,6 +151,7 @@ modules = {
|
|
|
119
151
|
});
|
|
120
152
|
},
|
|
121
153
|
...config,
|
|
154
|
+
callback: callback,
|
|
122
155
|
});
|
|
123
156
|
}
|
|
124
157
|
});
|
|
@@ -880,6 +880,13 @@ export function getDefaultFormConfig() {
|
|
|
880
880
|
otherTabList: [],
|
|
881
881
|
customListTabLabel: null,
|
|
882
882
|
globalConfig: null,
|
|
883
|
+
// 表单级动态字段规则:按本地规则/后台脚本动态控制整个表单内任意字段/容器的显隐/必填/只读/禁用/取值
|
|
884
|
+
dynamicFieldEnabled: false,
|
|
885
|
+
dynamicFieldSourceType: "local",
|
|
886
|
+
dynamicFieldRules: [],
|
|
887
|
+
dynamicFieldScriptCode: null,
|
|
888
|
+
dynamicFieldScriptParam: null,
|
|
889
|
+
dynamicFieldTriggerFields: [],
|
|
883
890
|
};
|
|
884
891
|
}
|
|
885
892
|
|