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.
@@ -0,0 +1,601 @@
1
+ <template>
2
+ <div class="form-dynamic-field-setting">
3
+ <el-form-item label="启用动态字段">
4
+ <el-switch v-model="formConfig.dynamicFieldEnabled"></el-switch>
5
+ <div class="tip-text">
6
+ 根据表单数据/后台脚本动态控制整个表单内任意字段、容器的显隐等状态
7
+ </div>
8
+ </el-form-item>
9
+
10
+ <template v-if="formConfig.dynamicFieldEnabled">
11
+ <el-form-item label="数据来源">
12
+ <el-radio-group v-model="formConfig.dynamicFieldSourceType" size="mini">
13
+ <el-radio-button label="local">本地规则</el-radio-button>
14
+ <el-radio-button label="script">后台脚本</el-radio-button>
15
+ </el-radio-group>
16
+ </el-form-item>
17
+
18
+ <template v-if="formConfig.dynamicFieldSourceType === 'local'">
19
+ <el-form-item label="字段规则">
20
+ <el-button
21
+ type="primary"
22
+ plain
23
+ size="mini"
24
+ icon="el-icon-setting"
25
+ @click="openRuleDialog"
26
+ >
27
+ 配置规则({{ (formConfig.dynamicFieldRules || []).length }})
28
+ </el-button>
29
+ </el-form-item>
30
+ </template>
31
+
32
+ <template v-if="formConfig.dynamicFieldSourceType === 'script'">
33
+ <el-form-item label="脚本编码">
34
+ <el-input
35
+ v-model="formConfig.dynamicFieldScriptCode"
36
+ size="mini"
37
+ placeholder="scriptCode 或 formCode/scriptCode"
38
+ ></el-input>
39
+ </el-form-item>
40
+ <el-form-item label="额外参数">
41
+ <a
42
+ href="javascript:void(0);"
43
+ class="a-link link-oneLind"
44
+ @click="editDynamicFieldScriptParam"
45
+ >
46
+ <span>{{ formConfig.dynamicFieldScriptParam }}</span>
47
+ <i class="el-icon-edit"></i>
48
+ </a>
49
+ <div class="tip-text">
50
+ 格式: return { stage:
51
+ formModel.status }
52
+ </div>
53
+ </el-form-item>
54
+ <el-form-item label="触发字段">
55
+ <el-select
56
+ v-model="formConfig.dynamicFieldTriggerFields"
57
+ multiple
58
+ filterable
59
+ size="mini"
60
+ style="width: 100%"
61
+ placeholder="字段值变化时重新请求后台"
62
+ >
63
+ <el-option
64
+ v-for="(n, idx) in treeOptions"
65
+ :key="n.value + '#' + idx"
66
+ :value="n.value"
67
+ :label="optPlainLabel(n)"
68
+ :disabled="n.isContainer"
69
+ >
70
+ <span
71
+ :style="{ paddingLeft: n.depth * 14 + 'px' }"
72
+ :class="{ 'opt-container': n.isContainer }"
73
+ >
74
+ <span v-if="n.isContainer" class="opt-tag"
75
+ >[{{ containerTypeLabel(n.type) }}]</span
76
+ >{{ n.baseLabel }}
77
+ </span>
78
+ </el-option>
79
+ </el-select>
80
+ <div class="tip-text">为空时仅在初始化时请求一次后台脚本</div>
81
+ </el-form-item>
82
+ <div class="tip-text">
83
+ 后台返回 fieldStates 的 key
84
+ 可为字段名,也可为「命名容器」名以控制其显隐(容器仅 visible 生效)
85
+ </div>
86
+ </template>
87
+ </template>
88
+
89
+ <el-dialog
90
+ title="表单动态字段规则"
91
+ :visible.sync="ruleDialogVisible"
92
+ :append-to-body="true"
93
+ width="760px"
94
+ custom-class="dynamic-field-rule-dialog"
95
+ >
96
+ <div class="rule-list">
97
+ <div
98
+ v-for="(rule, rIdx) in editingRules"
99
+ :key="rule.id"
100
+ class="rule-card"
101
+ >
102
+ <div class="rule-card-header">
103
+ <span class="rule-title">规则 {{ rIdx + 1 }}</span>
104
+ <el-button
105
+ type="text"
106
+ icon="el-icon-delete"
107
+ class="danger-text"
108
+ @click="removeRule(rIdx)"
109
+ >
110
+ 删除规则
111
+ </el-button>
112
+ </div>
113
+
114
+ <div class="rule-section">
115
+ <div class="rule-section-title">
116
+ <span>当满足</span>
117
+ <el-radio-group v-model="rule.logic" size="mini">
118
+ <el-radio-button label="and">全部条件</el-radio-button>
119
+ <el-radio-button label="or">任一条件</el-radio-button>
120
+ </el-radio-group>
121
+ </div>
122
+ <div
123
+ v-for="(cond, cIdx) in rule.conditions"
124
+ :key="cIdx"
125
+ class="rule-row"
126
+ >
127
+ <el-select
128
+ v-model="cond.field"
129
+ filterable
130
+ size="mini"
131
+ placeholder="字段"
132
+ class="cell-field"
133
+ >
134
+ <el-option
135
+ v-for="(n, idx) in treeOptions"
136
+ :key="n.value + '#' + idx"
137
+ :value="n.value"
138
+ :label="optPlainLabel(n)"
139
+ :disabled="n.isContainer"
140
+ >
141
+ <span
142
+ :style="{ paddingLeft: n.depth * 14 + 'px' }"
143
+ :class="{ 'opt-container': n.isContainer }"
144
+ >
145
+ <span v-if="n.isContainer" class="opt-tag"
146
+ >[{{ containerTypeLabel(n.type) }}]</span
147
+ >{{ n.baseLabel }}
148
+ </span>
149
+ </el-option>
150
+ </el-select>
151
+ <el-select
152
+ v-model="cond.operator"
153
+ size="mini"
154
+ placeholder="操作符"
155
+ class="cell-op"
156
+ >
157
+ <el-option
158
+ v-for="op in operatorOptions"
159
+ :key="op.value"
160
+ :label="op.label"
161
+ :value="op.value"
162
+ ></el-option>
163
+ </el-select>
164
+ <el-input
165
+ v-model="cond.value"
166
+ size="mini"
167
+ placeholder="值"
168
+ class="cell-value"
169
+ :disabled="op_noValue(cond.operator)"
170
+ ></el-input>
171
+ <el-button
172
+ type="text"
173
+ icon="el-icon-remove-outline"
174
+ class="danger-text"
175
+ @click="removeCondition(rule, cIdx)"
176
+ ></el-button>
177
+ </div>
178
+ <el-button
179
+ type="text"
180
+ icon="el-icon-plus"
181
+ @click="addCondition(rule)"
182
+ >添加条件</el-button
183
+ >
184
+ </div>
185
+
186
+ <div class="rule-section">
187
+ <div class="rule-section-title"><span>则设置字段/容器</span></div>
188
+ <div
189
+ v-for="(t, tIdx) in rule.targets"
190
+ :key="tIdx"
191
+ class="rule-row target-row"
192
+ >
193
+ <el-select
194
+ v-model="t.field"
195
+ filterable
196
+ size="mini"
197
+ placeholder="目标字段/容器"
198
+ class="cell-field"
199
+ >
200
+ <el-option
201
+ v-for="(n, idx) in treeOptions"
202
+ :key="n.value + '#' + idx"
203
+ :value="n.value"
204
+ :label="optPlainLabel(n)"
205
+ :disabled="n.isContainer && !n.hasName"
206
+ >
207
+ <span
208
+ :style="{ paddingLeft: n.depth * 14 + 'px' }"
209
+ :class="{ 'opt-container': n.isContainer }"
210
+ >
211
+ <span v-if="n.isContainer" class="opt-tag"
212
+ >[{{ containerTypeLabel(n.type) }}]</span
213
+ >{{ n.baseLabel }}
214
+ </span>
215
+ </el-option>
216
+ </el-select>
217
+ <span class="target-attr">
218
+ <span class="attr-label">显示</span>
219
+ <el-select
220
+ v-model="t.visible"
221
+ size="mini"
222
+ class="cell-tri"
223
+ clearable
224
+ placeholder="不变"
225
+ >
226
+ <el-option label="显示" :value="true"></el-option>
227
+ <el-option label="隐藏" :value="false"></el-option>
228
+ </el-select>
229
+ </span>
230
+ <span class="target-attr">
231
+ <span class="attr-label">必填</span>
232
+ <el-select
233
+ v-model="t.required"
234
+ size="mini"
235
+ class="cell-tri"
236
+ clearable
237
+ placeholder="不变"
238
+ >
239
+ <el-option label="必填" :value="true"></el-option>
240
+ <el-option label="非必填" :value="false"></el-option>
241
+ </el-select>
242
+ </span>
243
+ <span class="target-attr">
244
+ <span class="attr-label">只读</span>
245
+ <el-select
246
+ v-model="t.readonly"
247
+ size="mini"
248
+ class="cell-tri"
249
+ clearable
250
+ placeholder="不变"
251
+ >
252
+ <el-option label="只读" :value="true"></el-option>
253
+ <el-option label="可编辑" :value="false"></el-option>
254
+ </el-select>
255
+ </span>
256
+ <span class="target-attr">
257
+ <span class="attr-label">禁用</span>
258
+ <el-select
259
+ v-model="t.disabled"
260
+ size="mini"
261
+ class="cell-tri"
262
+ clearable
263
+ placeholder="不变"
264
+ >
265
+ <el-option label="禁用" :value="true"></el-option>
266
+ <el-option label="启用" :value="false"></el-option>
267
+ </el-select>
268
+ </span>
269
+ <el-button
270
+ type="text"
271
+ icon="el-icon-remove-outline"
272
+ class="danger-text"
273
+ @click="removeTarget(rule, tIdx)"
274
+ ></el-button>
275
+ </div>
276
+ <el-button type="text" icon="el-icon-plus" @click="addTarget(rule)"
277
+ >添加目标字段</el-button
278
+ >
279
+ <div class="tip-text">
280
+ 目标为容器时仅「显示」生效,必填/只读/禁用将被忽略
281
+ </div>
282
+ </div>
283
+ </div>
284
+
285
+ <el-button
286
+ type="primary"
287
+ plain
288
+ icon="el-icon-plus"
289
+ size="mini"
290
+ @click="addRule"
291
+ style="width: 100%"
292
+ >
293
+ 添加规则
294
+ </el-button>
295
+ </div>
296
+
297
+ <div slot="footer">
298
+ <el-button size="mini" @click="ruleDialogVisible = false"
299
+ >取消</el-button
300
+ >
301
+ <el-button size="mini" type="primary" @click="saveRules"
302
+ >确定</el-button
303
+ >
304
+ </div>
305
+ </el-dialog>
306
+
307
+ <el-dialog
308
+ title="额外参数"
309
+ :visible.sync="scriptParamDialogVisible"
310
+ v-if="scriptParamDialogVisible"
311
+ :show-close="true"
312
+ custom-class="dialog-style list-dialog"
313
+ v-dialog-drag
314
+ :close-on-click-modal="false"
315
+ :close-on-press-escape="false"
316
+ :destroy-on-close="true"
317
+ :append-to-body="true"
318
+ :modal-append-to-body="true"
319
+ >
320
+ <div class="cont">
321
+ <code-editor
322
+ :mode="'javascript'"
323
+ :readonly="false"
324
+ v-model="editingScriptParam"
325
+ ref="scriptParamEditor"
326
+ ></code-editor>
327
+ </div>
328
+ <div slot="footer" class="dialog-footer">
329
+ <el-button
330
+ @click="scriptParamDialogVisible = false"
331
+ class="button-sty"
332
+ icon="el-icon-close"
333
+ >
334
+ {{ i18nt("designer.hint.cancel") }}
335
+ </el-button>
336
+ <el-button
337
+ type="primary"
338
+ @click="saveDynamicFieldScriptParam"
339
+ class="button-sty"
340
+ icon="el-icon-check"
341
+ >
342
+ {{ i18nt("designer.hint.confirm") }}
343
+ </el-button>
344
+ </div>
345
+ </el-dialog>
346
+ </div>
347
+ </template>
348
+
349
+ <script>
350
+ import i18n from "../../../../components/xform/utils/i18n";
351
+ import { buildWidgetTreeOptions } from "../../../../components/xform/form-render/container-item/dynamicFieldEngine";
352
+
353
+ const NO_VALUE_OPERATORS = ["empty", "notEmpty"];
354
+
355
+ export default {
356
+ name: "form-dynamicField-setting",
357
+ mixins: [i18n],
358
+ props: {
359
+ designer: Object,
360
+ formConfig: Object,
361
+ },
362
+ data() {
363
+ return {
364
+ ruleDialogVisible: false,
365
+ scriptParamDialogVisible: false,
366
+ editingScriptParam: "",
367
+ editingRules: [],
368
+ operatorOptions: [
369
+ { label: "等于", value: "eq" },
370
+ { label: "不等于", value: "ne" },
371
+ { label: "大于", value: "gt" },
372
+ { label: "小于", value: "lt" },
373
+ { label: "大于等于", value: "ge" },
374
+ { label: "小于等于", value: "le" },
375
+ { label: "属于(逗号分隔)", value: "in" },
376
+ { label: "不属于(逗号分隔)", value: "nin" },
377
+ { label: "包含", value: "includes" },
378
+ { label: "为空", value: "empty" },
379
+ { label: "不为空", value: "notEmpty" },
380
+ ],
381
+ };
382
+ },
383
+ computed: {
384
+ // 带层级的字段/容器候选(整个表单)
385
+ treeOptions() {
386
+ return buildWidgetTreeOptions(
387
+ (this.designer && this.designer.widgetList) || []
388
+ );
389
+ },
390
+ },
391
+ methods: {
392
+ op_noValue(operator) {
393
+ return NO_VALUE_OPERATORS.indexOf(operator) > -1;
394
+ },
395
+ // 选中态/过滤用的纯文本标签
396
+ optPlainLabel(n) {
397
+ if (n.isContainer) {
398
+ return "[" + this.containerTypeLabel(n.type) + "] " + n.baseLabel;
399
+ }
400
+ return n.baseLabel;
401
+ },
402
+ containerTypeLabel(type) {
403
+ const map = {
404
+ grid: "栅格",
405
+ table: "表格布局",
406
+ "h5-table": "H5表格",
407
+ tab: "标签页",
408
+ "tab-pane": "标签项",
409
+ card: "卡片",
410
+ "vf-box": "区块",
411
+ panel: "面板",
412
+ detail: "单据详情",
413
+ "detail-pane": "详情面板",
414
+ "detail-h5": "H5详情",
415
+ "h5-card": "H5卡片",
416
+ "h5-card-pane": "H5卡片面板",
417
+ "sub-form": "子表单",
418
+ "grid-sub-form": "网格子表单",
419
+ };
420
+ return map[type] || type;
421
+ },
422
+ genId() {
423
+ return "fdr_" + Date.now() + "_" + Math.floor(Math.random() * 10000);
424
+ },
425
+ editDynamicFieldScriptParam() {
426
+ this.editingScriptParam = this.formConfig.dynamicFieldScriptParam || "";
427
+ this.scriptParamDialogVisible = true;
428
+ },
429
+ saveDynamicFieldScriptParam() {
430
+ const codeHints = this.$refs.scriptParamEditor.getEditorAnnotations();
431
+ let syntaxErrorFlag = false;
432
+ if (codeHints && codeHints.length > 0) {
433
+ codeHints.forEach((chItem) => {
434
+ if (chItem.type === "error") {
435
+ syntaxErrorFlag = true;
436
+ }
437
+ });
438
+ if (syntaxErrorFlag) {
439
+ this.$message.error(
440
+ this.i18nt("designer.setting.syntaxCheckWarning")
441
+ );
442
+ return;
443
+ }
444
+ }
445
+ this.formConfig.dynamicFieldScriptParam = this.editingScriptParam;
446
+ this.scriptParamDialogVisible = false;
447
+ },
448
+ openRuleDialog() {
449
+ this.editingRules = JSON.parse(
450
+ JSON.stringify(this.formConfig.dynamicFieldRules || [])
451
+ );
452
+ this.editingRules.forEach((rule) => {
453
+ if (!rule.id) rule.id = this.genId();
454
+ if (!rule.logic) rule.logic = "and";
455
+ if (!rule.conditions) rule.conditions = [];
456
+ if (!rule.targets) rule.targets = [];
457
+ });
458
+ this.ruleDialogVisible = true;
459
+ },
460
+ addRule() {
461
+ this.editingRules.push({
462
+ id: this.genId(),
463
+ logic: "and",
464
+ conditions: [{ field: "", operator: "eq", value: "" }],
465
+ targets: [
466
+ {
467
+ field: "",
468
+ visible: undefined,
469
+ required: undefined,
470
+ readonly: undefined,
471
+ disabled: undefined,
472
+ },
473
+ ],
474
+ });
475
+ },
476
+ removeRule(idx) {
477
+ this.editingRules.splice(idx, 1);
478
+ },
479
+ addCondition(rule) {
480
+ rule.conditions.push({ field: "", operator: "eq", value: "" });
481
+ },
482
+ removeCondition(rule, idx) {
483
+ rule.conditions.splice(idx, 1);
484
+ },
485
+ addTarget(rule) {
486
+ rule.targets.push({
487
+ field: "",
488
+ visible: undefined,
489
+ required: undefined,
490
+ readonly: undefined,
491
+ disabled: undefined,
492
+ });
493
+ },
494
+ removeTarget(rule, idx) {
495
+ rule.targets.splice(idx, 1);
496
+ },
497
+ saveRules() {
498
+ this.formConfig.dynamicFieldRules = JSON.parse(
499
+ JSON.stringify(this.editingRules)
500
+ );
501
+ this.ruleDialogVisible = false;
502
+ },
503
+ },
504
+ };
505
+ </script>
506
+
507
+ <style lang="scss" scoped>
508
+ .tip-text {
509
+ font-size: 12px;
510
+ color: #909399;
511
+ line-height: 1.4;
512
+ margin-top: 2px;
513
+ }
514
+
515
+ .rule-list {
516
+ max-height: 56vh;
517
+ overflow-y: auto;
518
+ }
519
+
520
+ .rule-card {
521
+ border: 1px solid #ebeef5;
522
+ border-radius: 4px;
523
+ padding: 10px 12px;
524
+ margin-bottom: 12px;
525
+ background: #fafafa;
526
+ }
527
+
528
+ .rule-card-header {
529
+ display: flex;
530
+ justify-content: space-between;
531
+ align-items: center;
532
+ margin-bottom: 6px;
533
+
534
+ .rule-title {
535
+ font-weight: bold;
536
+ font-size: 13px;
537
+ }
538
+ }
539
+
540
+ .rule-section {
541
+ margin-top: 6px;
542
+ }
543
+
544
+ .rule-section-title {
545
+ display: flex;
546
+ align-items: center;
547
+ gap: 8px;
548
+ font-size: 13px;
549
+ color: #606266;
550
+ margin-bottom: 6px;
551
+ }
552
+
553
+ .rule-row {
554
+ display: flex;
555
+ align-items: center;
556
+ gap: 6px;
557
+ margin-bottom: 6px;
558
+ flex-wrap: wrap;
559
+ }
560
+
561
+ .cell-field {
562
+ width: 180px;
563
+ }
564
+
565
+ .cell-op {
566
+ width: 120px;
567
+ }
568
+
569
+ .cell-value {
570
+ width: 130px;
571
+ }
572
+
573
+ .cell-tri {
574
+ width: 92px;
575
+ }
576
+
577
+ .target-attr {
578
+ display: flex;
579
+ align-items: center;
580
+ gap: 2px;
581
+
582
+ .attr-label {
583
+ font-size: 12px;
584
+ color: #909399;
585
+ }
586
+ }
587
+
588
+ .danger-text {
589
+ color: #f56c6c;
590
+ }
591
+
592
+ .opt-container {
593
+ color: #409eff;
594
+ }
595
+
596
+ .opt-tag {
597
+ color: #909399;
598
+ font-size: 12px;
599
+ margin-right: 4px;
600
+ }
601
+ </style>
@@ -292,6 +292,13 @@
292
292
  </el-form-item>
293
293
  </el-collapse-item>
294
294
 
295
+ <el-collapse-item name="8" title="动态字段规则">
296
+ <form-dynamic-field-setting
297
+ :designer="designer"
298
+ :form-config="formConfig"
299
+ ></form-dynamic-field-setting>
300
+ </el-collapse-item>
301
+
295
302
  <el-collapse-item
296
303
  v-if="showEventCollapse()"
297
304
  name="7"
@@ -885,6 +892,7 @@ import formTemplateDialog from "../../../../views/bd/setting/form_template/dialo
885
892
  import wfObjConfigDialog from "./wfObjConfigDialog.vue";
886
893
  import bdCompanyEnvDialog from "@base/views/bd/setting/bd_company_env/dialog";
887
894
  import Draggable from "vuedraggable";
895
+ import formDynamicFieldSetting from "./form-dynamicField-setting.vue";
888
896
 
889
897
  export default {
890
898
  name: "form-setting",
@@ -894,6 +902,7 @@ export default {
894
902
  wfObjConfigDialog,
895
903
  bdCompanyEnvDialog,
896
904
  Draggable,
905
+ formDynamicFieldSetting,
897
906
  },
898
907
  props: {
899
908
  designer: Object,