cloud-web-corejs 1.0.54-dev.798 → 1.0.54-dev.799
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 +3 -1
- package/src/components/baseTabs/mixins.js +11 -12
- package/src/components/bizTab/BizBillActions.vue +129 -0
- package/src/components/bizTab/BizTabListPage.vue +391 -0
- package/src/components/bizTab/README.md +378 -0
- package/src/components/bizTab/billTableUtil.js +48 -0
- package/src/components/bizTab/billValidators.js +136 -0
- package/src/components/bizTab/bizBillDetailMixin.js +687 -0
- package/src/components/bizTab/index.js +24 -0
- package/src/components/excelExport/exportFieldDialog.vue +373 -367
- package/src/components/excelExport/exportType.js +49 -0
- package/src/components/excelExport/mixins.js +1153 -1144
- package/src/components/vb-tabs/x-tabs.vue +167 -143
- package/src/components/wf/wfUtil.js +327 -292
- package/src/components/xform/form-designer/designer.js +56 -8
- package/src/components/xform/form-designer/form-widget/container-widget/detail-widget.vue +59 -5
- package/src/components/xform/form-designer/form-widget/field-widget/baseAttachment-widget.vue +60 -8
- package/src/components/xform/form-designer/form-widget/field-widget/form-item-wrapper.vue +8 -2
- package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +120 -92
- package/src/components/xform/form-designer/form-widget/field-widget/vabUpload-widget.vue +63 -94
- package/src/components/xform/form-designer/index.vue +0 -1
- package/src/components/xform/form-designer/setting-panel/dataSource-setting.vue +397 -397
- package/src/components/xform/form-designer/setting-panel/form-dynamicField-setting.vue +602 -602
- package/src/components/xform/form-designer/setting-panel/form-setting.vue +13 -13
- package/src/components/xform/form-designer/setting-panel/option-items-setting.vue +585 -585
- package/src/components/xform/form-designer/setting-panel/property-editor/a-link-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/a-text-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/alignType-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/censusClass-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/colorClass-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/commonAttributeEnabled-editor.vue +3 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/data-table-editor.vue +1154 -1154
- package/src/components/xform/form-designer/setting-panel/property-editor/container-detail/detail-editor.vue +96 -80
- package/src/components/xform/form-designer/setting-panel/property-editor/container-detail-plain/detail-plain-editor.vue +75 -75
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid/colHeight-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid-col/grid-col-height-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid-col/grid-col-offset-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid-col/grid-col-pull-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid-col/grid-col-push-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-grid-col/grid-col-span-editor.vue +4 -4
- package/src/components/xform/form-designer/setting-panel/property-editor/container-h5-card/h5-card-editor.vue +124 -124
- package/src/components/xform/form-designer/setting-panel/property-editor/container-panel/height-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-panel/width-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-tab/tab-customClass-editor.vue +119 -119
- package/src/components/xform/form-designer/setting-panel/property-editor/container-tab/tabClass-editor.vue +45 -45
- package/src/components/xform/form-designer/setting-panel/property-editor/container-table/table-dynamicField-editor.vue +344 -344
- package/src/components/xform/form-designer/setting-panel/property-editor/container-table-cell/cellHeight-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-table-cell/cellWidth-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-tree/tree-customClass-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/container-tree-pane/tree-pane-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-vf-dialog/cancelButtonLabel-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-vf-dialog/okButtonLabel-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-vf-dialog/title-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/container-vf-dialog/width-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/containerClass-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/customClass-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/defaultValue-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/descriptionsItems-editor.vue +4 -4
- package/src/components/xform/form-designer/setting-panel/property-editor/downloadButtonFlag-editor.vue +3 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/dropdownFlag-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/dsName-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/echartHeight-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/endPlaceholder-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-accessUrl/accessUrl-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-area-select/areaDataType-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-area-select/areaMinLevel-editor.vue +50 -50
- package/src/components/xform/form-designer/setting-panel/property-editor/field-area-select/areaName-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-autocomplete/autocomplete-vabSearchName-editor.vue +7 -7
- package/src/components/xform/form-designer/setting-panel/property-editor/field-button/addTableData-event-editor.vue +84 -84
- package/src/components/xform/form-designer/setting-panel/property-editor/field-button/button-type-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-button/clickBindEvent-editor.vue +97 -97
- package/src/components/xform/form-designer/setting-panel/property-editor/field-button/form-host-event-editor.vue +188 -188
- 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 +74 -67
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-dateLimit-editor.vue +4 -4
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-format-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-type-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-valueFormat-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultTime-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-format-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-type-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-valueFormat-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-divider/contentPosition-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-dropdown-menu/dropdown-menu-editor.vue +59 -59
- package/src/components/xform/form-designer/setting-panel/property-editor/field-echart/echart-bar-editor.vue +11 -11
- package/src/components/xform/form-designer/setting-panel/property-editor/field-echart/echart-category-editor.vue +10 -10
- package/src/components/xform/form-designer/setting-panel/property-editor/field-echart/echart-pie-editor.vue +12 -12
- package/src/components/xform/form-designer/setting-panel/property-editor/field-file-upload/file-upload-fileTypes-editor.vue +44 -44
- package/src/components/xform/form-designer/setting-panel/property-editor/field-html-text/htmlContent-editor.vue +29 -29
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import-button-editor.vue +6 -6
- package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import2-button-editor.vue +3 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/field-number/controlsPosition-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-picture-upload/picture-upload-fileTypes-editor.vue +44 -44
- package/src/components/xform/form-designer/setting-panel/property-editor/field-print-button/print-button-editor.vue +115 -115
- package/src/components/xform/form-designer/setting-panel/property-editor/field-print-button/print-detail-button-editor.vue +115 -115
- package/src/components/xform/form-designer/setting-panel/property-editor/field-rate/highThreshold-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-rate/lowThreshold-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-rate/rate-defaultValue-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-rate/rate-max-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-script/script-editor.vue +4 -4
- package/src/components/xform/form-designer/setting-panel/property-editor/field-script-input/script-input-editor.vue +4 -4
- package/src/components/xform/form-designer/setting-panel/property-editor/field-static-text/fontSize-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-static-text/textContent-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-status/field-status-editor.vue +3 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/field-switch/activeText-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-switch/inactiveText-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-switch/switchWidth-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-button-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +74 -71
- package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/table-export-button-editor.vue +3 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time/time-format-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time/time-timeLimit-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-time-range/time-range-format-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-vabSearch/vabSearchField-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-vabSearch/vabSearchName-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/field-vabUpload/field-vabUpload-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-vabUpload2/field-vabUpload2-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/field-vue-page/vue-page-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/fileMaxSize-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/fileTypesSelect.vue +176 -176
- package/src/components/xform/form-designer/setting-panel/property-editor/formScriptEnabled-editor.vue +2 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/formatType-editor.vue +2 -2
- package/src/components/xform/form-designer/setting-panel/property-editor/formula-editor.vue +972 -972
- package/src/components/xform/form-designer/setting-panel/property-editor/iconClass-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/label-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/labelAlign-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/labelColor-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/labelIconPosition-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/labelWidth-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/limit-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/max-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/maxLength-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/min-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/minLength-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/multipleLimit-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/name-editor.vue +178 -178
- package/src/components/xform/form-designer/setting-panel/property-editor/oplog-editor.vue +3 -3
- package/src/components/xform/form-designer/setting-panel/property-editor/placeholder-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/precision-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/project-tag-editor.vue +6 -6
- package/src/components/xform/form-designer/setting-panel/property-editor/requiredHint-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/rows-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/space-editor-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/startPlaceholder-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/step-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/styleTableClass-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/styleTitClass-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/tempStorage-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/type-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/uploadTip-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/uploadURL-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/urlValueEnabled-editor.vue +91 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/validation-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/validationHint-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/property-editor/widgetWidth-editor.vue +1 -1
- package/src/components/xform/form-designer/setting-panel/propertyRegister.js +1 -0
- package/src/components/xform/form-designer/widget-panel/index.vue +3 -1
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +55 -13
- package/src/components/xform/form-render/container-item/data-table-mixin copy.js +5910 -0
- package/src/components/xform/form-render/container-item/data-table-mixin.js +59 -13
- package/src/components/xform/form-render/container-item/detail-item.vue +52 -11
- package/src/components/xform/form-render/container-item/tab-item.vue +6 -2
- package/src/components/xform/form-render/indexMixin.js +56 -16
- package/src/components/xform/lang/zh-CN.js +2 -1
- package/src/components/xform/utils/attachmentValueUtil.js +239 -0
- package/src/components/xform/utils/util.js +27 -0
- package/src/mixins/wf/index.js +40 -38
- package/src/router/modules/customer.js +50 -0
- package/src/store/config/index.js +46 -0
- package/src/utils/scrollUtil.js +25 -0
- package/src/views/demo/bizTab/bill/billConfig.js +41 -0
- package/src/views/demo/bizTab/bill/detail.vue +436 -0
- package/src/views/demo/bizTab/bill/list.vue +288 -0
- package/src/views/demo/bizTab/bill/productDialog.vue +176 -0
- package/src/views/demo/bizTab/simple/billApi.js +123 -0
- package/src/views/demo/bizTab/simple/detail.vue +407 -0
- package/src/views/demo/bizTab/simple/list.vue +217 -0
- package/src/views/demo/bizTab/standalone/index.vue +121 -0
- package/src/views/demo/bizTab/wf/billConfig.js +44 -0
- package/src/views/demo/bizTab/wf/detail.vue +661 -0
- package/src/views/demo/bizTab/wf/list.vue +242 -0
- package/src/views/user/outLink/cc_form_view.vue +185 -0
|
@@ -26,6 +26,12 @@ import {
|
|
|
26
26
|
resolveColumnRequiredFlag,
|
|
27
27
|
} from "../../../../components/xform/utils/tableColumnHelper";
|
|
28
28
|
import { mergeQueryParam } from "../../../../components/xform/utils/queryParamUtil";
|
|
29
|
+
import { isUrlValueColumn } from "../../../../components/xform/utils/attachmentValueUtil";
|
|
30
|
+
import {
|
|
31
|
+
EXPORT_TYPE,
|
|
32
|
+
isItemExport,
|
|
33
|
+
requiresCheckedRows,
|
|
34
|
+
} from "../../../../components/excelExport/exportType";
|
|
29
35
|
import {
|
|
30
36
|
buildCellRequiredHint,
|
|
31
37
|
buildTableCellFormProp,
|
|
@@ -2572,8 +2578,12 @@ modules = {
|
|
|
2572
2578
|
let originOption = $grid.params.originOption;
|
|
2573
2579
|
let formData = {};
|
|
2574
2580
|
|
|
2575
|
-
|
|
2576
|
-
|
|
2581
|
+
// 明细·选择导出已按勾选行 id 精确定位,再叠加主表搜索条件既无意义、又可能
|
|
2582
|
+
// 与明细口径的字段名冲突造成双重过滤,故只有它排除搜索条件;
|
|
2583
|
+
// 明细·条件导出与主表条件导出一样,必须带上搜索条件。
|
|
2584
|
+
if (
|
|
2585
|
+
customParam?.exportParam?.type !== EXPORT_TYPE.ITEM_SELECTED
|
|
2586
|
+
) {
|
|
2577
2587
|
formData = tableOption.param ? tableOption.param() || {} : {};
|
|
2578
2588
|
}
|
|
2579
2589
|
const queryParams = Object.assign({}, formData);
|
|
@@ -2993,13 +3003,29 @@ modules = {
|
|
|
2993
3003
|
let result = [];
|
|
2994
3004
|
this.loodHandleColumns(this.widget.options.tableColumns, (item) => {
|
|
2995
3005
|
if (!item.children?.length && item.prop && item.label) {
|
|
2996
|
-
|
|
3006
|
+
// 开了「值存为URL」的附件列是明细表自己的普通列,不走独立附件通道
|
|
3007
|
+
if (item.formatS === "editAttachment" && !isUrlValueColumn(item)) {
|
|
2997
3008
|
result.push(item.prop);
|
|
2998
3009
|
}
|
|
2999
3010
|
}
|
|
3000
3011
|
});
|
|
3001
3012
|
return result;
|
|
3002
3013
|
},
|
|
3014
|
+
/**
|
|
3015
|
+
* 开了「值存为URL」的附件列 prop 集合。这类列的值是 URL 字符串、存在明细表
|
|
3016
|
+
* 自己的列上,凡是按「附件」特殊处理的链路(attachmentType 上送、保存时
|
|
3017
|
+
* attachments_ 提包)都要把它排除掉。
|
|
3018
|
+
* @returns {Array<String>}
|
|
3019
|
+
*/
|
|
3020
|
+
getUrlValueAttachmentProps() {
|
|
3021
|
+
let result = [];
|
|
3022
|
+
this.loodHandleColumns(this.widget.options.tableColumns, (item) => {
|
|
3023
|
+
if (!item.children?.length && item.prop && isUrlValueColumn(item)) {
|
|
3024
|
+
result.push(item.prop);
|
|
3025
|
+
}
|
|
3026
|
+
});
|
|
3027
|
+
return result;
|
|
3028
|
+
},
|
|
3003
3029
|
/** @returns {Array} 当前表格使用的三级表字段。 */
|
|
3004
3030
|
getThirdtabm() {
|
|
3005
3031
|
/* let vailColumns = this.widget.options.tableColumns.filter(
|
|
@@ -3123,7 +3149,8 @@ modules = {
|
|
|
3123
3149
|
let scriptCode = this.getScriptCode();
|
|
3124
3150
|
let accessParam = {};
|
|
3125
3151
|
let otherParam = {};
|
|
3126
|
-
|
|
3152
|
+
let exportType = customParam?.exportParam?.type;
|
|
3153
|
+
if (isItemExport(exportType)) {
|
|
3127
3154
|
let $grid = this.getGridTable();
|
|
3128
3155
|
let originOption = $grid.params.originOption;
|
|
3129
3156
|
let exportItemConfig = originOption.exportItemConfig || {};
|
|
@@ -3132,9 +3159,14 @@ modules = {
|
|
|
3132
3159
|
}
|
|
3133
3160
|
if (exportItemConfig.columns?.length) {
|
|
3134
3161
|
let result = [];
|
|
3162
|
+
// 导出用的是 vxe 列(field/title),拿不到组件 schema,按 prop 反查 URL 模式列
|
|
3163
|
+
let urlValueProps = this.getUrlValueAttachmentProps();
|
|
3135
3164
|
this.loodHandleColumns(exportItemConfig.columns, (item) => {
|
|
3136
3165
|
if (!item.children?.length && item.field && item.title) {
|
|
3137
|
-
if (
|
|
3166
|
+
if (
|
|
3167
|
+
item.field.startsWith("attachments_") &&
|
|
3168
|
+
urlValueProps.indexOf(item.field) === -1
|
|
3169
|
+
) {
|
|
3138
3170
|
result.push(item.field);
|
|
3139
3171
|
}
|
|
3140
3172
|
}
|
|
@@ -3143,14 +3175,16 @@ modules = {
|
|
|
3143
3175
|
otherParam.attachmentType = result;
|
|
3144
3176
|
}
|
|
3145
3177
|
}
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
}
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3178
|
+
if (exportItemConfig.param) {
|
|
3179
|
+
accessParam = exportItemConfig.param() || {};
|
|
3180
|
+
}
|
|
3181
|
+
// 只有选择模式以勾选行 id 为过滤条件;条件模式下由搜索条件 + exportItemParam 决定范围,
|
|
3182
|
+
// 写入空的 ids 会被后端当成"无匹配"。
|
|
3183
|
+
if (requiresCheckedRows(exportType)) {
|
|
3184
|
+
accessParam.ids = $grid.getCheckboxRecords(true).map((item) => {
|
|
3185
|
+
return item.id;
|
|
3186
|
+
});
|
|
3152
3187
|
}
|
|
3153
|
-
accessParam.ids = ids;
|
|
3154
3188
|
} else {
|
|
3155
3189
|
accessParam = this.getAccessParam() || {};
|
|
3156
3190
|
let attachmentType = this.getAttachmentType();
|
|
@@ -3311,6 +3345,12 @@ modules = {
|
|
|
3311
3345
|
nullValue = [];
|
|
3312
3346
|
} else if (widgetType === "vabsearch" && widget.options.multipleChoices) {
|
|
3313
3347
|
nullValue = [];
|
|
3348
|
+
} else if (
|
|
3349
|
+
isAttachmentWidgetType(widgetType) &&
|
|
3350
|
+
widget.options.urlValueEnabled
|
|
3351
|
+
) {
|
|
3352
|
+
/* 开了「值存为URL」的附件列存的是 URL 字符串,空值不能给 [] */
|
|
3353
|
+
nullValue = null;
|
|
3314
3354
|
} else if (
|
|
3315
3355
|
multiWidgetTypes.includes(widgetType) ||
|
|
3316
3356
|
isAttachmentWidgetType(widgetType)
|
|
@@ -4204,8 +4244,14 @@ modules = {
|
|
|
4204
4244
|
let formData = {
|
|
4205
4245
|
[entity]: mainData,
|
|
4206
4246
|
};
|
|
4247
|
+
// attachments_ 开头的键要提到顶层当独立附件包发;但开了「值存为URL」的
|
|
4248
|
+
// 附件列存的是本表自己列上的 URL 字符串,提出去主表列就存不到了
|
|
4249
|
+
let urlValueProps = this.getUrlValueAttachmentProps();
|
|
4207
4250
|
Object.keys(mainData).forEach((key) => {
|
|
4208
|
-
if (
|
|
4251
|
+
if (
|
|
4252
|
+
key.startsWith("attachments_") &&
|
|
4253
|
+
urlValueProps.indexOf(key) === -1
|
|
4254
|
+
) {
|
|
4209
4255
|
formData[key] = mainData[key];
|
|
4210
4256
|
}
|
|
4211
4257
|
});
|
|
@@ -101,18 +101,59 @@
|
|
|
101
101
|
</template>
|
|
102
102
|
</div>
|
|
103
103
|
</div>
|
|
104
|
+
<!-- 正文区:panes 是通用容器列表,既可直接挂 detail-pane(模块),也可挂 tab 等其它容器。
|
|
105
|
+
baseTabs 的锚点导航靠 getTabs() 探测 slot 子级:detail-pane 带 tabPaneGrade=2 会被收进
|
|
106
|
+
navList;tab 等容器两个条件都不满足,被静默跳过——即标签内的模块不进外层导航,由标签内
|
|
107
|
+
自己的 detail-plain 负责(见 docs/详情模块标签承载方案.md)。 -->
|
|
104
108
|
<baseTabs :showNav="!widget.options.hideNav && !plainMode">
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
109
|
+
<template v-for="(paneWidget, index) in widget.panes">
|
|
110
|
+
<detail-pane-widget
|
|
111
|
+
v-if="paneWidget.type === 'detail-pane'"
|
|
112
|
+
:key="paneWidget.id || index"
|
|
113
|
+
:widget="paneWidget"
|
|
114
|
+
:parent-list="widget.panes"
|
|
115
|
+
:index-of-parent-list="index"
|
|
116
|
+
:parent-widget="widget"
|
|
117
|
+
:col-height="widget.options.colHeight"
|
|
118
|
+
tabRef="baseTabRef"
|
|
119
|
+
:tabPaneGrade="2"
|
|
120
|
+
></detail-pane-widget>
|
|
121
|
+
<component
|
|
122
|
+
v-else-if="'container' === paneWidget.category"
|
|
123
|
+
:is="paneWidget.type + '-item'"
|
|
124
|
+
:key="paneWidget.id || index"
|
|
125
|
+
:widget="paneWidget"
|
|
126
|
+
:parent-list="widget.panes"
|
|
127
|
+
:index-of-parent-list="index"
|
|
128
|
+
:parent-widget="widget"
|
|
129
|
+
>
|
|
130
|
+
<!-- 递归传递插槽!!! -->
|
|
131
|
+
<template
|
|
132
|
+
v-for="slot in Object.keys($scopedSlots)"
|
|
133
|
+
v-slot:[slot]="scope"
|
|
134
|
+
>
|
|
135
|
+
<slot :name="slot" v-bind="scope" />
|
|
136
|
+
</template>
|
|
137
|
+
</component>
|
|
138
|
+
<component
|
|
139
|
+
v-else
|
|
140
|
+
:is="paneWidget.type + '-widget'"
|
|
141
|
+
:key="paneWidget.id || index"
|
|
142
|
+
:field="paneWidget"
|
|
143
|
+
:designer="null"
|
|
144
|
+
:parent-list="widget.panes"
|
|
145
|
+
:index-of-parent-list="index"
|
|
146
|
+
:parent-widget="widget"
|
|
147
|
+
>
|
|
148
|
+
<!-- 递归传递插槽!!! -->
|
|
149
|
+
<template
|
|
150
|
+
v-for="slot in Object.keys($scopedSlots)"
|
|
151
|
+
v-slot:[slot]="scope"
|
|
152
|
+
>
|
|
153
|
+
<slot :name="slot" v-bind="scope" />
|
|
154
|
+
</template>
|
|
155
|
+
</component>
|
|
156
|
+
</template>
|
|
116
157
|
</baseTabs>
|
|
117
158
|
</div>
|
|
118
159
|
</container-item-wrapper>
|
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
:class="widget.options.isFullscreen ? 'full-height' : ''"
|
|
5
5
|
>
|
|
6
6
|
<div :key="widget.id" class="tab-container mHeight" v-show="!widget.options.hidden">
|
|
7
|
+
<!-- 高度默认 auto(跟随内容):没在属性面板配 height 就不设。
|
|
8
|
+
原来兜底成固定 300px,内容多了内部滚动、少了留白,装详情内容模块时尤其别扭 -->
|
|
7
9
|
<el-tabs
|
|
8
10
|
v-model="activeTabName"
|
|
9
11
|
:type="widget.displayType"
|
|
10
12
|
:ref="widget.id"
|
|
11
13
|
:class="[customClass, widget.options.tabClass]"
|
|
12
14
|
:style="{
|
|
13
|
-
height: widget.options.isFullscreen ? '' : widget.options.height
|
|
15
|
+
height: widget.options.isFullscreen ? '' : widget.options.height,
|
|
14
16
|
}"
|
|
15
17
|
>
|
|
16
18
|
<el-tab-pane
|
|
@@ -121,5 +123,7 @@ export default {
|
|
|
121
123
|
</script>
|
|
122
124
|
|
|
123
125
|
<style lang="scss" scoped>
|
|
124
|
-
|
|
126
|
+
/* 内容区高度跟随内容。原来写死 min-height:312px,会把上面 height:auto 的效果整个抵消掉
|
|
127
|
+
(无论内容多少都至少 312px)。这里只留一个小兜底,保证空标签页不塌成一条线。 */
|
|
128
|
+
::v-deep .mHeight .el-tabs .el-tabs__content{min-height:60px}
|
|
125
129
|
</style>
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
getColumnWidgetOptions,
|
|
28
28
|
applyColumnMetaToFieldWidget,
|
|
29
29
|
applyColumnMetaToColumnRow,
|
|
30
|
+
cloneColumnFieldWidget,
|
|
30
31
|
isArrayValueWidgetType,
|
|
31
32
|
isEmptyArrayFieldValue,
|
|
32
33
|
XFORM_SYSTEM_FIELDS,
|
|
@@ -41,6 +42,7 @@ import {
|
|
|
41
42
|
hiddenWidgetTypesOfWf,
|
|
42
43
|
freeWidgetTypesOfWf,
|
|
43
44
|
} from "../../../components/xform/form-designer/widget-panel/widgetsConfig.js";
|
|
45
|
+
import { isUrlValueColumn } from "../../../components/xform/utils/attachmentValueUtil";
|
|
44
46
|
import scriptHttpMixin from "../../../components/xform/mixins/scriptHttp";
|
|
45
47
|
import defaultHandleMixin from "../../../components/xform/mixins/defaultHandle";
|
|
46
48
|
import xeUtils from "xe-utils";
|
|
@@ -660,10 +662,22 @@ modules = {
|
|
|
660
662
|
}
|
|
661
663
|
} else {
|
|
662
664
|
let type1 = columnFormatMap[t.formatS];
|
|
665
|
+
let type2 = columnFormatMap[t.editFormatS];
|
|
666
|
+
// 展示/编辑同类型且只配了一方时,另一方从已配置的一方复制:
|
|
667
|
+
// 按类型新建的是空白 schema,defaultValue、optionItems、searchDialogConfig
|
|
668
|
+
// 等只配在一方的属性会丢,编辑表新增行取 editWidget 默认值时同样受影响。
|
|
669
|
+
let inheritable = !!type1 && type1 === type2;
|
|
663
670
|
if (type1) {
|
|
664
671
|
if (!t.widget) {
|
|
665
|
-
|
|
666
|
-
|
|
672
|
+
if (inheritable && t.editWidget) {
|
|
673
|
+
t.widget = applyColumnMetaToFieldWidget(
|
|
674
|
+
cloneColumnFieldWidget(t.editWidget),
|
|
675
|
+
t,
|
|
676
|
+
false
|
|
677
|
+
);
|
|
678
|
+
} else {
|
|
679
|
+
t.widget = this.getColumnWidget(t, false);
|
|
680
|
+
}
|
|
667
681
|
} else {
|
|
668
682
|
applyColumnMetaToFieldWidget(t.widget, t, false);
|
|
669
683
|
}
|
|
@@ -672,11 +686,17 @@ modules = {
|
|
|
672
686
|
this.normalizeActionColumnWidget(t.widget, t.formatS);
|
|
673
687
|
}
|
|
674
688
|
}
|
|
675
|
-
let type2 = columnFormatMap[t.editFormatS];
|
|
676
689
|
if (type2) {
|
|
677
690
|
if (!t.editWidget) {
|
|
678
|
-
|
|
679
|
-
|
|
691
|
+
if (inheritable && t.widget) {
|
|
692
|
+
t.editWidget = applyColumnMetaToFieldWidget(
|
|
693
|
+
cloneColumnFieldWidget(t.widget),
|
|
694
|
+
t,
|
|
695
|
+
true
|
|
696
|
+
);
|
|
697
|
+
} else {
|
|
698
|
+
t.editWidget = this.getColumnWidget(t, true);
|
|
699
|
+
}
|
|
680
700
|
} else {
|
|
681
701
|
applyColumnMetaToFieldWidget(t.editWidget, t, true);
|
|
682
702
|
}
|
|
@@ -1658,17 +1678,29 @@ modules = {
|
|
|
1658
1678
|
t.buildDataFromWidget(e);
|
|
1659
1679
|
});
|
|
1660
1680
|
});
|
|
1661
|
-
else if ("detail" === e.type || "detail-plain" === e.type)
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1681
|
+
else if ("detail" === e.type || "detail-plain" === e.type) {
|
|
1682
|
+
// 递归下钻。原来是写死两层展开 panes[].widgetList,而 panes 现在是通用容器列表——
|
|
1683
|
+
// 除 detail-pane(内容模块)外还可能挂 tab 容器承载标签,写死两层会把标签下的字段
|
|
1684
|
+
// 整支漏掉,表现为数据不绑定。
|
|
1685
|
+
// 注:detail.widgetList(标题栏按钮区)沿用原口径,仍不参与建模。
|
|
1686
|
+
if (e.panes) {
|
|
1687
|
+
e.panes.forEach(function (paneItem) {
|
|
1688
|
+
t.buildDataFromWidget(paneItem);
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
} else if ("detail-pane" === e.type) {
|
|
1692
|
+
// 模块正文 + 模块标题栏按钮区。后者原先漏建模,按钮区里放字段组件时取不到值。
|
|
1693
|
+
if (e.widgetList) {
|
|
1694
|
+
e.widgetList.forEach(function (childItem) {
|
|
1695
|
+
t.buildDataFromWidget(childItem);
|
|
1670
1696
|
});
|
|
1671
|
-
|
|
1697
|
+
}
|
|
1698
|
+
if (e.buttonWidgetList) {
|
|
1699
|
+
e.buttonWidgetList.forEach(function (childItem) {
|
|
1700
|
+
t.buildDataFromWidget(childItem);
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
} else if ("sub-form" === e.type) {
|
|
1672
1704
|
let i = e.options.name;
|
|
1673
1705
|
if (currentFormData.hasOwnProperty(i)) {
|
|
1674
1706
|
let n = currentFormData[i];
|
|
@@ -2932,7 +2964,9 @@ modules = {
|
|
|
2932
2964
|
} else if (
|
|
2933
2965
|
item.prop &&
|
|
2934
2966
|
item.label &&
|
|
2935
|
-
item.formatS === "editAttachment"
|
|
2967
|
+
item.formatS === "editAttachment" &&
|
|
2968
|
+
// 开了「值存为URL」的附件列是明细表自己的普通列,不走独立附件通道
|
|
2969
|
+
!isUrlValueColumn(item)
|
|
2936
2970
|
) {
|
|
2937
2971
|
result.push(item.prop);
|
|
2938
2972
|
}
|
|
@@ -2984,6 +3018,8 @@ modules = {
|
|
|
2984
3018
|
let result = [];
|
|
2985
3019
|
getAllFieldWidgets(widgetList).forEach((w) => {
|
|
2986
3020
|
if (w.field && excludeTypes.indexOf(w.type) !== -1) {
|
|
3021
|
+
// 开了「值存为URL」的附件字段是主表普通列,值随 getOne 一起回来,不发独立包
|
|
3022
|
+
if (w.field.options && w.field.options.urlValueEnabled) return;
|
|
2987
3023
|
result.push({
|
|
2988
3024
|
name: this.getFieldKeyName(w.field),
|
|
2989
3025
|
scriptCode: w.field.options.formScriptCode || "getList",
|
|
@@ -3337,6 +3373,10 @@ modules = {
|
|
|
3337
3373
|
options.excludeTypes || this.compareExcludeTypes || [];
|
|
3338
3374
|
this.getFieldWidgets().forEach((w) => {
|
|
3339
3375
|
if (excludeTypes.indexOf(w.type) === -1) return;
|
|
3376
|
+
// URL 模式字段存的是字符串,不是文件对象,不需要按白名单精简
|
|
3377
|
+
if (w.field && w.field.options && w.field.options.urlValueEnabled) {
|
|
3378
|
+
return;
|
|
3379
|
+
}
|
|
3340
3380
|
attachKeySet[this.getFieldKeyName(w.field)] = true;
|
|
3341
3381
|
});
|
|
3342
3382
|
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 附件字段值归一工具。
|
|
3
|
+
*
|
|
4
|
+
* 附件组件(baseUpload / base-attachment)只认「附件对象」这一种形态:
|
|
5
|
+
* { domain, url, thumbnail, medium, large, source, name, extension, ... },
|
|
6
|
+
* 其中 domain 与路径是分开的两个字段,渲染时靠 domain + url 拼接。
|
|
7
|
+
* 外部(接口返回、setValue 脚本、字段默认值)常常直接给一个完整 URL 字符串或
|
|
8
|
+
* URL 数组,两个组件对这种值的容忍度不一致(vabUpload 丢裸字符串、baseAttachment
|
|
9
|
+
* 裂数组内的字符串),故在字段层统一归一:进来的一律转成附件对象数组,出去的按
|
|
10
|
+
* 字段配置决定是对象数组还是 URL 字符串。
|
|
11
|
+
*/
|
|
12
|
+
import Vue from "vue";
|
|
13
|
+
|
|
14
|
+
/* 顶层字符串支持逗号/换行分隔多个 URL */
|
|
15
|
+
const URL_SEPARATOR_REG = /[,\n\r]+/;
|
|
16
|
+
/* 协议(或协议相对) + 域名 */
|
|
17
|
+
const DOMAIN_REG = /^((?:https?:)?\/\/[^/]+)/i;
|
|
18
|
+
|
|
19
|
+
function isPlainObject(val) {
|
|
20
|
+
return Object.prototype.toString.call(val) === "[object Object]";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* $commonFileUtil 挂在 Vue.prototype 上(src/utils/vab.js),这里延迟取,
|
|
24
|
+
避免 util 直接 import vab.js(它会拉起 request/store/element-ui 全家桶)。 */
|
|
25
|
+
function getFileUtil() {
|
|
26
|
+
let fileUtil = Vue.prototype.$commonFileUtil;
|
|
27
|
+
if (!fileUtil && typeof window !== "undefined" && window.$vueRoot) {
|
|
28
|
+
fileUtil = window.$vueRoot.$commonFileUtil;
|
|
29
|
+
}
|
|
30
|
+
return fileUtil || null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* 图片判定必须复用 $commonFileUtil,另造一套白名单会和渲染层
|
|
34
|
+
getShowUrl 的判定打架(它的白名单不含 svg/tif) */
|
|
35
|
+
function isPictureFile(purePath) {
|
|
36
|
+
let fileUtil = getFileUtil();
|
|
37
|
+
return fileUtil ? !!fileUtil.isPictureFile(purePath) : false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getExtension(fileName) {
|
|
41
|
+
let i = fileName.lastIndexOf(".");
|
|
42
|
+
return i < 0 ? "" : fileName.substring(i + 1).toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 解析一个 URL(绝对/协议相对/相对路径)为附件对象。
|
|
47
|
+
* 非法输入返回 null(不抛异常),调用方无需 try/catch。
|
|
48
|
+
*
|
|
49
|
+
* @param {String} fileUrl
|
|
50
|
+
* @returns {Object|null} { domain, url, thumbnail, medium, large, source, name, extension }
|
|
51
|
+
*/
|
|
52
|
+
export function parseFileUrl(fileUrl) {
|
|
53
|
+
if (typeof fileUrl !== "string") {
|
|
54
|
+
if (fileUrl !== null && fileUrl !== undefined) {
|
|
55
|
+
console.warn("[attachmentValueUtil] 附件 URL 必须是字符串:", fileUrl);
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
let value = fileUrl.trim();
|
|
60
|
+
if (!value) return null;
|
|
61
|
+
|
|
62
|
+
let domain = "";
|
|
63
|
+
let url = value;
|
|
64
|
+
let domainMatch = value.match(DOMAIN_REG);
|
|
65
|
+
if (domainMatch) {
|
|
66
|
+
domain = domainMatch[0];
|
|
67
|
+
url = value.substring(domain.length);
|
|
68
|
+
if (!url || url === "/") {
|
|
69
|
+
console.warn("[attachmentValueUtil] URL 缺少文件路径部分:", fileUrl);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* 后缀与文件名要按剥掉 query/hash 的纯路径算(a.png?sign=xx 否则会被当成
|
|
75
|
+
非图片),但 url/medium 等字段必须保留含 query 的原始路径——签名 URL 依赖它 */
|
|
76
|
+
let purePath = url.split(/[?#]/)[0];
|
|
77
|
+
let i = purePath.lastIndexOf("/");
|
|
78
|
+
let fileName = i >= 0 ? purePath.substring(i + 1) : purePath;
|
|
79
|
+
if (!fileName) {
|
|
80
|
+
console.warn("[attachmentValueUtil] 无法从 URL 中提取文件名:", fileUrl);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
fileName = decodeURIComponent(fileName);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
/* 非法转义序列,保留原文件名 */
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let extension = getExtension(fileName);
|
|
90
|
+
/* 非图片不填缩略图字段,与 obsUpload 的既有做法一致;渲染层拿不到 medium
|
|
91
|
+
会退回 url 并显示文件类型图标 */
|
|
92
|
+
let picture = isPictureFile(purePath);
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
domain,
|
|
96
|
+
url,
|
|
97
|
+
thumbnail: picture ? url : null,
|
|
98
|
+
medium: picture ? url : null,
|
|
99
|
+
large: picture ? url : null,
|
|
100
|
+
source: picture ? url : null,
|
|
101
|
+
name: fileName,
|
|
102
|
+
extension,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 把任意形态的附件字段值归一成附件对象数组。
|
|
108
|
+
* 支持:null / 字符串 / 逗号或换行分隔的字符串 / 字符串数组 / 对象 / 对象数组 / 混合数组。
|
|
109
|
+
* 已经是对象的原样保留——重新解析会丢掉后端字段(id、fileSize、createDate、attachCode 等)。
|
|
110
|
+
*
|
|
111
|
+
* @param {*} val
|
|
112
|
+
* @returns {Array<Object>}
|
|
113
|
+
*/
|
|
114
|
+
export function normalizeAttachmentValue(val) {
|
|
115
|
+
if (val === null || val === undefined || val === "") return [];
|
|
116
|
+
|
|
117
|
+
let list;
|
|
118
|
+
if (Array.isArray(val)) {
|
|
119
|
+
/* 已经全是附件对象(无需转换)时必须原样返回,不能新建数组:调用方会把它写回
|
|
120
|
+
表单模型,而 fieldMixin.initValueWatchEvent 监听模型值——换一个新数组就等于
|
|
121
|
+
模型值"变了",会被灌回 fieldModel 再触发一轮回写,无限循环(查询列表里每行
|
|
122
|
+
一个附件单元格,一查询整页卡死)。空数组同理。 */
|
|
123
|
+
if (val.every(isPlainObject)) return val;
|
|
124
|
+
list = val;
|
|
125
|
+
} else if (isPlainObject(val)) {
|
|
126
|
+
return Object.keys(val).length ? [val] : [];
|
|
127
|
+
} else if (typeof val === "string") {
|
|
128
|
+
list = val.split(URL_SEPARATOR_REG);
|
|
129
|
+
} else {
|
|
130
|
+
console.warn("[attachmentValueUtil] 无法识别的附件值:", val);
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let rows = [];
|
|
135
|
+
list.forEach((item) => {
|
|
136
|
+
if (!item) return;
|
|
137
|
+
if (isPlainObject(item)) {
|
|
138
|
+
rows.push(item);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
let row = parseFileUrl(item);
|
|
142
|
+
if (row) rows.push(row);
|
|
143
|
+
});
|
|
144
|
+
return rows;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 附件对象数组 → URL 字符串。拼接规则与 baseUpload 的 dataType 分支一致。
|
|
149
|
+
*
|
|
150
|
+
* @param {Array} rows
|
|
151
|
+
* @param {Object} opts { field: "url"(原文件)|"large"|"medium"|"thumbnail", multi: Boolean }
|
|
152
|
+
* @returns {String|null|Array<String>} multi 为 false 返回单个字符串,否则返回字符串数组
|
|
153
|
+
*/
|
|
154
|
+
export function toUrlValue(rows, opts) {
|
|
155
|
+
let options = opts || {};
|
|
156
|
+
/* 取值字段为空(非图片没有大中小图、旧配置没维护过)时一律退回 url */
|
|
157
|
+
let field = options.field || "url";
|
|
158
|
+
/* 入参兜底:模型值可能是字符串(单值 URL 模式),不能直接 .map */
|
|
159
|
+
let list = Array.isArray(rows) ? rows : rows ? [rows] : [];
|
|
160
|
+
let urls = list
|
|
161
|
+
.map((row) => {
|
|
162
|
+
if (!row) return null;
|
|
163
|
+
if (typeof row === "string") return row;
|
|
164
|
+
if (!isPlainObject(row)) return null;
|
|
165
|
+
return (row.domain || "") + (row[field] || row.url || "");
|
|
166
|
+
})
|
|
167
|
+
.filter((url) => !!url);
|
|
168
|
+
if (options.multi === false) {
|
|
169
|
+
return urls.length ? urls[0] : null;
|
|
170
|
+
}
|
|
171
|
+
return urls;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 附件字段是否按多值处理。沿用组件既有约定:限制数量为 1 即单值。
|
|
176
|
+
*/
|
|
177
|
+
export function isUrlValueMulti(fieldOptions) {
|
|
178
|
+
return !(fieldOptions && Number(fieldOptions.limit) === 1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 内部值(附件对象数组) → 落到表单模型的值。
|
|
183
|
+
* 未开启 urlValueEnabled 时保持附件对象数组,开启后转成 URL 字符串(单值)或字符串数组。
|
|
184
|
+
*/
|
|
185
|
+
export function toModelValue(rows, fieldOptions) {
|
|
186
|
+
if (!fieldOptions || !fieldOptions.urlValueEnabled) return rows;
|
|
187
|
+
return toUrlValue(rows, {
|
|
188
|
+
field: fieldOptions.urlValueField || "url",
|
|
189
|
+
multi: isUrlValueMulti(fieldOptions),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 两个「落到表单模型的值」是否等价。URL 模式下模型值是 String | Array<String> | null,
|
|
195
|
+
* 而 toModelValue 每次都产出新数组——不比一下就回写,会和 fieldMixin 的
|
|
196
|
+
* initValueWatchEvent(模型一变就把模型值灌回 fieldModel)形成死循环。
|
|
197
|
+
*/
|
|
198
|
+
export function isSameModelValue(a, b) {
|
|
199
|
+
if (a === b) return true;
|
|
200
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
201
|
+
if (a.length !== b.length) return false;
|
|
202
|
+
return a.every((item, index) => item === b[index]);
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 数据表的附件列是否开了「值存为URL」。列的组件 schema 挂在 widget(显示态) /
|
|
209
|
+
* editWidget(编辑态) 上,两者同属一列,任一开启即按普通列处理——它的值是 URL
|
|
210
|
+
* 字符串,存在明细表自己的列上,不走 attachmentType 独立附件通道。
|
|
211
|
+
*/
|
|
212
|
+
export function isUrlValueColumn(column) {
|
|
213
|
+
if (!column) return false;
|
|
214
|
+
let options = column.editWidget && column.editWidget.options;
|
|
215
|
+
if (!options) {
|
|
216
|
+
options = column.widget && column.widget.options;
|
|
217
|
+
}
|
|
218
|
+
return !!(options && options.urlValueEnabled);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 归一前后是否等价。用于避免在 created 里无谓地重新赋值 fieldModel——
|
|
223
|
+
* 换一个新数组会让 watcher 白触发一次 onChange。
|
|
224
|
+
*/
|
|
225
|
+
export function isSameAttachmentRows(rows, val) {
|
|
226
|
+
if (!Array.isArray(val) || rows.length !== val.length) return false;
|
|
227
|
+
return rows.every((row, index) => row === val[index]);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export default {
|
|
231
|
+
parseFileUrl,
|
|
232
|
+
normalizeAttachmentValue,
|
|
233
|
+
toUrlValue,
|
|
234
|
+
isUrlValueMulti,
|
|
235
|
+
toModelValue,
|
|
236
|
+
isSameModelValue,
|
|
237
|
+
isUrlValueColumn,
|
|
238
|
+
isSameAttachmentRows,
|
|
239
|
+
};
|
|
@@ -99,6 +99,13 @@ export function isEmptyArrayFieldValue(value, type, options = {}) {
|
|
|
99
99
|
(item) => item === null || item === undefined || item === ""
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
|
+
/* 附件字段开了「值存为URL」且限制数量为 1 时,模型里存的是单个 URL 字符串,
|
|
103
|
+
不能按空数组判空,否则必填校验永远不通过 */
|
|
104
|
+
if (isAttachmentWidgetType(type) && options.urlValueEnabled) {
|
|
105
|
+
if (typeof value === "string") {
|
|
106
|
+
return !value.trim();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
102
109
|
if (!Array.isArray(value)) {
|
|
103
110
|
return true;
|
|
104
111
|
}
|
|
@@ -851,6 +858,26 @@ export function getColumnWidgetOptions(row, isEdit = false) {
|
|
|
851
858
|
return row.widgetOptions ?? row.columnOption;
|
|
852
859
|
}
|
|
853
860
|
|
|
861
|
+
/**
|
|
862
|
+
* 复制列内 field widget,用于展示组件与编辑组件同类型、只配置了其中一方的列。
|
|
863
|
+
* 另一方若按类型新建空白 schema,只配在已有一方的 defaultValue / optionItems /
|
|
864
|
+
* searchDialogConfig 等会全部丢失(编辑表新增行取默认值同样受影响)。
|
|
865
|
+
* 字段绑定 keyName 保持不变;id 与 name 必须重新生成——refList 按
|
|
866
|
+
* options.name + 行键 注册,fieldSchemaMap 按 id 索引,两个组件同名会互相覆盖。
|
|
867
|
+
*/
|
|
868
|
+
export function cloneColumnFieldWidget(fieldWidget) {
|
|
869
|
+
if (!fieldWidget) {
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
let newWidget = deepClone(fieldWidget);
|
|
873
|
+
newWidget.id = String(newWidget.type).replace(/-/g, "") + generateId();
|
|
874
|
+
if (newWidget.hasOwnProperty("tableField")) {
|
|
875
|
+
newWidget.tableField = newWidget.id;
|
|
876
|
+
}
|
|
877
|
+
newWidget.options.name = newWidget.id;
|
|
878
|
+
return newWidget;
|
|
879
|
+
}
|
|
880
|
+
|
|
854
881
|
/** 将列级 label / keyName / required 同步到列内 field widget(动态列 label 在列顶层) */
|
|
855
882
|
export function applyColumnMetaToFieldWidget(fieldWidget, row, isEdit = false) {
|
|
856
883
|
if (!fieldWidget || !row) {
|