cloud-web-corejs 1.0.54-dev.810 → 1.0.54-dev.812
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/VabUpload/image-viewer.vue +442 -442
- package/src/components/VabUpload/index.vue +44 -2
- package/src/components/VabUpload/mixins.js +126 -19
- package/src/components/VabUpload/view.vue +247 -209
- package/src/components/baseTabs/mixins.js +181 -181
- package/src/components/mobile/wf/content.vue +1665 -1556
- package/src/components/table/config.js +78 -78
- package/src/components/table/index.js +1276 -1276
- package/src/components/table/tableForm.vue +330 -330
- package/src/components/table/tableFormMixin.js +318 -318
- package/src/components/table/vxeFilter/index.js +163 -163
- package/src/components/table/vxeFilter/mixin.js +316 -316
- package/src/components/wf/content.vue +1188 -1188
- package/src/components/wf/wf.js +29 -12
- package/src/components/wf/wfActionDropdown.vue +1 -1
- package/src/components/wf/wfActionItems.js +1 -1
- package/src/components/xform/docs/2026-08 xform H5 P0 /345/256/236/347/216/260/350/247/204/346/240/274.md" +528 -0
- package/src/components/xform/docs/2026-08 xform H5 P1 /345/256/236/347/216/260/350/247/204/346/240/274.md" +412 -0
- package/src/components/xform/docs/2026-08 xform H5 P2 /345/256/236/347/216/260/350/247/204/346/240/274.md" +287 -0
- package/src/components/xform/docs/2026-08 xform /347/247/273/345/212/250/347/253/257/345/270/203/345/261/200/345/257/271/351/275/220 bill_setting /346/226/271/346/241/210.md" +400 -0
- package/src/components/xform/form-designer/designer.js +15 -0
- package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue +269 -269
- package/src/components/xform/form-designer/form-widget/container-widget/detail-temp-widget.vue +132 -0
- package/src/components/xform/form-designer/form-widget/container-widget/detail-widget.vue +250 -250
- package/src/components/xform/form-designer/form-widget/dialog/fileReferenceDialog.vue +319 -320
- package/src/components/xform/form-designer/form-widget/dialog/formDialog.vue +365 -365
- package/src/components/xform/form-designer/form-widget/dialog/searchFormDialog.vue +554 -555
- package/src/components/xform/form-designer/form-widget/dialog/vabSearchDialog.vue +409 -409
- package/src/components/xform/form-designer/form-widget/field-widget/a-link-widget.vue +150 -132
- package/src/components/xform/form-designer/form-widget/field-widget/date-range-widget.vue +114 -114
- package/src/components/xform/form-designer/form-widget/field-widget/date-widget.vue +154 -154
- package/src/components/xform/form-designer/form-widget/field-widget/form-item-wrapper.vue +29 -1
- package/src/components/xform/form-designer/form-widget/field-widget/mixins/date-limit-mixin.js +178 -178
- package/src/components/xform/form-designer/form-widget/field-widget/mixins/time-limit-mixin.js +77 -77
- package/src/components/xform/form-designer/form-widget/field-widget/select-widget.vue +139 -139
- package/src/components/xform/form-designer/form-widget/field-widget/time-range-widget.vue +106 -106
- package/src/components/xform/form-designer/form-widget/field-widget/time-widget.vue +134 -134
- package/src/components/xform/form-designer/form-widget/field-widget/vabUpload-widget.vue +1 -0
- package/src/components/xform/form-designer/setting-panel/form-setting.vue +39 -39
- package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/exportItemColumns-dialog.vue +438 -438
- package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/table-column-dialog.vue +2103 -2103
- package/src/components/xform/form-designer/setting-panel/property-editor/container-detail/detail-temp-edito.vue +90 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue +82 -82
- package/src/components/xform/form-designer/setting-panel/property-editor/container-table/table-dynamicField-editor.vue +8 -8
- package/src/components/xform/form-designer/setting-panel/property-editor/dropdownFlag-editor.vue +137 -137
- package/src/components/xform/form-designer/setting-panel/property-editor/field-button/search-dialog-event-editor.vue +237 -237
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue +43 -43
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue +43 -43
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import2-button-editor.vue +96 -96
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue +42 -42
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue +43 -43
- package/src/components/xform/form-designer/setting-panel/property-editor/formScriptEnabled-editor.vue +158 -158
- package/src/components/xform/form-designer/setting-panel/property-editor/h5Span-editor.vue +51 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/itemStyle-editor.vue +39 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/name-editor.vue +188 -188
- package/src/components/xform/form-designer/setting-panel/property-editor/styleTempClass-editor.vue +51 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/textFlag-editor.vue +347 -347
- package/src/components/xform/form-designer/setting-panel/propertyRegister.js +4 -0
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +55 -3
- package/src/components/xform/form-render/container-item/data-table-mixin.js +33 -12
- package/src/components/xform/form-render/container-item/detail-h5-item.vue +183 -32
- package/src/components/xform/form-render/container-item/detail-temp-item.vue +110 -0
- package/src/components/xform/form-render/container-item/h5-card-pane-item.vue +160 -140
- package/src/components/xform/form-render/container-item/list-h5-item.vue +1642 -1700
- package/src/components/xform/form-render/index.vue +153 -147
- package/src/components/xform/form-render/indexMixin.js +12 -0
- package/src/components/xform/lang/en-US.js +10 -0
- package/src/components/xform/lang/zh-CN.js +12 -0
- package/src/components/xform/mixins/defaultHandle.js +707 -707
- package/src/components/xform/styles/h5.scss +1634 -0
- package/src/components/xform/utils/textMaskUtil.js +182 -182
- package/src/components/xform/utils/treeTableUtil.js +1292 -1265
- package/src/components/xform/utils/util.js +56 -11
- package/src/utils/pdfUtil.js +429 -429
- package/src/views/bd/setting/bd_company_env/dialog.vue +174 -174
- package/src/views/bd/setting/table_model/edit.vue +1066 -1066
- package/src/views/bd/setting/table_model/mixins/edit.js +1455 -1455
- package/src/views/bd/setting/table_model/mixins/zdDialog.js +148 -148
- package/src/views/user/home/wjl/content.vue +394 -31
- package/src/views/user/role/edit.vue +632 -632
- package/src/views/user/role/list.vue +260 -260
- package/src/views/user/wf/wf_manage/list.vue +1116 -1116
|
@@ -27,6 +27,7 @@ const COMMON_PROPERTIES = {
|
|
|
27
27
|
border: "border-editor",
|
|
28
28
|
labelWidth: "labelWidth-editor",
|
|
29
29
|
labelHidden: "labelHidden-editor",
|
|
30
|
+
h5Span: "h5Span-editor",
|
|
30
31
|
rows: "rows-editor",
|
|
31
32
|
required: "required-editor",
|
|
32
33
|
// 'requiredHint': 'requiredHint-editor',
|
|
@@ -71,6 +72,7 @@ const COMMON_PROPERTIES = {
|
|
|
71
72
|
fileTypes: "fileTypes-editor",
|
|
72
73
|
customClass: "customClass-editor",
|
|
73
74
|
styleTitClass: "styleTitClass-editor",
|
|
75
|
+
styleTempClass: "styleTempClass-editor",
|
|
74
76
|
styleTableClass: "styleTableClass-editor",
|
|
75
77
|
iconClass: "iconClass-editor",
|
|
76
78
|
echartHeight: "echartHeight-editor",
|
|
@@ -108,6 +110,7 @@ const COMMON_PROPERTIES = {
|
|
|
108
110
|
pull: "pull-editor",
|
|
109
111
|
height: "height-editor",
|
|
110
112
|
detailContainer: "detail-editor",
|
|
113
|
+
detailTempContainer: "detail-temp-editor",
|
|
111
114
|
detailPlainContainer: "detail-plain-editor",
|
|
112
115
|
detailPaneContainer: "detail-pane-editor",
|
|
113
116
|
vabSearchField: "vabSearchField-editor",
|
|
@@ -121,6 +124,7 @@ const COMMON_PROPERTIES = {
|
|
|
121
124
|
detailH5Container: "detail-h5-editor",
|
|
122
125
|
h5Card: "h5-card-editor",
|
|
123
126
|
listH5: "list-h5-editor",
|
|
127
|
+
itemStyle: "itemStyle-editor",
|
|
124
128
|
formScriptEnabled: "formScriptEnabled-editor",
|
|
125
129
|
textFlag: "textFlag-editor",
|
|
126
130
|
showRuleFlag: "showRuleFlag-editor",
|
|
@@ -445,6 +445,26 @@ export const containers = [
|
|
|
445
445
|
customClass: ""
|
|
446
446
|
}
|
|
447
447
|
},*/
|
|
448
|
+
{
|
|
449
|
+
type: "detail-temp",
|
|
450
|
+
category: "container",
|
|
451
|
+
icon: "form",
|
|
452
|
+
commonFlag: !0,
|
|
453
|
+
layoutType: "PC",
|
|
454
|
+
panes: [],
|
|
455
|
+
widgetList: [],
|
|
456
|
+
options: {
|
|
457
|
+
name: "",
|
|
458
|
+
hidden: !1,
|
|
459
|
+
label: "模板模块",
|
|
460
|
+
detailTempContainer: true,
|
|
461
|
+
styleTempClass: 'd-temp-1',
|
|
462
|
+
customClass: "",
|
|
463
|
+
wfEnabled: false,
|
|
464
|
+
onCreated: "",
|
|
465
|
+
onMounted: "",
|
|
466
|
+
},
|
|
467
|
+
},
|
|
448
468
|
{
|
|
449
469
|
type: "detail",
|
|
450
470
|
category: "container",
|
|
@@ -548,6 +568,7 @@ export const containers = [
|
|
|
548
568
|
detailH5Container: true,
|
|
549
569
|
// colHeight: null,
|
|
550
570
|
customClass: "",
|
|
571
|
+
// 底栏平铺个数不做成选项,写死在 detail-h5-item 的 H5_BOTTOM_MAX_BUTTONS(=3)
|
|
551
572
|
wfEnabled: false,
|
|
552
573
|
onCreated: "",
|
|
553
574
|
onMounted: "",
|
|
@@ -573,6 +594,8 @@ export const containers = [
|
|
|
573
594
|
listH5: true,
|
|
574
595
|
// colHeight: null,
|
|
575
596
|
customClass: "",
|
|
597
|
+
// 明细行样式:'plain'=原有朴素列表(默认,保持存量表现);'card'=卡片皮肤
|
|
598
|
+
itemStyle: "plain",
|
|
576
599
|
isQueryTable: false,
|
|
577
600
|
|
|
578
601
|
accessUrl: null,
|
|
@@ -4548,6 +4571,7 @@ export const widgetPanelOrder = {
|
|
|
4548
4571
|
"detail-tabs",
|
|
4549
4572
|
"detail-plain",
|
|
4550
4573
|
"detail-pane",
|
|
4574
|
+
"detail-temp",
|
|
4551
4575
|
"tree-pane",
|
|
4552
4576
|
"tree",
|
|
4553
4577
|
"vf-dialog",
|
|
@@ -4629,18 +4653,46 @@ export const widgetPanelOrder = {
|
|
|
4629
4653
|
],
|
|
4630
4654
|
};
|
|
4631
4655
|
|
|
4656
|
+
/**
|
|
4657
|
+
* H5 版式:所有表单字段统一具备 h5Span(整宽/半宽)。
|
|
4658
|
+
*
|
|
4659
|
+
* 为什么用后处理而不是在 42 个字段定义里逐个展开 ...defaultH5Config:
|
|
4660
|
+
* 1) 一处逻辑覆盖全部字段,不会漏;
|
|
4661
|
+
* 2) 顺带覆盖 extension 通过 add*Schema 动态注册的组件;
|
|
4662
|
+
* 3) 用函数调用而非展开运算符,不踩本文件头部注释里那个 Babel TDZ 的坑。
|
|
4663
|
+
*
|
|
4664
|
+
* 属性面板显不显示「H5 占宽」由 designer.hasConfig 决定,它查的是**原型 widget
|
|
4665
|
+
* 的 options**(不是实例),所以必须在这里写进原型。
|
|
4666
|
+
* 详见 docs/2026-08 xform H5 P0 实现规格.md §3.1。
|
|
4667
|
+
*/
|
|
4668
|
+
export const defaultH5Config = {
|
|
4669
|
+
h5Span: "full", // 'full' | 'half'
|
|
4670
|
+
};
|
|
4671
|
+
|
|
4672
|
+
function applyH5FieldDefaults(schema) {
|
|
4673
|
+
if (!schema || !schema.formItemFlag || !schema.options) return schema;
|
|
4674
|
+
if (!Object.prototype.hasOwnProperty.call(schema.options, "h5Span")) {
|
|
4675
|
+
Object.assign(schema.options, defaultH5Config);
|
|
4676
|
+
}
|
|
4677
|
+
return schema;
|
|
4678
|
+
}
|
|
4679
|
+
|
|
4680
|
+
[basicFields, advancedFields, businessFields, customFields].forEach((list) =>
|
|
4681
|
+
list.forEach(applyH5FieldDefaults)
|
|
4682
|
+
);
|
|
4683
|
+
|
|
4632
4684
|
export function addContainerWidgetSchema(containerSchema) {
|
|
4633
4685
|
containers.push(containerSchema);
|
|
4634
4686
|
}
|
|
4635
4687
|
|
|
4636
4688
|
export function addBasicFieldSchema(fieldSchema) {
|
|
4637
|
-
basicFields.push(fieldSchema);
|
|
4689
|
+
basicFields.push(applyH5FieldDefaults(fieldSchema));
|
|
4638
4690
|
}
|
|
4639
4691
|
|
|
4640
4692
|
export function addAdvancedFieldSchema(fieldSchema) {
|
|
4641
|
-
advancedFields.push(fieldSchema);
|
|
4693
|
+
advancedFields.push(applyH5FieldDefaults(fieldSchema));
|
|
4642
4694
|
}
|
|
4643
4695
|
|
|
4644
4696
|
export function addCustomWidgetSchema(widgetSchema) {
|
|
4645
|
-
customFields.push(widgetSchema);
|
|
4697
|
+
customFields.push(applyH5FieldDefaults(widgetSchema));
|
|
4646
4698
|
}
|
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
isTemporaryTreeKey,
|
|
69
69
|
syncTreeKeyReferences,
|
|
70
70
|
sanitizeTreeRow,
|
|
71
|
+
stripTreeContainers,
|
|
71
72
|
} from "../../utils/treeTableUtil";
|
|
72
73
|
import { tableTreeMixins } from "../../../../mixins/tableTree/index.js";
|
|
73
74
|
|
|
@@ -3570,7 +3571,7 @@ modules = {
|
|
|
3570
3571
|
let newData = this.createNewTableData();
|
|
3571
3572
|
tableRows.push(newData);
|
|
3572
3573
|
}
|
|
3573
|
-
this.setValue(tableRows);
|
|
3574
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
3574
3575
|
this.$nextTick(() => {
|
|
3575
3576
|
this.handleWbs();
|
|
3576
3577
|
});
|
|
@@ -4557,7 +4558,7 @@ modules = {
|
|
|
4557
4558
|
await reconcileGrid.clearActived();
|
|
4558
4559
|
}
|
|
4559
4560
|
if (rebuildTreeAfterSave && !responseAlreadyApplied) {
|
|
4560
|
-
this.setValue(treeTableRows);
|
|
4561
|
+
this.setValue(this.stripTreeContainerRows(treeTableRows));
|
|
4561
4562
|
treeSnapshotApplied = true;
|
|
4562
4563
|
await new Promise((resolve) => this.$nextTick(resolve));
|
|
4563
4564
|
}
|
|
@@ -4729,7 +4730,7 @@ modules = {
|
|
|
4729
4730
|
} else {
|
|
4730
4731
|
tableRows.splice(0, 0, newRow);
|
|
4731
4732
|
}
|
|
4732
|
-
this.setValue(tableRows);
|
|
4733
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
4733
4734
|
this.$nextTick(() => {
|
|
4734
4735
|
this.handleWbs();
|
|
4735
4736
|
if (isEditTable) {
|
|
@@ -4751,7 +4752,7 @@ modules = {
|
|
|
4751
4752
|
} else {
|
|
4752
4753
|
tableRows.splice(0, 0, newRow);
|
|
4753
4754
|
}
|
|
4754
|
-
this.setValue(tableRows);
|
|
4755
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
4755
4756
|
this.$nextTick(() => {
|
|
4756
4757
|
this.handleWbs();
|
|
4757
4758
|
// setValue 已浅克隆所有行,obj.row 是失效引用,须按 _X_ROW_KEY 找回新行
|
|
@@ -4839,7 +4840,7 @@ modules = {
|
|
|
4839
4840
|
});
|
|
4840
4841
|
this.validateNewTreeRows(newRows, treeContext);
|
|
4841
4842
|
tableRows.push(...newRows);
|
|
4842
|
-
this.setValue(tableRows);
|
|
4843
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
4843
4844
|
this.$nextTick(() => {
|
|
4844
4845
|
this.handleWbs();
|
|
4845
4846
|
if (parent) {
|
|
@@ -4848,6 +4849,26 @@ modules = {
|
|
|
4848
4849
|
}
|
|
4849
4850
|
});
|
|
4850
4851
|
},
|
|
4852
|
+
/**
|
|
4853
|
+
* 去掉 VXE 建树时写回行对象的容器字段(children / mapChildren)。
|
|
4854
|
+
*
|
|
4855
|
+
* 删除、排序这类「改扁平数组再整表重载」的操作必须先剥容器:容器是上一次
|
|
4856
|
+
* 渲染的产物,已被移出数组的节点仍挂在存活父行下,setValue 里的
|
|
4857
|
+
* canonicalizeTreeInput 会顺着容器把它们收回来,删除与排序因此静默失效。
|
|
4858
|
+
*
|
|
4859
|
+
* 只对 isTreeTable(强制 transform,父子关系由 parentField 表达)生效;
|
|
4860
|
+
* 靠 children 表达层级的表原样返回,剥掉会丢层级。
|
|
4861
|
+
* @param {Array} rows 取自表单模型的扁平活动行。
|
|
4862
|
+
* @returns {Array} 可安全交给 setValue 的行数组。
|
|
4863
|
+
*/
|
|
4864
|
+
stripTreeContainerRows(rows) {
|
|
4865
|
+
if (!this.widget.options.isTreeTable) {
|
|
4866
|
+
return rows || [];
|
|
4867
|
+
}
|
|
4868
|
+
return stripTreeContainers(rows || [], {
|
|
4869
|
+
fields: this.getTreeFields(),
|
|
4870
|
+
});
|
|
4871
|
+
},
|
|
4851
4872
|
/**
|
|
4852
4873
|
* 收集节点全部后代的 _X_ROW_KEY(不含节点自身)。
|
|
4853
4874
|
* 兼容嵌套结构(children 字段)与扁平结构(parentField 关联)两种数据形态。
|
|
@@ -4927,7 +4948,7 @@ modules = {
|
|
|
4927
4948
|
});
|
|
4928
4949
|
}
|
|
4929
4950
|
let newRows = tableRows.filter((item) => !delKeys.has(item._X_ROW_KEY));
|
|
4930
|
-
this.setValue(newRows);
|
|
4951
|
+
this.setValue(this.stripTreeContainerRows(newRows));
|
|
4931
4952
|
this.$nextTick(() => {
|
|
4932
4953
|
this.handleWbs();
|
|
4933
4954
|
});
|
|
@@ -5185,7 +5206,7 @@ modules = {
|
|
|
5185
5206
|
} else {
|
|
5186
5207
|
tableRows.splice(0, 0, newRow);
|
|
5187
5208
|
}
|
|
5188
|
-
this.setValue(tableRows);
|
|
5209
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
5189
5210
|
this.$nextTick(() => {
|
|
5190
5211
|
this.handleWbs();
|
|
5191
5212
|
});
|
|
@@ -5202,7 +5223,7 @@ modules = {
|
|
|
5202
5223
|
} else {
|
|
5203
5224
|
tableRows.splice(0, 0, newRow);
|
|
5204
5225
|
}
|
|
5205
|
-
this.setValue(tableRows);
|
|
5226
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
5206
5227
|
this.$nextTick(() => {
|
|
5207
5228
|
this.handleWbs();
|
|
5208
5229
|
// setValue 已浅克隆所有行,obj.row 是失效引用,须按 _X_ROW_KEY 找回新行
|
|
@@ -5399,7 +5420,7 @@ modules = {
|
|
|
5399
5420
|
);
|
|
5400
5421
|
tableRows.splice(currentIndex, 1);
|
|
5401
5422
|
tableRows.splice(prevIndex, 0, row);
|
|
5402
|
-
this.setValue(tableRows);
|
|
5423
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
5403
5424
|
this.$nextTick(() => {
|
|
5404
5425
|
this.handleWbs();
|
|
5405
5426
|
});
|
|
@@ -5448,7 +5469,7 @@ modules = {
|
|
|
5448
5469
|
);
|
|
5449
5470
|
tableRows.splice(currentIndex, 1);
|
|
5450
5471
|
tableRows.splice(nextIndex, 0, row);
|
|
5451
|
-
this.setValue(tableRows);
|
|
5472
|
+
this.setValue(this.stripTreeContainerRows(tableRows));
|
|
5452
5473
|
this.$nextTick(() => {
|
|
5453
5474
|
this.handleWbs();
|
|
5454
5475
|
});
|
|
@@ -5525,7 +5546,7 @@ modules = {
|
|
|
5525
5546
|
rows.forEach((row, index1) => {
|
|
5526
5547
|
items.splice(index + index1, 0, row);
|
|
5527
5548
|
});
|
|
5528
|
-
this.setValue(items);
|
|
5549
|
+
this.setValue(this.stripTreeContainerRows(items));
|
|
5529
5550
|
this.$nextTick(() => {
|
|
5530
5551
|
this.handleWbs();
|
|
5531
5552
|
});
|
|
@@ -5820,7 +5841,7 @@ modules = {
|
|
|
5820
5841
|
if (this.designState) return;
|
|
5821
5842
|
this.$on("setFormData", (o) => {
|
|
5822
5843
|
let rows = this.formModel[this.fieldKeyName] || [];
|
|
5823
|
-
this.setValue(rows);
|
|
5844
|
+
this.setValue(this.stripTreeContainerRows(rows));
|
|
5824
5845
|
});
|
|
5825
5846
|
},
|
|
5826
5847
|
/** @param {Object} widget 组件 schema。@param {Array<String>} ignoreFields 忽略字段。@returns {Boolean} 是否处理禁用状态。 */
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
<container-item-wrapper :widget="widget">
|
|
13
13
|
<div class="h5-detail-wrap grid-container" :class="[customClass]" :ref="widget.id">
|
|
14
14
|
<div class="h5-header">{{ widget.options.label }}</div>
|
|
15
|
-
|
|
15
|
+
<!-- 唯一滚动区:标题栏与底部动作栏 flex:none 固定,内容在这里滚。
|
|
16
|
+
样式见 components/xform/styles/h5.scss 块 G(.h5-detail-body 必须有 min-height:0) -->
|
|
17
|
+
<div class="h5-detail-body">
|
|
16
18
|
<transition-group name="fade" tag="div" class="form-widget-list">
|
|
17
19
|
<template v-if="!!widget.panes && (widget.panes.length > 0)">
|
|
18
20
|
<template v-for="(subWidget, swIdx) in widget.panes">
|
|
@@ -39,12 +41,24 @@
|
|
|
39
41
|
</template>
|
|
40
42
|
</template>
|
|
41
43
|
</transition-group>
|
|
44
|
+
<!-- 移动版流程面板:自给自足(mounted 里自己取数),只需给 wfOption。
|
|
45
|
+
全部用方法求值而非 computed —— 流程状态挂在表单实例上且非响应式,
|
|
46
|
+
computed 会缓存住早于流程就绪时的空值(见 wfStart 的注释)。
|
|
47
|
+
样式见 styles/h5.scss 块 L。 -->
|
|
48
|
+
<mobileWfContent v-if="showWfPanel()" ref="wfContent" :wfOption="getWfOption()"
|
|
49
|
+
:defaultShowWfContent="getDefaultShowWfContent()"
|
|
50
|
+
:hideActions="true"/>
|
|
42
51
|
</div>
|
|
43
52
|
<div class="h5-fixed-bottom-btns ">
|
|
44
53
|
<transition-group name="fade" tag="div" class="form-widget-list">
|
|
45
|
-
<template v-if="
|
|
46
|
-
<template v-for="(subWidget, swIdx) in
|
|
47
|
-
|
|
54
|
+
<template v-if="visibleButtons().length > 0">
|
|
55
|
+
<template v-for="(subWidget, swIdx) in visibleButtons()">
|
|
56
|
+
<!-- 审批动作按钮,不是 widget,单独渲染。只出文字不带图标 -->
|
|
57
|
+
<div class="field-wrapper" v-if="subWidget.__builtin" :key="'b-' + subWidget.__builtin">
|
|
58
|
+
<el-button class="button-sty" :type="subWidget.type"
|
|
59
|
+
@click="subWidget.onClick">{{ subWidget.label }}</el-button>
|
|
60
|
+
</div>
|
|
61
|
+
<template v-else-if="'container' === subWidget.category">
|
|
48
62
|
<component :is="subWidget.type + '-item'" :widget="subWidget" :key="swIdx"
|
|
49
63
|
:parent-list="widget.widgetList"
|
|
50
64
|
:index-of-parent-list="swIdx" :parent-widget="widget">
|
|
@@ -67,6 +81,25 @@
|
|
|
67
81
|
</template>
|
|
68
82
|
</template>
|
|
69
83
|
</transition-group>
|
|
84
|
+
<!-- 超出的按钮收进纯图标下拉。它按内容宽(不参与等分),排在最右。
|
|
85
|
+
popper-class 而非嵌套作用域:el-dropdown-menu 默认 append-to-body,
|
|
86
|
+
菜单 DOM 会被挪到 body 下、脱离 .xform-h5,故样式写成顶层
|
|
87
|
+
.xform-h5-dropdown 选择器(见 styles/h5.scss)。 -->
|
|
88
|
+
<el-dropdown v-if="overflowButtons().length > 0" class="h5-more-dropdown"
|
|
89
|
+
trigger="click" popper-class="xform-h5-dropdown">
|
|
90
|
+
<!-- 裸图标触发器,不套 el-button:底栏在页面底部、菜单往上弹,故用向上箭头 -->
|
|
91
|
+
<i class="el-icon-arrow-up h5-more-icon"></i>
|
|
92
|
+
<el-dropdown-menu slot="dropdown">
|
|
93
|
+
<el-dropdown-item v-for="(subWidget, swIdx) in overflowButtons()" :key="swIdx">
|
|
94
|
+
<el-button v-if="subWidget.__builtin" class="button-sty" :type="subWidget.type"
|
|
95
|
+
@click="subWidget.onClick">{{ subWidget.label }}</el-button>
|
|
96
|
+
<component v-else :is="subWidget.type + '-widget'" :field="subWidget" :designer="null"
|
|
97
|
+
:parent-list="widget.widgetList"
|
|
98
|
+
:index-of-parent-list="swIdx + visibleButtons().length"
|
|
99
|
+
:parent-widget="widget"/>
|
|
100
|
+
</el-dropdown-item>
|
|
101
|
+
</el-dropdown-menu>
|
|
102
|
+
</el-dropdown>
|
|
70
103
|
</div>
|
|
71
104
|
</div>
|
|
72
105
|
|
|
@@ -83,7 +116,18 @@ import containerItemMixin from "./containerItemMixin"
|
|
|
83
116
|
import FieldComponents from '../../../../components/xform/form-designer/form-widget/field-widget/index'
|
|
84
117
|
|
|
85
118
|
|
|
86
|
-
import {
|
|
119
|
+
import {getVisibleWfActionItems} from '../../../../components/wf/wfActionItems'
|
|
120
|
+
|
|
121
|
+
/* H5 底栏只放这四个审批动作,其余(催办/加签/减签/沟通/修改候选人/撤回…)不进底栏。
|
|
122
|
+
★ 这里的书写序就是底栏的显示序:通过 → 驳回 → 中断 → 转办。 */
|
|
123
|
+
const H5_WF_ACTION_KEYS = ['agree', 'reject', 'manual', 'transfer'];
|
|
124
|
+
|
|
125
|
+
/* 底栏平铺的按钮个数上限,超出的收进最右侧的「更多」图标下拉 ——
|
|
126
|
+
即一行最多「3 个操作按钮 + 1 个更多图标」。
|
|
127
|
+
写死而不做成表单选项:这个数由底栏宽度决定,配大了会挤成一团,
|
|
128
|
+
而且此前做成 options.maxVisibleButtons 后,已保存的表单会锁住旧值,
|
|
129
|
+
改了原型默认值也不生效,反成绊脚石。 */
|
|
130
|
+
const H5_BOTTOM_MAX_BUTTONS = 3;
|
|
87
131
|
|
|
88
132
|
export default {
|
|
89
133
|
name: "detail-h5-item",
|
|
@@ -92,6 +136,11 @@ export default {
|
|
|
92
136
|
components: {
|
|
93
137
|
ContainerItemWrapper,
|
|
94
138
|
...FieldComponents,
|
|
139
|
+
/* 懒加载:PC 版式的表单不该把移动 wf 那坨打进主包。
|
|
140
|
+
注:content.vue 的根节点是 <h5-card-pane>,Vue 2 的组件解析只查自身
|
|
141
|
+
components 与全局注册、不查父组件的局部注册,所以那个依赖必须由
|
|
142
|
+
content.vue 自己声明(已在该文件补上),在这里注册是没用的。 */
|
|
143
|
+
mobileWfContent: () => import('../../../../components/mobile/wf/content.vue'),
|
|
95
144
|
},
|
|
96
145
|
props: {
|
|
97
146
|
widget: Object,
|
|
@@ -103,19 +152,142 @@ export default {
|
|
|
103
152
|
},
|
|
104
153
|
mounted() {
|
|
105
154
|
this.handleOnMounted();
|
|
106
|
-
this.$nextTick(() => {
|
|
107
|
-
this.createWf();
|
|
108
|
-
})
|
|
109
155
|
},
|
|
110
156
|
beforeDestroy() {
|
|
111
157
|
this.unregisterFromRefList()
|
|
112
158
|
},
|
|
113
159
|
data() {
|
|
114
|
-
return {
|
|
115
|
-
wfInfo: {}
|
|
116
|
-
}
|
|
160
|
+
return {}
|
|
117
161
|
},
|
|
118
162
|
methods: {
|
|
163
|
+
/**
|
|
164
|
+
* 流程状态实时求值 —— 与 PC 的 detail-item.wfStart() 同口径。
|
|
165
|
+
*
|
|
166
|
+
* 取数不归本组件管:form-render 的 loadDefaultEntityData 在
|
|
167
|
+
* formConfig.wfEnabled 为真时就已经初始化好流程,把结果挂在表单实例上
|
|
168
|
+
* (wfStartOption / wfStartCtx / wfParam / hasWf),入参也在那边算好
|
|
169
|
+
* (objId = dataId、wfCode = reportTemplate.objTypeCode,见 indexMixin:1394)。
|
|
170
|
+
*
|
|
171
|
+
* 必须用方法而不是 computed:wfStartOption / wfStartCtx / wfParam **都不在
|
|
172
|
+
* form-render 的 data 里**(只有 hasWf 在),不是响应式的,computed 会把
|
|
173
|
+
* 早于流程就绪时求得的空值缓存住。监听 hasWf 也不行 —— 单据没启动流程时
|
|
174
|
+
* 它是 false 赋 false,watcher 根本不触发。
|
|
175
|
+
*
|
|
176
|
+
* 注意:容器 options 上那个 wfEnabled 是旧路径的开关,与表单设置里的
|
|
177
|
+
* formConfig.wfEnabled 不是一回事,这里一律以表单实例的状态为准。
|
|
178
|
+
*/
|
|
179
|
+
wfStart() {
|
|
180
|
+
let f = this.getFormRef && this.getFormRef();
|
|
181
|
+
if (!f || !f.wfStartOption) return null
|
|
182
|
+
let param = f.wfParam || {};
|
|
183
|
+
return {
|
|
184
|
+
ctx: f.wfStartCtx || f.$parent,
|
|
185
|
+
option: f.wfStartOption,
|
|
186
|
+
param: param,
|
|
187
|
+
hasWf: !!(f.hasWf || param.hasWf),
|
|
188
|
+
wfInfo: param.wfInfo || {},
|
|
189
|
+
taskParam: param.taskParam || {},
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
/**
|
|
193
|
+
* 映射成移动版 content.vue 要的 wfOption。
|
|
194
|
+
* 结果缓存在非响应式实例属性上:模板里调用的方法每次渲染都会执行,
|
|
195
|
+
* 每次返回新对象会让子组件 props 无谓变化;而在渲染期写 data 会触发重渲染循环。
|
|
196
|
+
*/
|
|
197
|
+
getWfOption() {
|
|
198
|
+
if (this._wfOptionCache) return this._wfOptionCache
|
|
199
|
+
let ws = this.wfStart();
|
|
200
|
+
if (!ws) return null
|
|
201
|
+
let opt = ws.option;
|
|
202
|
+
let serviceId = opt.serviceId || "user";
|
|
203
|
+
this._wfOptionCache = {
|
|
204
|
+
objId: opt.objId,
|
|
205
|
+
wfCode: opt.wfCode,
|
|
206
|
+
serviceId: serviceId,
|
|
207
|
+
wf_prefix: "/" + serviceId,
|
|
208
|
+
startParam: opt.startParam,
|
|
209
|
+
startConfirmText: opt.startConfirmText,
|
|
210
|
+
parentVue: ws.ctx,
|
|
211
|
+
};
|
|
212
|
+
return this._wfOptionCache
|
|
213
|
+
},
|
|
214
|
+
/* 流程面板:已启动流程且非预览态才渲染 */
|
|
215
|
+
showWfPanel() {
|
|
216
|
+
let ws = this.wfStart();
|
|
217
|
+
return !this.previewState && !!ws && ws.hasWf;
|
|
218
|
+
},
|
|
219
|
+
/* 宿主通过 $attrs 传「进来就展开流程区」,与 PC 版 wfUtil 同口径 */
|
|
220
|
+
getDefaultShowWfContent() {
|
|
221
|
+
let ws = this.wfStart();
|
|
222
|
+
let target = ws && ws.ctx;
|
|
223
|
+
return !!(target && target.$attrs && target.$attrs.defaultShowWfContent);
|
|
224
|
+
},
|
|
225
|
+
/* 注:H5 底栏不放「流程启动」和「修改单据」两个内建按钮
|
|
226
|
+
(PC 的 wfUtil 与移动版 mixin 里都有,这里按需求去掉),
|
|
227
|
+
底栏只有审批动作 + 业务按钮。 */
|
|
228
|
+
/**
|
|
229
|
+
* 审批动作按钮(通过/驳回/中断/转办)。
|
|
230
|
+
*
|
|
231
|
+
* 复用 PC 的动作注册表 wfActionItems —— 它的 run 是 (wfVm) => wfVm.openAgreeDialog()
|
|
232
|
+
* 这种形式,而这些方法名在移动版 content.vue 里完全一致,所以同一份注册表两边通用。
|
|
233
|
+
*
|
|
234
|
+
* show 用表单实例上的 wfInfo 求值(读 f.hasWf 会建立响应式依赖,流程就绪时能重渲染);
|
|
235
|
+
* run 则要真实的面板实例,点击时才从 $refs 取 —— 那时面板一定已经渲染好了。
|
|
236
|
+
* 面板内那一排同名按钮由 :hideActions="true" 藏掉,不会出现两份。
|
|
237
|
+
*/
|
|
238
|
+
wfActionButtons() {
|
|
239
|
+
let ws = this.wfStart();
|
|
240
|
+
if (!ws || !ws.hasWf || this.previewState) return []
|
|
241
|
+
// 只用 wfInfo 算显隐,不依赖面板实例(它可能还没渲染)
|
|
242
|
+
let items = getVisibleWfActionItems({ wfInfo: ws.wfInfo });
|
|
243
|
+
let byKey = {};
|
|
244
|
+
items.forEach((item) => {
|
|
245
|
+
byKey[item.key] = item;
|
|
246
|
+
});
|
|
247
|
+
// 按 H5_WF_ACTION_KEYS 取,顺序由它决定 —— 不能用 items.filter,
|
|
248
|
+
// 那样保留的是注册表的定义序(通过/中断/驳回/转办),与要求的顺序不一致
|
|
249
|
+
return H5_WF_ACTION_KEYS.map((key) => byKey[key])
|
|
250
|
+
.filter((item) => !!item)
|
|
251
|
+
.map((item) => ({
|
|
252
|
+
__builtin: "wfAction-" + item.key,
|
|
253
|
+
label: item.i18nPath
|
|
254
|
+
? this.$t2(item.defaultLabel, item.i18nPath)
|
|
255
|
+
: item.defaultLabel,
|
|
256
|
+
// 注册表里的 iconClass/elIcon 不取:H5 底栏按钮只出文字
|
|
257
|
+
type: item.buttonType || "primary",
|
|
258
|
+
onClick: () => {
|
|
259
|
+
let wfVm = this.$refs.wfContent;
|
|
260
|
+
if (!wfVm) return
|
|
261
|
+
item.run(wfVm);
|
|
262
|
+
},
|
|
263
|
+
}));
|
|
264
|
+
},
|
|
265
|
+
/**
|
|
266
|
+
* 底栏按钮:审批动作在前(审批中的单据以审批为主),然后是流程启动/修改单据,
|
|
267
|
+
* 最后是业务按钮。hidden 的业务按钮先剔除,否则「更多」里会留空条目
|
|
268
|
+
* (static-content-wrapper 内部只是 v-show 隐藏,el-dropdown-item 仍占一行)。
|
|
269
|
+
*/
|
|
270
|
+
bottomButtons() {
|
|
271
|
+
let widgetButtons = (this.widget.widgetList || []).filter(
|
|
272
|
+
(w) => !w.options || !w.options.hidden
|
|
273
|
+
);
|
|
274
|
+
return this.wfActionButtons().concat(widgetButtons);
|
|
275
|
+
},
|
|
276
|
+
/**
|
|
277
|
+
* 平铺的按钮。宽度由 CSS 的 flex:1 等分决定 ——
|
|
278
|
+
* 1 个铺满、2 个各一半、3 个各三分之一,不需要在这里算。
|
|
279
|
+
*/
|
|
280
|
+
visibleButtons() {
|
|
281
|
+
let list = this.bottomButtons();
|
|
282
|
+
if (list.length <= H5_BOTTOM_MAX_BUTTONS) return list;
|
|
283
|
+
return list.slice(0, H5_BOTTOM_MAX_BUTTONS);
|
|
284
|
+
},
|
|
285
|
+
/** 超出上限的按钮,收进底栏最右侧那个纯图标下拉 */
|
|
286
|
+
overflowButtons() {
|
|
287
|
+
let list = this.bottomButtons();
|
|
288
|
+
if (list.length <= H5_BOTTOM_MAX_BUTTONS) return [];
|
|
289
|
+
return list.slice(H5_BOTTOM_MAX_BUTTONS);
|
|
290
|
+
},
|
|
119
291
|
reload() {
|
|
120
292
|
this.getFormRef().$parent.$baseReload()
|
|
121
293
|
},
|
|
@@ -123,27 +295,6 @@ export default {
|
|
|
123
295
|
if (!!this.previewState) return
|
|
124
296
|
this.getFormRef().saveForm();
|
|
125
297
|
},
|
|
126
|
-
createWf() {
|
|
127
|
-
if (!!this.previewState || !this.widget.options.wfEnabled) return
|
|
128
|
-
let formTarget = this.getFormRef();
|
|
129
|
-
let formData = formTarget.formData;
|
|
130
|
-
if (formData && formData.object_foreign_id) {
|
|
131
|
-
let reportTemplate = formTarget.reportTemplate;
|
|
132
|
-
let formCode = reportTemplate.formCode;
|
|
133
|
-
let option = {
|
|
134
|
-
objId: formData.object_foreign_id, //单据ID
|
|
135
|
-
wfCode: formCode, //流程编码
|
|
136
|
-
showStartBtn: true, //是否放出启动按钮,流程已启动时此参数失效
|
|
137
|
-
serviceId: 'user',
|
|
138
|
-
startConfirmText: () => formTarget.getWfStartConfirmText(),
|
|
139
|
-
callback: ({wfInfo}) => {
|
|
140
|
-
this.wfInfo = wfInfo;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
initWf.call(formTarget.$parent, option);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
}
|
|
147
298
|
},
|
|
148
299
|
}
|
|
149
300
|
</script>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
/**
|
|
3
|
+
* author: vformAdmin
|
|
4
|
+
* email: vdpadmin@163.com
|
|
5
|
+
* website: https://www.vform666.com
|
|
6
|
+
* date: 2021.08.18
|
|
7
|
+
* remark: 如果要分发VForm源码,需在本文件顶部保留此文件头信息!!
|
|
8
|
+
*/
|
|
9
|
+
-->
|
|
10
|
+
<template>
|
|
11
|
+
<container-item-wrapper :widget="widget">
|
|
12
|
+
<div class="detail-temp-wrap" :class="[customClass]" :ref="widget.id">
|
|
13
|
+
<div class="detail-temp-box" v-for="(paneWidget, index) in widget.panes" :key="paneWidget.id || index" :class="widget.options.styleTempClass">
|
|
14
|
+
<div class="detail-temp-header">
|
|
15
|
+
<span class="detail-temp-label">{{ getI18nLabel(paneWidget.options.label) || '模块' }}</span>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="detail-temp-body">
|
|
18
|
+
<template v-for="(subWidget, swIdx) in paneWidget.widgetList">
|
|
19
|
+
<template v-if="'container' === subWidget.category">
|
|
20
|
+
<component
|
|
21
|
+
:is="subWidget.type + '-item'"
|
|
22
|
+
:widget="subWidget"
|
|
23
|
+
:key="subWidget.id || swIdx"
|
|
24
|
+
:parent-list="paneWidget.widgetList"
|
|
25
|
+
:index-of-parent-list="swIdx"
|
|
26
|
+
:parent-widget="paneWidget"
|
|
27
|
+
>
|
|
28
|
+
<!-- 递归传递插槽 -->
|
|
29
|
+
<template v-for="slot in Object.keys($scopedSlots)" v-slot:[slot]="scope">
|
|
30
|
+
<slot :name="slot" v-bind="scope" />
|
|
31
|
+
</template>
|
|
32
|
+
</component>
|
|
33
|
+
</template>
|
|
34
|
+
<template v-else>
|
|
35
|
+
<component
|
|
36
|
+
:is="subWidget.type + '-widget'"
|
|
37
|
+
:field="subWidget"
|
|
38
|
+
:designer="null"
|
|
39
|
+
:key="subWidget.id || swIdx"
|
|
40
|
+
:parent-list="paneWidget.widgetList"
|
|
41
|
+
:index-of-parent-list="swIdx"
|
|
42
|
+
:parent-widget="paneWidget"
|
|
43
|
+
>
|
|
44
|
+
<!-- 递归传递插槽 -->
|
|
45
|
+
<template v-for="slot in Object.keys($scopedSlots)" v-slot:[slot]="scope">
|
|
46
|
+
<slot :name="slot" v-bind="scope" />
|
|
47
|
+
</template>
|
|
48
|
+
</component>
|
|
49
|
+
</template>
|
|
50
|
+
</template>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</container-item-wrapper>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<script>
|
|
58
|
+
import emitter from '../../../../components/xform/utils/emitter'
|
|
59
|
+
import i18n from "../../../../components/xform/utils/i18n"
|
|
60
|
+
import refMixin from "../../../../components/xform/form-render/refMixin"
|
|
61
|
+
import containerItemMixin from "./containerItemMixin"
|
|
62
|
+
import FieldComponents from '../../../../components/xform/form-designer/form-widget/field-widget/index'
|
|
63
|
+
|
|
64
|
+
export default {
|
|
65
|
+
name: "detail-temp-item",
|
|
66
|
+
componentName: 'ContainerItem',
|
|
67
|
+
mixins: [emitter, i18n, refMixin, containerItemMixin],
|
|
68
|
+
components: {
|
|
69
|
+
...FieldComponents,
|
|
70
|
+
},
|
|
71
|
+
props: {
|
|
72
|
+
widget: Object,
|
|
73
|
+
parentWidget: Object,
|
|
74
|
+
parentList: Array,
|
|
75
|
+
indexOfParentList: Number,
|
|
76
|
+
},
|
|
77
|
+
inject: ['refList', 'globalModel', 'previewState'],
|
|
78
|
+
computed: {
|
|
79
|
+
customClass() {
|
|
80
|
+
return this.widget.options.customClass || ''
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
watch: {
|
|
84
|
+
//
|
|
85
|
+
},
|
|
86
|
+
created() {
|
|
87
|
+
this.initRefList()
|
|
88
|
+
this.handleOnCreated();
|
|
89
|
+
},
|
|
90
|
+
mounted() {
|
|
91
|
+
this.handleOnMounted();
|
|
92
|
+
},
|
|
93
|
+
data() {
|
|
94
|
+
return {
|
|
95
|
+
showStatus: true,
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
methods: {
|
|
99
|
+
opeaShowCont() {
|
|
100
|
+
this.showStatus = !this.showStatus
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<style lang="scss" scoped>
|
|
107
|
+
.detail-temp-wrap {
|
|
108
|
+
min-height: 50px;
|
|
109
|
+
}
|
|
110
|
+
</style>
|