cloud-web-corejs 1.1.0-dev.22 → 1.1.0-dev.23

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.
Files changed (30) hide show
  1. package/package.json +1 -1
  2. package/src/components/bizTab/BizTabListPage.vue +66 -33
  3. package/src/components/bizTab/README.md +3 -1
  4. package/src/components/mobile/wf/content.vue +27 -3
  5. package/src/components/table/index.js +5 -2
  6. package/src/components/table/plugins/cell-area/index.js +10 -3
  7. package/src/components/wf/wfStartDialog.vue +1 -0
  8. package/src/components/wf/wfUtil.js +47 -29
  9. package/src/components/wf/wfVisibility.js +6 -0
  10. package/src/components/xform/form-designer/form-widget/container-widget/data-table-mixin.js +7 -0
  11. package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue +3 -1
  12. package/src/components/xform/form-designer/form-widget/field-widget/fieldMixin.js +25 -1
  13. package/src/components/xform/form-designer/setting-panel/form-setting.vue +14 -2
  14. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/data-table-editor.vue +318 -12
  15. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/table-column-dialog.vue +23 -7
  16. package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +48 -0
  17. package/src/components/xform/form-render/container-item/data-table-item.vue +8 -6
  18. package/src/components/xform/form-render/container-item/data-table-mixin.js +584 -24
  19. package/src/components/xform/form-render/container-item/detail-h5-item.vue +26 -16
  20. package/src/components/xform/form-render/container-item/detail-item.vue +350 -446
  21. package/src/components/xform/form-render/fieldControlMixin.js +2 -0
  22. package/src/components/xform/form-render/indexMixin.js +25 -15
  23. package/src/components/xform/mixins/businessLock.js +59 -0
  24. package/src/components/xform/mixins/wfStart.js +103 -0
  25. package/src/components/xform/mixins/wfVisibility.js +33 -0
  26. package/src/components/xform/styles/h5.scss +6 -1
  27. package/src/components/xform/utils/util.js +2 -0
  28. package/src/views/user/home/index.vue +1 -1
  29. package/src/views/user/home/net/distributor.vue +1015 -0
  30. package/src/views/user/home/net/index.vue +61 -0
@@ -1,4 +1,5 @@
1
1
  import cloneDeep from "lodash/cloneDeep";
2
+ import { applyBusinessLock } from '@base/components/xform/mixins/businessLock';
2
3
  import {
3
4
  collectFieldControlTargets, readFieldState, writeStateOptions, computeFieldStates,
4
5
  resolveScriptStates, resolveRunMode, applyFieldState, isEntryVisible, sameValue,
@@ -410,6 +411,7 @@ export default {
410
411
  this.handleWidgetShowRule(projected);
411
412
  if (entry && states?.[entry.key]) writeStateOptions(projected.options, states[entry.key]);
412
413
  this.applyWorkflowFieldControl(projected);
414
+ applyBusinessLock(projected, this);
413
415
  if (widget.formItemFlag && this.disabledMode) projected.options.disabled = true;
414
416
  const effective = readFieldState(projected);
415
417
  // 非输入按钮不在动态目标范围,但仍应用流程自身的 disabled。
@@ -45,6 +45,8 @@ import {
45
45
  } from "../../../components/xform/form-designer/widget-panel/widgetsConfig.js";
46
46
  import { isUrlValueColumn } from "../../../components/xform/utils/attachmentValueUtil";
47
47
  import scriptHttpMixin from "../../../components/xform/mixins/scriptHttp";
48
+ import wfVisibilityMixin from "@base/components/xform/mixins/wfVisibility";
49
+ import businessLockMixin from "@base/components/xform/mixins/businessLock";
48
50
  import defaultHandleMixin from "../../../components/xform/mixins/defaultHandle";
49
51
  import xeUtils from "xe-utils";
50
52
  import { extendDeeply } from "@base/utils/index.js";
@@ -103,6 +105,8 @@ modules = {
103
105
  baseFormulaDialog,
104
106
  },
105
107
  mixins: [
108
+ wfVisibilityMixin,
109
+ businessLockMixin,
106
110
  baseRefUtil.emitter,
107
111
  baseRefUtil.i18n,
108
112
  scriptHttpMixin,
@@ -234,6 +238,9 @@ modules = {
234
238
  currentFormData: {},
235
239
  timerMap: {},
236
240
  hasWf: false,
241
+ // 未启动流程时 hasWf 仍为 false,启动参数必须自身可响应,才能让详情按钮及时出现。
242
+ wfStartOption: null,
243
+ wfStartCtx: null,
237
244
  showFormContent: false,
238
245
 
239
246
  showFormDialog: false,
@@ -765,7 +772,7 @@ modules = {
765
772
  let widgetEditOnWf = this.hanldeWfWidgetNew0(); //是否有流程时,当前用户特定流程节点是否可全局可编辑
766
773
  this.widgetEditOnWf = widgetEditOnWf;
767
774
 
768
- traverseAllWidgetsNew(this.formJson.widgetList, (widget) => {
775
+ traverseAllWidgetsNew(this.formJson.widgetList, (widget) => this.withBusinessLock(widget, () => {
769
776
  //修复data-table旧数据表格列widget与editWidget为空的问题
770
777
  this.handleTableColumnWidget(widget);
771
778
 
@@ -800,9 +807,9 @@ modules = {
800
807
  }
801
808
  }
802
809
  }
803
- });
810
+ }));
804
811
 
805
- this.wfModifyEnabled = hasModifyItem;
812
+ this.wfModifyEnabled = hasModifyItem && !this.businessLocked;
806
813
  },
807
814
  getFieldControlWidgets() {
808
815
  const widgets = [];
@@ -841,18 +848,20 @@ modules = {
841
848
 
842
849
  const processWidget = (widget) => {
843
850
  if (!widget) return;
844
- this.handleWidgetShowRule(widget);
845
- if (wfParam.hasWf && widget?.options?.saveSubmitWfButton) {
846
- widget.options.hidden = true;
847
- return;
848
- }
849
- if (!wfParam.hasWf || widgetEditOnWf) return;
850
- this.hanldeWfWidgetNew1(widget);
851
- if (wfInfo.taskStep === "9999") {
852
- this.hanldeWfWidgetItemNew(widget);
853
- } else if (toModify && taskDefinitionKey) {
854
- this.hanldeWfWidgetItemNew(widget);
855
- }
851
+ return this.withBusinessLock(widget, () => {
852
+ this.handleWidgetShowRule(widget);
853
+ if (wfParam.hasWf && widget?.options?.saveSubmitWfButton) {
854
+ widget.options.hidden = true;
855
+ return;
856
+ }
857
+ if (!wfParam.hasWf || widgetEditOnWf) return;
858
+ this.hanldeWfWidgetNew1(widget);
859
+ if (wfInfo.taskStep === "9999") {
860
+ this.hanldeWfWidgetItemNew(widget);
861
+ } else if (toModify && taskDefinitionKey) {
862
+ this.hanldeWfWidgetItemNew(widget);
863
+ }
864
+ });
856
865
  };
857
866
 
858
867
  const columnLoopDo = (column) => {
@@ -1463,6 +1472,7 @@ modules = {
1463
1472
  showStartBtn: true, //需要启动按钮(语义不变)
1464
1473
  injectStartBtn: false, //但不走 wfUtil 的 DOM 强制注入,改由 detail-item 模板声明式渲染
1465
1474
  showWfFold: true,
1475
+ layoutType: formConfig.layoutType,
1466
1476
  formCode: formCode,
1467
1477
  startConfirmText: () => this.getWfStartConfirmText(),
1468
1478
  callback: (wfParam) => {
@@ -0,0 +1,59 @@
1
+ import { applyFieldState } from '@base/components/xform/form-render/fieldControlEngine';
2
+
3
+ // 最后叠加业务限制,不改变真实流程状态,也不放宽既有字段规则。
4
+ export function applyBusinessLock(widget, host) {
5
+ if (!host.businessLocked || !widget?.options) return;
6
+ const deleteColumn = ['editDelete', 'removeTreeRow'].includes(widget.columnType);
7
+ if (widget.options.saveSubmitWfButton || deleteColumn) {
8
+ widget.options.hidden = true;
9
+ } else if (!host.getIsfreeWidgetTypesOfWf(widget)) {
10
+ if (host.getIsHiddenWidgetTypesOfWf(widget)) widget.options.hidden = true;
11
+ else if (widget.formItemFlag) widget.options.disabled = true;
12
+ }
13
+ }
14
+
15
+ export default {
16
+ data() {
17
+ return { businessLocked: false };
18
+ },
19
+ methods: {
20
+ // 可在表单事件脚本中调用;返回的 Promise 在本次视图更新后完成。
21
+ setBusinessLocked(locked = true) {
22
+ this.businessLocked = locked === true;
23
+ if (this.isFieldControlEnabled()) {
24
+ // 初始化前仅记录锁定意图,避免将锁定结果当成模板基线。
25
+ if (this.fieldControlInitialized) {
26
+ this.prepareFieldControlTargets();
27
+ this.applyFieldControlStates(this.getFieldControlRuntime().dynamicStates);
28
+ }
29
+ } else {
30
+ this.hanldeCommonWidget2();
31
+ }
32
+ return this.$nextTick();
33
+ },
34
+ withBusinessLock(widget, evaluate) {
35
+ if (!widget?.options) return evaluate();
36
+ if (!this._businessLockBaseline) this._businessLockBaseline = new WeakMap();
37
+ const previous = this._businessLockBaseline.get(widget);
38
+ if (previous) {
39
+ Object.keys(previous).forEach(key => {
40
+ if (previous[key] === undefined) this.$delete(widget.options, key);
41
+ else this.$set(widget.options, key, previous[key]);
42
+ });
43
+ this._businessLockBaseline.delete(widget);
44
+ }
45
+ try {
46
+ return evaluate();
47
+ } finally {
48
+ const baseline = { hidden: widget.options.hidden, disabled: widget.options.disabled };
49
+ applyBusinessLock(widget, this);
50
+ if (this.businessLocked) this._businessLockBaseline.set(widget, baseline);
51
+ if (this.businessLocked || previous) {
52
+ applyFieldState({ widget, refKey: widget.options.name, isContainer: widget.category === 'container' },
53
+ { visible: !widget.options.hidden, disabled: !!widget.options.disabled },
54
+ name => this.getWidgetRef(name));
55
+ }
56
+ }
57
+ },
58
+ },
59
+ };
@@ -0,0 +1,103 @@
1
+ import { openStartWfDialog } from "@base/components/wf/wfUtil";
2
+ import { getWfButtonNames, loadWfButtonNames, DEFAULT_SUBMIT_BTN } from "@base/components/wf/wfButtonName";
3
+ import { loadWfAutoConfirm } from "@base/components/wf/wfAutoConfirm";
4
+ import { loadWfUserRange } from "@base/components/wf/wfUserRange";
5
+ import settingConfig from "@base/settings";
6
+
7
+ // PC 与 H5 共用启动规则、校验和回调;容器提供 wfStart() 获取各自的流程状态。
8
+ export default {
9
+ computed: {
10
+ wfStartButtonName() {
11
+ return getWfButtonNames().submitBtn || settingConfig.wfStartButtonName || this.$t1(DEFAULT_SUBMIT_BTN);
12
+ },
13
+ },
14
+ methods: {
15
+ initWfStartSettings() {
16
+ if (this.getFormRef()?.formConfig?.wfEnabled) {
17
+ loadWfButtonNames(this);
18
+ loadWfAutoConfirm(this);
19
+ loadWfUserRange(this);
20
+ }
21
+ },
22
+ // 流程启动按钮:有启动信息、需要按钮(showStartBtn 未显式关闭)、未启动、非预览态才显示。
23
+ // 声明式渲染,替代 wfUtil 的 DOM 强制注入。
24
+ showWfStartBtn() {
25
+ if (this.getFormRef()?.businessLocked) return false;
26
+ let ws = this.wfStart();
27
+ if (!ws || this.previewState) return false;
28
+ let opt = ws.option || {};
29
+ if (opt.showStartBtn === false || ws.hasWf) return false;
30
+ return this.evalWfStartBtnShow();
31
+ },
32
+ /**
33
+ * 「提交流程」按钮显隐脚本(formConfig.wfStartBtnShow):return false 隐藏,不配则显示。
34
+ * 在渲染期求值,好处是随表单数据自动更新,代价是脚本会被反复执行——所以:
35
+ * 1) 编译结果按脚本原文缓存,避免每次渲染都 new Function;
36
+ * 2) 编译/执行异常一律放行(返回 true),不能因为脚本写错就把提交入口挡死;
37
+ * 3) formData 取轻量的 formRef.formData,不走 getSysFormData/getRealFormData 那套重加工。
38
+ * 脚本里务必只读数据、返回布尔,改数据会引发渲染循环。
39
+ */
40
+ evalWfStartBtnShow() {
41
+ let formRef = this.getFormRef && this.getFormRef();
42
+ let src = formRef && formRef.formConfig && formRef.formConfig.wfStartBtnShow;
43
+ if (!src) return true;
44
+ let cache = this._wfStartShowFn; //挂实例属性即可,不需要响应式
45
+ if (!cache || cache.src !== src) {
46
+ try {
47
+ cache = {
48
+ src,
49
+ fn: new Function("dataId", "formCode", "formData", src),
50
+ };
51
+ } catch (error) {
52
+ console.error("wfStartBtnShow 脚本编译失败", error);
53
+ return true;
54
+ }
55
+ this._wfStartShowFn = cache;
56
+ }
57
+ try {
58
+ let ret = cache.fn.call(
59
+ formRef,
60
+ formRef.dataId,
61
+ formRef.reportTemplate && formRef.reportTemplate.formCode,
62
+ formRef.formData
63
+ );
64
+ return ret !== false;
65
+ } catch (error) {
66
+ console.error("wfStartBtnShow 脚本执行异常", error);
67
+ return true;
68
+ }
69
+ },
70
+ // 声明式触发流程启动(替代原注入按钮的点击),复用 wfUtil 的 openStartWfDialog
71
+ startWf() {
72
+ if (this.getFormRef()?.businessLocked) return;
73
+ let ws = this.wfStart();
74
+ if (!ws || !ws.option || !ws.ctx) return;
75
+ // startConfirmText 原样透传:它只承载模板脚本 wfStartConfirmText 的文案(见 indexMixin
76
+ // 的 option 构造)。按钮名拼接与「后台 param19 自动确认」都由 wf.js 统一处理——
77
+ // 在这里替它拼默认文案的话,wf.js 会把它当成脚本自定义的告警,自动确认就失效了。
78
+ let innerOnStart = ws.option.onStart;
79
+ let formRef = this.getFormRef && this.getFormRef();
80
+ openStartWfDialog(ws.ctx, {
81
+ ...ws.option, //浅拷贝:wfStartOption 是 formRef 上的共享对象,不可原地改
82
+ // 提交前置处理:确认框在 wfStartDialog 内部,这里(打开弹框前)是唯一能拦的位置。
83
+ // 既有的 onStart 是表单校验(仅 wfStartBindSave 开启时注入),把它的 done 换成
84
+ // 「跑前置脚本」,即得到「先校验、后脚本、再确认框」;没开自动保存时直接跑脚本。
85
+ onStart: (done) => {
86
+ let runBefore = () => {
87
+ if (!formRef || typeof formRef.runBeforeSubmitWf !== "function") {
88
+ return done();
89
+ }
90
+ formRef.runBeforeSubmitWf("wfStart").then((pass) => {
91
+ if (pass) done();
92
+ });
93
+ };
94
+ if (typeof innerOnStart === "function") {
95
+ innerOnStart(runBefore);
96
+ } else {
97
+ runBefore();
98
+ }
99
+ },
100
+ });
101
+ },
102
+ },
103
+ };
@@ -0,0 +1,33 @@
1
+ // 与组件显隐规则一致:只匹配当前公司的角色,命中任意角色即隐藏。
2
+ export default {
3
+ data() {
4
+ return {
5
+ // 脚本态与角色配置分开保存;脚本取消隐藏时不会越过角色限制。
6
+ wfInfoHiddenByScript: false,
7
+ };
8
+ },
9
+ computed: {
10
+ _hideWf() {
11
+ const inherited = this.$attrs && this.$attrs._hideWf;
12
+ if (inherited === true || inherited === "true") return true;
13
+ if (this.wfInfoHiddenByScript) return true;
14
+ const configured = this.formConfig && this.formConfig.wfInfoHiddenRoleCodes;
15
+ const codes = (Array.isArray(configured) ? configured : String(configured || "").split(","))
16
+ .map(code => String(code).trim()).filter(Boolean);
17
+ return (this.userRoleDTO2s || []).some(role => codes.includes(role.roleCode));
18
+ },
19
+ },
20
+ methods: {
21
+ /**
22
+ * 给表单事件脚本调用:this.setWfInfoHidden(true/false)。
23
+ * 只控制流程信息、导航和依赖面板的审批入口,不影响流程初始化及启动按钮。
24
+ */
25
+ setWfInfoHidden(hidden = true) {
26
+ this.wfInfoHiddenByScript = hidden === true || hidden === "true";
27
+ if (typeof this._refreshWfInfoVisibility === "function") {
28
+ this._refreshWfInfoVisibility();
29
+ }
30
+ return this.$nextTick();
31
+ },
32
+ },
33
+ };
@@ -180,7 +180,8 @@ $xformH5Size:14px;
180
180
  那条正是块 C1 依赖的前提。 */
181
181
  .el-form-item {
182
182
  display: flex;
183
- align-items: flex-start;
183
+ /* 单行字段与移动端基本信息表格保持一致:标签和值都落在字段行中线。 */
184
+ align-items: center;
184
185
  position: relative;
185
186
  min-height: $xformH5RowHeight;
186
187
  margin-bottom: 0;
@@ -189,6 +190,8 @@ $xformH5Size:14px;
189
190
  /* 对手:style.scss:13854 `.h5-detail-wrap .h5-item .el-form-item__label` (0,3,0)
190
191
  带 text-align:left !important,且把 &:after 设成 display:none;本方 (0,5,0)。 */
191
192
  .el-form-item > .el-form-item__label {
193
+ display: flex !important;
194
+ align-items: center;
192
195
  width: $xformH5LabelWidth;
193
196
  padding: 0 5px 0 0;
194
197
  margin: 0;
@@ -1750,6 +1753,8 @@ $xformH5Size:14px;
1750
1753
  border-radius: 0;
1751
1754
 
1752
1755
  > .el-dialog__body {
1756
+ display: flex;
1757
+ flex-direction: column;
1753
1758
  flex: 1;
1754
1759
  min-height: 0;
1755
1760
  overflow-y: auto;
@@ -1116,6 +1116,8 @@ export function getDefaultFormConfig() {
1116
1116
  onBeforeSubmitWf: null,
1117
1117
  // 「提交流程」按钮显隐脚本:return false 隐藏,不配则显示
1118
1118
  wfStartBtnShow: null,
1119
+ // 当前公司角色编码,逗号分隔;命中任意角色只隐藏流程信息,保留启动入口。
1120
+ wfInfoHiddenRoleCodes: "",
1119
1121
  wfAgreenBindSave: false,
1120
1122
  wfAgreeConfigData: [],
1121
1123
  wfConfigDataEnabled: false,
@@ -90,7 +90,7 @@ export default {
90
90
  url = defaultHomePage || settingConfig.defaultHomePage || '@base/views/user/home/default.vue'
91
91
  }
92
92
  // 首页菜单不会归属别的子应用,无需 remote 兜底;归属解析见 @base/utils/resolveViewComponent
93
- this.homeContent = (await loadViewComponentAsync(url)).component;
93
+ this.homeContent = (await loadViewComponentAsync(url)).component;
94
94
 
95
95
  this.showHomeContent = true;
96
96
  this.flag = 1;