cloud-web-corejs 1.0.54-dev.800 → 1.0.54-dev.802
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/baseArea/index.vue +82 -27
- package/src/components/bizTab/BizBillActions.vue +2 -2
- package/src/components/bizTab/bizBillDetailMixin.js +27 -9
- package/src/components/excelExport/exportFieldDialog.vue +11 -9
- package/src/components/table/config.js +6 -4
- package/src/components/table/index.js +78 -22
- package/src/components/table/state.js +42 -0
- package/src/components/table/tableForm.vue +16 -5
- package/src/components/table/tableFormMixin.js +35 -7
- package/src/components/table/vxeFilter/index.js +4 -2
- package/src/components/table/vxeFilter/mixin.js +10 -4
- package/src/components/wf/content.vue +12 -0
- package/src/components/wf/wf.js +72 -23
- package/src/components/wf/wfActionDropdown.vue +85 -0
- package/src/components/wf/wfActionItems.js +136 -0
- package/src/components/wf/wfAutoConfirm.js +55 -0
- package/src/components/wf/wfUserRange.js +53 -0
- package/src/components/wf/wfUtil.js +46 -2
- package/src/components/xform/form-designer/designer.js +6 -1
- package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue +9 -3
- package/src/components/xform/form-designer/form-widget/dialog/vabSearchDialog.vue +2 -1
- package/src/components/xform/form-designer/form-widget/field-widget/date-range-widget.vue +3 -2
- package/src/components/xform/form-designer/form-widget/field-widget/date-widget.vue +3 -12
- package/src/components/xform/form-designer/form-widget/field-widget/mixins/date-limit-mixin.js +2 -46
- package/src/components/xform/form-designer/form-widget/field-widget/mixins/relative-default-mixin.js +107 -0
- package/src/components/xform/form-designer/form-widget/field-widget/mixins/relativeDateUtil.js +321 -0
- package/src/components/xform/form-designer/form-widget/field-widget/mixins/time-limit-mixin.js +2 -17
- package/src/components/xform/form-designer/form-widget/field-widget/time-range-widget.vue +3 -2
- package/src/components/xform/form-designer/form-widget/field-widget/time-widget.vue +3 -12
- package/src/components/xform/form-designer/setting-panel/form-dynamicField-setting.vue +5 -5
- package/src/components/xform/form-designer/setting-panel/form-setting.vue +48 -26
- package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/data-table-editor.vue +16 -19
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue +13 -12
- package/src/components/xform/form-designer/setting-panel/property-editor/container-table/table-dynamicField-editor.vue +16 -18
- package/src/components/xform/form-designer/setting-panel/property-editor/event-handler/afterColumnsCreated-editor.vue +30 -0
- 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-common/keyName-editor.vue +4 -4
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue +35 -36
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue +35 -18
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import2-button-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue +34 -36
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue +35 -18
- package/src/components/xform/form-designer/setting-panel/property-editor/fixedQuery-editor.vue +39 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/formScriptEnabled-editor.vue +20 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/name-editor.vue +188 -178
- package/src/components/xform/form-designer/setting-panel/property-editor/relative-default-block.vue +369 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/textFlag-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/propertyRegister.js +2 -0
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +35 -2
- package/src/components/xform/form-render/container-item/data-table-mixin.js +150 -75
- package/src/components/xform/form-render/container-item/detail-item.vue +8 -12
- package/src/components/xform/lang/en-US.js +3 -0
- package/src/components/xform/lang/zh-CN.js +3 -0
- package/src/components/xform/mixins/defaultHandle.js +18 -3
- package/src/components/xform/utils/fixedQueryUtil.js +93 -0
- package/src/views/user/outLink/cc_form_view.vue +33 -30
- package/src/views/user/wf/wf_manage/list.vue +17 -1
- package/src/components/xform/form-render/container-item/data-table-mixin copy.js +0 -5910
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 流程提交确认框自动确认:由后台 wf_diy_attribute 的 param19 统一维护,全局拉取一次后缓存。
|
|
3
|
+
* 返回 true 时,「提交流程」「保存并提交流程」的系统默认确认框不再弹,直接按「确定」处理。
|
|
4
|
+
*
|
|
5
|
+
* 不含表单模板脚本 wfStartConfirmText 自定义的提示语——业务方常拿它做金额超限之类的告警,
|
|
6
|
+
* 那种提示必须由人确认,不能被这个全局开关吞掉(判定在 wf.js 的启动确认分支)。
|
|
7
|
+
*/
|
|
8
|
+
import Vue from "vue";
|
|
9
|
+
|
|
10
|
+
/* 与 wfButtonName.js 同款:缓存必须是响应式的,值后到时读取方才能重算。
|
|
11
|
+
这里语义是「没配就不自动确认」,所以初值直接给 false,不需要区分未配置。 */
|
|
12
|
+
const wfAutoConfirm = Vue.observable({
|
|
13
|
+
enabled: false,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
let pending = null;
|
|
17
|
+
|
|
18
|
+
export function isWfAutoConfirm() {
|
|
19
|
+
return wfAutoConfirm.enabled === true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 拉取自动确认开关。全局只发一次请求,重复调用复用同一个 promise。
|
|
24
|
+
* @param {Object} vm 任意 Vue 实例(取 $http),不传则退回 window.$vueRoot
|
|
25
|
+
* @returns {Promise<Boolean>}
|
|
26
|
+
*/
|
|
27
|
+
export function loadWfAutoConfirm(vm) {
|
|
28
|
+
if (pending) return pending;
|
|
29
|
+
let target = vm || window.$vueRoot;
|
|
30
|
+
if (!target || !target.$http) return Promise.resolve(wfAutoConfirm.enabled);
|
|
31
|
+
let errored = false;
|
|
32
|
+
let request = new Promise((resolve) => {
|
|
33
|
+
target.$http({
|
|
34
|
+
url: USER_PREFIX + "/wf_diy_attribute/getValue",
|
|
35
|
+
method: "post",
|
|
36
|
+
data: { attributeKey: "param19" },
|
|
37
|
+
success: (res) => {
|
|
38
|
+
let val = res ? res.objx : null;
|
|
39
|
+
//后台可能回布尔也可能回字符串,两种都认;其余(含没配)一律当关
|
|
40
|
+
wfAutoConfirm.enabled = val === true || val === "true";
|
|
41
|
+
resolve(wfAutoConfirm.enabled);
|
|
42
|
+
},
|
|
43
|
+
fail: () => resolve(wfAutoConfirm.enabled),
|
|
44
|
+
error: () => {
|
|
45
|
+
errored = true;
|
|
46
|
+
pending = null; //失败不锁死,下次进流程表单可重试
|
|
47
|
+
resolve(wfAutoConfirm.enabled);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//回调若是同步回来的(拦截器短路、单测桩),上面那句 pending = null 会被下面这句盖掉,
|
|
52
|
+
//于是重试永远拿到那个已 settle 的旧 promise —— 用 errored 补一刀。
|
|
53
|
+
pending = errored ? null : request;
|
|
54
|
+
return request;
|
|
55
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「节点候选人范围」开关:后台 wf_diy_attribute 的 param12,全局拉取一次后缓存。
|
|
3
|
+
* 开着时启动流程会先打 /wf/preStart,返回候选人则弹「修改候选人」弹框(见 wf.js subWfStartForm)。
|
|
4
|
+
*
|
|
5
|
+
* wfStartDialog 内部另有一份 initWfUserRangeParam(),每次开弹框现取,那份是启动流程的权威判定,
|
|
6
|
+
* 不动它。这里这份只服务于弹框之外的调用方——「保存并提交」要在**保存之前**就知道这个开关,
|
|
7
|
+
* 才能决定确认框是当场弹(param12 关,后面不可能有候选人弹框)还是延后给弹框(param12 开)。
|
|
8
|
+
*/
|
|
9
|
+
import Vue from "vue";
|
|
10
|
+
|
|
11
|
+
const wfUserRange = Vue.observable({
|
|
12
|
+
enabled: false,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
let pending = null;
|
|
16
|
+
|
|
17
|
+
export function isWfUserRangeEnabled() {
|
|
18
|
+
return wfUserRange.enabled === true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 拉取开关。全局只发一次请求,重复调用复用同一个 promise。
|
|
23
|
+
* @param {Object} vm 任意 Vue 实例(取 $http),不传则退回 window.$vueRoot
|
|
24
|
+
* @returns {Promise<Boolean>}
|
|
25
|
+
*/
|
|
26
|
+
export function loadWfUserRange(vm) {
|
|
27
|
+
if (pending) return pending;
|
|
28
|
+
let target = vm || window.$vueRoot;
|
|
29
|
+
if (!target || !target.$http) return Promise.resolve(wfUserRange.enabled);
|
|
30
|
+
let errored = false;
|
|
31
|
+
let request = new Promise((resolve) => {
|
|
32
|
+
target.$http({
|
|
33
|
+
url: USER_PREFIX + "/wf_diy_attribute/getValue",
|
|
34
|
+
method: "post",
|
|
35
|
+
data: { attributeKey: "param12" },
|
|
36
|
+
success: (res) => {
|
|
37
|
+
let val = res ? res.objx : null;
|
|
38
|
+
//与 wf.js initWfUserRangeParam 同口径,字符串 "true" 一并认
|
|
39
|
+
wfUserRange.enabled = val === true || val === "true";
|
|
40
|
+
resolve(wfUserRange.enabled);
|
|
41
|
+
},
|
|
42
|
+
fail: () => resolve(wfUserRange.enabled),
|
|
43
|
+
error: () => {
|
|
44
|
+
errored = true;
|
|
45
|
+
pending = null; //失败不锁死,下次进流程表单可重试
|
|
46
|
+
resolve(wfUserRange.enabled);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//回调同步回来时(拦截器短路、单测桩),上面那句 pending = null 会被下面这句盖掉,补一刀
|
|
51
|
+
pending = errored ? null : request;
|
|
52
|
+
return request;
|
|
53
|
+
}
|
|
@@ -81,6 +81,10 @@ f = async function (option) {
|
|
|
81
81
|
|
|
82
82
|
let showStartBtn = option.showStartBtn != null ? option.showStartBtn : true;
|
|
83
83
|
let showModifyBtn = option.showModifyBtn != null ? option.showModifyBtn : true;
|
|
84
|
+
let contentInstance = null; //流程面板实例,标题栏下拉要点它的方法
|
|
85
|
+
//宿主声明「不挂流程信息面板」:面板整棵 v-if 掉,标题栏那份审批入口也不能挂
|
|
86
|
+
let _hideWf = that._hideWf || that.$attrs._hideWf;
|
|
87
|
+
let isHideWf = _hideWf === true || _hideWf === 'true';
|
|
84
88
|
|
|
85
89
|
if (wfInfo) {
|
|
86
90
|
let wfModel = configUtil.settingConfig.wfModel || 1;
|
|
@@ -101,8 +105,7 @@ f = async function (option) {
|
|
|
101
105
|
}
|
|
102
106
|
});
|
|
103
107
|
instances.push(instance);
|
|
104
|
-
|
|
105
|
-
let isHideWf = _hideWf === true || _hideWf === 'true';
|
|
108
|
+
contentInstance = instance;
|
|
106
109
|
if (!_hideWf && slideWrap) {
|
|
107
110
|
let navVm = new configUtil.Vue({
|
|
108
111
|
render: function (h) {
|
|
@@ -196,6 +199,30 @@ f = async function (option) {
|
|
|
196
199
|
appendPrevChildDom(wfBtnRegion, startVm.$mount().$el)
|
|
197
200
|
}
|
|
198
201
|
|
|
202
|
+
/* 审批操作:开了 wfActionInHeaderEnabled 时,在详情模块标题栏再挂一份 —— 通过/驳回/撤回
|
|
203
|
+
平铺成独立按钮,其余收进「流程操作」下拉(wfActionDropdown.vue)。流程模块里的
|
|
204
|
+
原按钮条不动、不隐藏;点击走流程面板实例上的同一套方法。
|
|
205
|
+
放在「修改单据」「流程启动」之后挂——appendPrevChildDom 是前插,最后插的排最左,
|
|
206
|
+
最终顺序:通过/驳回/撤回/流程操作 → 修改单据 → 内建/业务按钮。
|
|
207
|
+
hiddenAllButton / 素身详情(取不到 .fr) 自动跳过。
|
|
208
|
+
_hideWf 也必须跳过:那种页面 content.vue 根节点 v-if 掉了,弹框根本没渲染出来,
|
|
209
|
+
挂上去就是一排点了没反应的按钮(wfInfo 照样有值,光看 items 判断不出来)。 */
|
|
210
|
+
if (shouldMountHeaderActions({
|
|
211
|
+
option,
|
|
212
|
+
settingConfig: configUtil.settingConfig,
|
|
213
|
+
wfBtnRegion,
|
|
214
|
+
contentInstance,
|
|
215
|
+
isHideWf
|
|
216
|
+
})) {
|
|
217
|
+
let Dropdown = configUtil.Vue.extend(configUtil.getWfObj('/wfActionDropdown.vue'));
|
|
218
|
+
let dropdownVm = new Dropdown({
|
|
219
|
+
i18n: that._i18n,
|
|
220
|
+
propsData: { wfVm: contentInstance }
|
|
221
|
+
});
|
|
222
|
+
instances.push(dropdownVm);
|
|
223
|
+
appendPrevChildDom(wfBtnRegion, dropdownVm.$mount().$el);
|
|
224
|
+
}
|
|
225
|
+
|
|
199
226
|
registerDispose();
|
|
200
227
|
}
|
|
201
228
|
|
|
@@ -216,6 +243,23 @@ f = async function (option) {
|
|
|
216
243
|
}
|
|
217
244
|
}
|
|
218
245
|
|
|
246
|
+
/* 标题栏那份审批入口挂不挂。抽成函数是为了能单测——done() 整条链路要打 http、要真 DOM。
|
|
247
|
+
ctx: { option, settingConfig, wfBtnRegion, contentInstance, isHideWf } */
|
|
248
|
+
export function shouldMountHeaderActions(ctx) {
|
|
249
|
+
let option = (ctx && ctx.option) || {};
|
|
250
|
+
let settingConfig = (ctx && ctx.settingConfig) || {};
|
|
251
|
+
let actionInHeader = option.actionInHeader != null
|
|
252
|
+
? option.actionInHeader
|
|
253
|
+
: settingConfig.wfActionInHeaderEnabled === true;
|
|
254
|
+
return !!(
|
|
255
|
+
actionInHeader
|
|
256
|
+
&& ctx.wfBtnRegion //素身详情取不到 .d-header > .fr
|
|
257
|
+
&& ctx.contentInstance //没流程面板就没方法可调
|
|
258
|
+
&& !ctx.isHideWf //面板被 v-if 掉了,挂上去全是哑按钮
|
|
259
|
+
&& !option.hiddenAllButton
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
219
263
|
function getModifyButtonName(that, taskParam) {
|
|
220
264
|
let buttonName = null;
|
|
221
265
|
if (!taskParam.buttonName || taskParam.buttonName == "修改单据") {
|
|
@@ -1660,10 +1660,13 @@ let chartContainers = [],
|
|
|
1660
1660
|
"'}";
|
|
1661
1661
|
dataTableCon.buttons.push(tableExportButton);
|
|
1662
1662
|
|
|
1663
|
+
// 两个查询条件的值由树节点点击注入,勾上「固定查询条件」后
|
|
1664
|
+
// 刷新、查询条件设置的还原/确定都不会把它清掉
|
|
1663
1665
|
let searchInput = this.copyNewFieldWidget(
|
|
1664
1666
|
this.getFieldWidgetByType("input")
|
|
1665
1667
|
);
|
|
1666
1668
|
searchInput.options.disabled = true;
|
|
1669
|
+
searchInput.options.fixedQuery = true;
|
|
1667
1670
|
searchInput.options.label = newCon.options.treeLabel;
|
|
1668
1671
|
dataTableCon.widgetList.push(searchInput);
|
|
1669
1672
|
|
|
@@ -1672,10 +1675,12 @@ let chartContainers = [],
|
|
|
1672
1675
|
);
|
|
1673
1676
|
searchIdInput.options.disabled = true;
|
|
1674
1677
|
searchIdInput.options.hidden = true;
|
|
1678
|
+
searchIdInput.options.fixedQuery = true;
|
|
1675
1679
|
searchIdInput.options.label = `隐藏${newCon.options.treeLabel}ID`;
|
|
1676
1680
|
dataTableCon.widgetList.push(searchIdInput);
|
|
1677
1681
|
|
|
1678
|
-
|
|
1682
|
+
// 存量表单没有 fixedQuery 开关,仍靠 ignoreFields 兜底刷新按钮;
|
|
1683
|
+
// 新建的表单两条通道并存(取并集),不冲突
|
|
1679
1684
|
dataTableCon.options.onResetTable = `this.resetEvent({\n ignoreFields:['${searchInput.options.name}', '${searchIdInput.options.name}']\n});`;
|
|
1680
1685
|
|
|
1681
1686
|
//初始化树
|
package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<template #form>
|
|
18
18
|
<template v-if="widget.options.isQueryTable">
|
|
19
19
|
<div class="clearfix screen-btns">
|
|
20
|
-
<div class="fl
|
|
20
|
+
<div class="fl button-drag-zone">
|
|
21
21
|
<!-- <vxe-button status="primary" class="button-sty" icon="el-icon-upload2"
|
|
22
22
|
v-if="widget.options.showExportBtn!==false">导出
|
|
23
23
|
</vxe-button>-->
|
|
@@ -247,9 +247,14 @@ div.table-container {
|
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
/* 按钮拖放区:宽度自适应,最多占满除右侧刷新/搜索按钮外的空间,超出后按钮换行 */
|
|
251
|
+
.screen-btns .fl.button-drag-zone {
|
|
252
|
+
max-width: calc(100% - 180px);
|
|
253
|
+
}
|
|
254
|
+
|
|
250
255
|
.sub-form-table {
|
|
251
256
|
min-height: 68px;
|
|
252
|
-
min-width:
|
|
257
|
+
min-width: 200px
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
.sub-form-table .sub-form-drag-drop-zone {
|
|
@@ -257,7 +262,8 @@ div.table-container {
|
|
|
257
262
|
}
|
|
258
263
|
|
|
259
264
|
.sub-form-table div.sub-form-table-column {
|
|
260
|
-
display: inline-block
|
|
265
|
+
display: inline-block;
|
|
266
|
+
vertical-align: top
|
|
261
267
|
}
|
|
262
268
|
|
|
263
269
|
</style>
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
|
|
80
80
|
<script>
|
|
81
81
|
import {selectDialogMixins} from '../../../../../mixins/selectDialog/index.js';
|
|
82
|
+
import {getTableStateValue} from '../../../../../components/table/state';
|
|
82
83
|
|
|
83
84
|
export default {
|
|
84
85
|
name: "vabSearchDialog",
|
|
@@ -234,7 +235,7 @@ export default {
|
|
|
234
235
|
}
|
|
235
236
|
|
|
236
237
|
var $grid = this.$refs[tableRef];
|
|
237
|
-
let isQueryAllPage = $grid
|
|
238
|
+
let isQueryAllPage = getTableStateValue($grid, 'isQueryAllPage');
|
|
238
239
|
let pathStr1 = "";
|
|
239
240
|
if (isQueryAllPage === false) {
|
|
240
241
|
queryParams.searchCount = false;
|
|
@@ -26,11 +26,12 @@ import emitter from '../../../../../components/xform/utils/emitter'
|
|
|
26
26
|
import i18n from "../../../../../components/xform/utils/i18n";
|
|
27
27
|
import fieldMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/fieldMixin";
|
|
28
28
|
import utcTransformMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/mixins/utc-transform-mixin";
|
|
29
|
+
import relativeDefaultMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/mixins/relative-default-mixin";
|
|
29
30
|
|
|
30
31
|
export default {
|
|
31
32
|
name: "date-range-widget",
|
|
32
33
|
componentName: 'FieldWidget', //必须固定为FieldWidget,用于接收父级组件的broadcast事件
|
|
33
|
-
mixins: [emitter, fieldMixin, i18n, utcTransformMixin],
|
|
34
|
+
mixins: [emitter, fieldMixin, i18n, utcTransformMixin, relativeDefaultMixin],
|
|
34
35
|
props: {
|
|
35
36
|
field: Object,
|
|
36
37
|
parentWidget: Object,
|
|
@@ -83,7 +84,7 @@ export default {
|
|
|
83
84
|
created() {
|
|
84
85
|
/* 注意:子组件mounted在父组件created之后、父组件mounted之前触发,故子组件mounted需要用到的prop
|
|
85
86
|
需要在父组件created中初始化!! */
|
|
86
|
-
this.
|
|
87
|
+
this.initRelativeFieldModel()
|
|
87
88
|
this.registerToRefList()
|
|
88
89
|
this.initEventHandler()
|
|
89
90
|
this.buildFieldRules()
|
|
@@ -27,11 +27,12 @@ import i18n from "../../../../../components/xform/utils/i18n";
|
|
|
27
27
|
import fieldMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/fieldMixin";
|
|
28
28
|
import dateLimitMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/mixins/date-limit-mixin";
|
|
29
29
|
import utcTransformMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/mixins/utc-transform-mixin";
|
|
30
|
+
import relativeDefaultMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/mixins/relative-default-mixin";
|
|
30
31
|
|
|
31
32
|
export default {
|
|
32
33
|
name: "date-widget",
|
|
33
34
|
componentName: 'FieldWidget', //必须固定为FieldWidget,用于接收父级组件的broadcast事件
|
|
34
|
-
mixins: [emitter, fieldMixin, i18n, dateLimitMixin, utcTransformMixin],
|
|
35
|
+
mixins: [emitter, fieldMixin, i18n, dateLimitMixin, utcTransformMixin, relativeDefaultMixin],
|
|
35
36
|
props: {
|
|
36
37
|
field: Object,
|
|
37
38
|
parentWidget: Object,
|
|
@@ -102,7 +103,7 @@ export default {
|
|
|
102
103
|
created() {
|
|
103
104
|
/* 注意:子组件mounted在父组件created之后、父组件mounted之前触发,故子组件mounted需要用到的prop
|
|
104
105
|
需要在父组件created中初始化!! */
|
|
105
|
-
this.
|
|
106
|
+
this.initRelativeFieldModel()
|
|
106
107
|
this.registerToRefList()
|
|
107
108
|
this.initEventHandler()
|
|
108
109
|
this.buildFieldRules()
|
|
@@ -138,16 +139,6 @@ export default {
|
|
|
138
139
|
},
|
|
139
140
|
setNow() {
|
|
140
141
|
this.$refs.fieldEditor.panel.changeToNow()
|
|
141
|
-
},
|
|
142
|
-
refreshDefaultValue() {
|
|
143
|
-
if (this.designState !== true) {
|
|
144
|
-
return
|
|
145
|
-
}
|
|
146
|
-
if (this.isNowDateValueType(this.field.options.defaultValueType)) {
|
|
147
|
-
this.fieldModel = this.getNowDateValue()
|
|
148
|
-
} else if (this.field.options.defaultValue !== undefined) {
|
|
149
|
-
this.fieldModel = this.field.options.defaultValue
|
|
150
|
-
}
|
|
151
142
|
}
|
|
152
143
|
}
|
|
153
144
|
}
|
package/src/components/xform/form-designer/form-widget/field-widget/mixins/date-limit-mixin.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/* 日期组件的最小日期支持配置为「当前时间」,此处统一解析。
|
|
2
|
+
默认值(含「当前时间」与相对偏移)已收敛到 relative-default-mixin,不在此处理。 */
|
|
2
3
|
export const DATE_VALUE_TYPE_NOW = "now";
|
|
3
4
|
|
|
4
5
|
export default {
|
|
@@ -9,35 +10,6 @@ export default {
|
|
|
9
10
|
isNowDateValueType(valueType) {
|
|
10
11
|
return valueType === DATE_VALUE_TYPE_NOW;
|
|
11
12
|
},
|
|
12
|
-
/* 按组件的valueFormat格式化,valueFormat为空时picker的值为Date对象 */
|
|
13
|
-
formatDateValue(date, valueFormat) {
|
|
14
|
-
if (!valueFormat) {
|
|
15
|
-
return date;
|
|
16
|
-
}
|
|
17
|
-
if (valueFormat === "timestamp") {
|
|
18
|
-
return date.getTime();
|
|
19
|
-
}
|
|
20
|
-
const pad = (val) => (val < 10 ? "0" + val : String(val));
|
|
21
|
-
const tokenMap = {
|
|
22
|
-
yyyy: String(date.getFullYear()),
|
|
23
|
-
yy: String(date.getFullYear()).slice(-2),
|
|
24
|
-
MM: pad(date.getMonth() + 1),
|
|
25
|
-
dd: pad(date.getDate()),
|
|
26
|
-
HH: pad(date.getHours()),
|
|
27
|
-
mm: pad(date.getMinutes()),
|
|
28
|
-
ss: pad(date.getSeconds()),
|
|
29
|
-
};
|
|
30
|
-
return valueFormat.replace(
|
|
31
|
-
/yyyy|yy|MM|dd|HH|mm|ss/g,
|
|
32
|
-
(token) => tokenMap[token]
|
|
33
|
-
);
|
|
34
|
-
},
|
|
35
|
-
/* 当前时间,dates(多选日期)类型的值为数组 */
|
|
36
|
-
getNowDateValue() {
|
|
37
|
-
const options = this.getDateLimitOptions();
|
|
38
|
-
const nowValue = this.formatDateValue(new Date(), options.valueFormat);
|
|
39
|
-
return options.type === "dates" ? [nowValue] : nowValue;
|
|
40
|
-
},
|
|
41
13
|
/* 最小日期:固定日期或当前时间 */
|
|
42
14
|
getDateLimitMinValue() {
|
|
43
15
|
const options = this.getDateLimitOptions();
|
|
@@ -202,21 +174,5 @@ export default {
|
|
|
202
174
|
}
|
|
203
175
|
return "日期超出允许范围";
|
|
204
176
|
},
|
|
205
|
-
/* 默认值配置为「当前时间」时,临时替换 defaultValue 后再走通用的取值逻辑 */
|
|
206
|
-
initDateFieldModel() {
|
|
207
|
-
const options = this.getDateLimitOptions();
|
|
208
|
-
if (!this.isNowDateValueType(options.defaultValueType)) {
|
|
209
|
-
this.initFieldModel();
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const rawDefaultValue = options.defaultValue;
|
|
214
|
-
options.defaultValue = this.getNowDateValue();
|
|
215
|
-
try {
|
|
216
|
-
this.initFieldModel();
|
|
217
|
-
} finally {
|
|
218
|
-
options.defaultValue = rawDefaultValue;
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
177
|
},
|
|
222
178
|
};
|
package/src/components/xform/form-designer/form-widget/field-widget/mixins/relative-default-mixin.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 日期/时间组件「相对默认值」的取值入口(date、date-range、time、time-range 共用)。
|
|
3
|
+
*
|
|
4
|
+
* 相对值必须每次初始化重算,绝不能写回 options.defaultValue —— options 会被序列化保存,
|
|
5
|
+
* 写回就变成死值。这里的做法是:先照常跑 initFieldModel(此时 options.defaultValue 为空,
|
|
6
|
+
* 不会填任何值),再在「本该取默认值」的场景下用 initValue 灌入现算的相对值。
|
|
7
|
+
*
|
|
8
|
+
* 放在 initFieldModel 之后灌值还顺带绕开了 utc-transform-mixin:相对值本身就是本地时间,
|
|
9
|
+
* 若参与 UTC→本地转换会再偏一次时区。
|
|
10
|
+
*/
|
|
11
|
+
import { resolveDefaultValueFromOptions } from "./relativeDateUtil";
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
methods: {
|
|
15
|
+
/**
|
|
16
|
+
* 当前配置对应的相对默认值;未配相对默认值返回 undefined(调用方走静态默认值)。
|
|
17
|
+
* @param {Date} baseDate 基准时刻,仅测试用
|
|
18
|
+
*/
|
|
19
|
+
getRelativeDefaultValue(baseDate) {
|
|
20
|
+
return resolveDefaultValueFromOptions(
|
|
21
|
+
this.field?.options,
|
|
22
|
+
this.field?.type,
|
|
23
|
+
baseDate
|
|
24
|
+
);
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
/** @returns {Boolean} 值是否为空(范围组件的空值是空数组) */
|
|
28
|
+
isEmptyFieldValue(value) {
|
|
29
|
+
if (value === null || value === undefined || value === "") {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return Array.isArray(value) && value.length === 0;
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 是否落在「新增时取默认值」的场景。
|
|
37
|
+
* 判定与 fieldMixin.initFieldModel 里的默认值分支保持一致:值为空 + 新增单据/新增明细行。
|
|
38
|
+
* @returns {Boolean}
|
|
39
|
+
*/
|
|
40
|
+
willInitDefaultValue() {
|
|
41
|
+
if (!this.field?.formItemFlag) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const currentData
|
|
45
|
+
= this.tableParam && this.tableParam.row
|
|
46
|
+
? this.tableParam.row
|
|
47
|
+
: this.formModel;
|
|
48
|
+
if (!currentData) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (!this.isEmptyFieldValue(currentData[this.fieldKeyName])) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (this.tableParam) {
|
|
55
|
+
return !this.tableParam.row.id; //明细:只有新增行才填默认值
|
|
56
|
+
}
|
|
57
|
+
const dataId = this.getFormRef()?.dataId ?? null;
|
|
58
|
+
return !dataId; //主表:只有新增单据才填默认值
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/** 取值入口,替代各日期组件 created 里直接调的 initFieldModel */
|
|
62
|
+
initRelativeFieldModel() {
|
|
63
|
+
const relativeValue = this.getRelativeDefaultValue();
|
|
64
|
+
if (relativeValue === undefined) {
|
|
65
|
+
this.initFieldModel();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const shouldInit = this.willInitDefaultValue();
|
|
69
|
+
this.initFieldModel();
|
|
70
|
+
if (shouldInit) {
|
|
71
|
+
this.initValue(relativeValue);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
/*
|
|
76
|
+
* 表单重置:相对模式按重置时刻重算,与新增时同口径;静态默认值维持 fieldMixin 的行为。
|
|
77
|
+
* 这里不委托 fieldMixin.resetField,是为了不把它那条重依赖链(公式引擎、codemirror)
|
|
78
|
+
* 拖进本文件;它对本 mixin 覆盖的日期/时间组件也只多一段附件组件的分支,用不上。
|
|
79
|
+
*/
|
|
80
|
+
resetField() {
|
|
81
|
+
if (this.subFormItemFlag) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const relativeValue = this.getRelativeDefaultValue();
|
|
85
|
+
this.setValue(
|
|
86
|
+
relativeValue === undefined
|
|
87
|
+
? this.field.options.defaultValue
|
|
88
|
+
: relativeValue
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/* 设计器里改默认值配置后的预览刷新,由 propertyMixin.emitDefaultValueChange 调用 */
|
|
93
|
+
refreshDefaultValue() {
|
|
94
|
+
if (this.designState !== true) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const relativeValue = this.getRelativeDefaultValue();
|
|
98
|
+
if (relativeValue !== undefined) {
|
|
99
|
+
this.fieldModel = relativeValue;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (this.field.options.defaultValue !== undefined) {
|
|
103
|
+
this.fieldModel = this.field.options.defaultValue;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|