cloud-web-corejs 1.0.54-dev.786 → 1.0.54-dev.788
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 +2 -1
- package/src/components/VabUpload/index.vue +1 -1
- package/src/components/baseInputExport/mixins.js +13 -2
- package/src/components/code-editor/async.js +29 -0
- package/src/components/code-editor/index.vue +65 -6
- package/src/components/excelImport/index.js +69 -7
- package/src/components/excelImport/mixins.js +841 -9
- package/src/components/fileLibrary/fileHistoryDialog.vue +1 -1
- package/src/components/fileLibrary/fileObjAuthEdit.vue +1 -1
- package/src/components/fileLibrary/filterDialog.vue +1 -1
- package/src/components/formDialog/README.md +324 -241
- package/src/components/formDialog/actionButtons.js +90 -0
- package/src/components/formDialog/index.js +48 -35
- package/src/components/formDialog/index.vue +802 -724
- package/src/components/formDrawer/drawer.vue +719 -0
- package/src/components/formDrawer/index.js +50 -0
- package/src/components/onlineTalk/talkUserDialog.vue +1 -1
- package/src/components/table/index.js +4 -0
- package/src/components/tempStorage/tempStorageDialog.vue +1 -1
- package/src/components/wf/addTaskUserdialog.vue +1 -1
- package/src/components/xform/docs/2026-08 /345/210/227/350/241/250/345/257/274/345/207/272/350/204/261/346/225/217/345/210/227/345/211/224/351/231/244/350/220/275/345/234/260/346/226/207/346/241/243.md" +165 -0
- package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue +1 -1
- package/src/components/xform/form-designer/form-widget/dialog/formDialog.vue +115 -4
- package/src/components/xform/form-designer/form-widget/dialog/formDrawer.vue +102 -5
- package/src/components/xform/form-designer/form-widget/dialog/formFieldDialog.vue +1 -1
- package/src/components/xform/form-designer/form-widget/dialog/vabSearchDialog.vue +1 -1
- package/src/components/xform/form-designer/form-widget/field-widget/form-item-wrapper.vue +18 -73
- package/src/components/xform/form-designer/form-widget/field-widget/script-input-widget.vue +3 -0
- package/src/components/xform/form-designer/setting-panel/action-button-config-dialog.vue +241 -0
- package/src/components/xform/form-designer/setting-panel/form-setting.vue +116 -0
- package/src/components/xform/form-designer/setting-panel/property-editor/container-detail/detail-editor.vue +6 -0
- package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +1 -0
- package/src/components/xform/form-render/container-item/data-table-mixin.js +1480 -1460
- package/src/components/xform/form-render/container-item/detail-item.vue +11 -2
- package/src/components/xform/form-render/container-item/list-h5-item.vue +12 -0
- package/src/components/xform/form-render/indexMixin.js +5 -0
- package/src/components/xform/utils/textMaskUtil.js +186 -0
- package/src/index.js +505 -472
- package/src/store/config/index.js +224 -0
- package/src/store/modules/tagsView.js +4 -2
- package/src/utils/lazyPlugin.js +66 -0
- package/src/views/bd/project/branch/bd_branch/edit.vue +145 -0
- package/src/views/bd/project/branch/bd_branch/list.vue +72 -0
- package/src/views/bd/project/branch/bd_branch/menuKindDialog.vue +106 -0
- package/src/views/bd/project/branch/bd_branch/mixins/edit.js +189 -0
- package/src/views/bd/project/branch/bd_branch/mixins/list.js +124 -0
- package/src/views/bd/project/branch/bd_branch/mixins/menuKindDialog.js +85 -0
- package/src/views/bd/project/branch/form_script/list.vue +22 -0
- package/src/views/bd/project/branch/form_template/list.vue +21 -0
- package/src/views/bd/project/branch/menu_kind/list.vue +21 -0
- package/src/views/bd/project/common/form_script/list.vue +16 -0
- package/src/views/bd/project/common/form_template/list.vue +15 -0
- package/src/views/bd/project/common/menu_kind/list.vue +15 -0
- package/src/views/bd/project/core/branchContext.js +100 -0
- package/src/views/bd/project/core/branchPage.js +78 -0
- package/src/views/bd/project/core/branchPageWrap.vue +216 -0
- package/src/views/bd/project/core/branchScope.js +44 -0
- package/src/views/bd/project/core/branchSelect.vue +106 -0
- package/src/views/bd/project/core/httpBranchPatch.js +58 -0
- package/src/views/bd/project/datatable/menu_kind/list.vue +15 -0
- package/src/views/bd/project/datatable/table_model/list.vue +15 -0
- package/src/views/bd/setting/bd_attach_setting/dialog.vue +1 -1
- package/src/views/bd/setting/bd_attach_setting/list.vue +1 -1
- package/src/views/bd/setting/bd_company_env/dialog.vue +1 -1
- package/src/views/bd/setting/bd_company_env/list.vue +1 -1
- package/src/views/bd/setting/formVersion/ftHistoryDialog.vue +1 -1
- package/src/views/bd/setting/form_import_log/list.vue +1 -1
- package/src/views/bd/setting/form_script/dialog.vue +1 -1
- package/src/views/bd/setting/form_script/form_list.vue +1 -1
- package/src/views/bd/setting/form_script/list.vue +1 -1
- package/src/views/bd/setting/form_script/list1.vue +1 -1
- package/src/views/bd/setting/form_template/dialog.vue +1 -1
- package/src/views/bd/setting/form_template/formDesignerDialog.vue +1 -0
- package/src/views/bd/setting/form_template/ftHistoryDialog.vue +1 -1
- package/src/views/bd/setting/form_template/itemList.vue +1 -1
- package/src/views/bd/setting/form_template/list.vue +3 -3
- package/src/views/bd/setting/form_template/mixins/edit.js +3 -3
- package/src/views/bd/setting/form_template/mixins/list.js +3 -3
- package/src/views/bd/setting/form_template/mixins/list2.js +3 -3
- package/src/views/bd/setting/form_template/mixins/wf_list.js +3 -3
- package/src/views/bd/setting/form_template/wf_list.vue +3 -3
- package/src/views/bd/setting/logic_param/list.vue +1 -1
- package/src/views/bd/setting/menu_kind/dialog.vue +1 -1
- package/src/views/bd/setting/menu_kind/list.vue +1 -1
- package/src/views/bd/setting/push_data/list.vue +1 -1
- package/src/views/bd/setting/push_data_h/list.vue +1 -1
- package/src/views/bd/setting/request_async_setting/list.vue +1 -1
- package/src/views/bd/setting/request_setting/list.vue +1 -1
- package/src/views/bd/setting/table_model/dialog.vue +1 -1
- package/src/views/bd/setting/table_model/list.vue +1 -1
- package/src/views/bd/setting/table_model/zdDialog.vue +1 -1
- package/src/views/support/export_template/list.vue +1 -1
- package/src/views/user/access_log/list.vue +1 -1
- package/src/views/user/access_log/list2.vue +1 -1
- package/src/views/user/api_request/list.vue +1 -1
- package/src/views/user/area/dialog.vue +1 -1
- package/src/views/user/area/list.vue +1 -1
- package/src/views/user/bill_setting/list.vue +1 -1
- package/src/views/user/bill_setting/userDialog.vue +1 -1
- package/src/views/user/code_rules/list.vue +1 -1
- package/src/views/user/common_attribute/list.vue +1 -1
- package/src/views/user/common_script/list.vue +1 -1
- package/src/views/user/company_info/dialog.vue +1 -1
- package/src/views/user/country/dialog.vue +1 -1
- package/src/views/user/country/list.vue +1 -1
- package/src/views/user/data_type_setting/dialog.vue +1 -1
- package/src/views/user/extend_datasource/dialog.vue +1 -1
- package/src/views/user/extend_datasource/list.vue +1 -1
- package/src/views/user/fieldTranslation/list.vue +1 -1
- package/src/views/user/field_values_invisible/list.vue +1 -1
- package/src/views/user/file_type/list.vue +1 -1
- package/src/views/user/file_view_area/list.vue +1 -1
- package/src/views/user/form/form_template/dialog.vue +1 -1
- package/src/views/user/form/form_template/itemList.vue +1 -1
- package/src/views/user/form/form_template/list.vue +1 -1
- package/src/views/user/form/form_template_field/dialog.vue +1 -1
- package/src/views/user/form/form_type/dialog.vue +1 -1
- package/src/views/user/form/form_type/list.vue +1 -1
- package/src/views/user/form/report_requestaccess/dialog.vue +1 -1
- package/src/views/user/form/report_requestaccess/list.vue +1 -1
- package/src/views/user/form/vform/designer.vue +51 -22
- package/src/views/user/groups/dialog.vue +1 -1
- package/src/views/user/groups/list.vue +1 -1
- package/src/views/user/lang_tag/dialog.vue +1 -1
- package/src/views/user/lang_tag/list.vue +1 -1
- package/src/views/user/language_setting/list.vue +1 -1
- package/src/views/user/menu/list.vue +1 -1
- package/src/views/user/mobile_menu/list.vue +1 -1
- package/src/views/user/notify_message/list.vue +1 -1
- package/src/views/user/notify_template/list.vue +1 -1
- package/src/views/user/notify_template/list2.vue +1 -1
- package/src/views/user/oplog/list.vue +1 -1
- package/src/views/user/position/dialog.vue +1 -1
- package/src/views/user/position/list.vue +1 -1
- package/src/views/user/project_tag/dialog.vue +1 -1
- package/src/views/user/project_tag/list.vue +1 -1
- package/src/views/user/push_setting/list.vue +1 -1
- package/src/views/user/request_setting/list.vue +1 -1
- package/src/views/user/role/dialog.vue +1 -1
- package/src/views/user/role/list.vue +1 -1
- package/src/views/user/sale_org/dialog.vue +1 -1
- package/src/views/user/sale_org/list.vue +1 -1
- package/src/views/user/system_notice/list.vue +1 -1
- package/src/views/user/system_parameter/list.vue +1 -1
- package/src/views/user/user/dialog.vue +1 -1
- package/src/views/user/user/form_dialog.vue +1 -1
- package/src/views/user/user/form_list.vue +1 -1
- package/src/views/user/user/list.vue +2 -2
- package/src/views/user/user_log_classify/list.vue +1 -1
- package/src/views/user/wf/wfReport/index.vue +2 -2
- package/src/views/user/wf/wf_auto_submit_data/list.vue +2 -2
- package/src/views/user/wf/wf_manage/list.vue +2 -2
- package/src/views/user/wf/wf_manage/list2.vue +2 -2
- package/src/views/user/wf/wf_obj_config/dialog.vue +1 -1
- package/src/views/user/wf/wf_obj_config/list.vue +1 -1
- package/src/views/user/wf/wf_obj_config/list_form.vue +1 -1
- package/src/views/user/wf/wf_transfer_setting/list.vue +1 -1
- package/src/views/user/workbench_menu/list.vue +1 -1
|
@@ -33,30 +33,34 @@ import {
|
|
|
33
33
|
isEmptyCellValueInRow,
|
|
34
34
|
shouldSkipCellValidation,
|
|
35
35
|
} from "../../../../components/xform/utils/tableCellValidateUtil";
|
|
36
|
-
import {
|
|
37
|
-
buildDynamicSchemaRequestData,
|
|
38
|
-
getDynamicSchemaOption,
|
|
39
|
-
isActionColumnFormat,
|
|
40
|
-
isNonDataExportColumn,
|
|
41
|
-
normalizeDynamicColumns as normalizeDynamicColumnList,
|
|
42
|
-
resolveDynamicSchemaResponse,
|
|
43
|
-
} from "../../utils/dynamicSchemaUtil";
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
36
|
+
import {
|
|
37
|
+
buildDynamicSchemaRequestData,
|
|
38
|
+
getDynamicSchemaOption,
|
|
39
|
+
isActionColumnFormat,
|
|
40
|
+
isNonDataExportColumn,
|
|
41
|
+
normalizeDynamicColumns as normalizeDynamicColumnList,
|
|
42
|
+
resolveDynamicSchemaResponse,
|
|
43
|
+
} from "../../utils/dynamicSchemaUtil";
|
|
44
|
+
import {
|
|
45
|
+
buildTextMaskContext,
|
|
46
|
+
markMaskedExportColumns,
|
|
47
|
+
} from "../../utils/textMaskUtil";
|
|
48
|
+
import {
|
|
49
|
+
resolveTreeFields,
|
|
50
|
+
resolveTreeIdentityConfig,
|
|
51
|
+
resolveTreeCopyConfig,
|
|
52
|
+
resolveTreeSubmitConfig,
|
|
53
|
+
canonicalizeTreeInput,
|
|
54
|
+
isRootParent,
|
|
55
|
+
normalizeTreeKey,
|
|
56
|
+
treeKeyEquals,
|
|
57
|
+
makeTreeTempKey,
|
|
58
|
+
markTemporaryTreeKey,
|
|
59
|
+
isTemporaryTreeKey,
|
|
60
|
+
syncTreeKeyReferences,
|
|
61
|
+
sanitizeTreeRow,
|
|
62
|
+
} from "../../utils/treeTableUtil";
|
|
63
|
+
import { tableTreeMixins } from "../../../../mixins/tableTree/index.js";
|
|
60
64
|
|
|
61
65
|
let modules = {};
|
|
62
66
|
const baseRefUtil = {
|
|
@@ -163,17 +167,17 @@ modules = {
|
|
|
163
167
|
dynamicTableColumns: [],
|
|
164
168
|
dynamicColumnsPreloaded: false,
|
|
165
169
|
dynamicColumnsInitResolved: false,
|
|
166
|
-
dynamicColumnsInitSkipped: false,
|
|
167
|
-
resolvedTreeConfig: null,
|
|
168
|
-
resolvedTreeIdentityConfig: null,
|
|
169
|
-
resolvedTreeCopyConfig: null,
|
|
170
|
-
resolvedTreeSubmitConfig: null,
|
|
171
|
-
treeTemporaryKeyRegistry: new Set(),
|
|
172
|
-
treeKnownFormalKeyRegistry: new Set(),
|
|
173
|
-
treeSingleSavePending: false,
|
|
174
|
-
treeSingleSaveReconcileTask: null,
|
|
175
|
-
// 列/网格未就绪时 setValue 只缓存数据,置此标志延后行 schema 构建
|
|
176
|
-
pendingSchemaInit: false,
|
|
170
|
+
dynamicColumnsInitSkipped: false,
|
|
171
|
+
resolvedTreeConfig: null,
|
|
172
|
+
resolvedTreeIdentityConfig: null,
|
|
173
|
+
resolvedTreeCopyConfig: null,
|
|
174
|
+
resolvedTreeSubmitConfig: null,
|
|
175
|
+
treeTemporaryKeyRegistry: new Set(),
|
|
176
|
+
treeKnownFormalKeyRegistry: new Set(),
|
|
177
|
+
treeSingleSavePending: false,
|
|
178
|
+
treeSingleSaveReconcileTask: null,
|
|
179
|
+
// 列/网格未就绪时 setValue 只缓存数据,置此标志延后行 schema 构建
|
|
180
|
+
pendingSchemaInit: false,
|
|
177
181
|
};
|
|
178
182
|
},
|
|
179
183
|
watch: {
|
|
@@ -243,6 +247,11 @@ modules = {
|
|
|
243
247
|
this.bootstrapDynamicColumnsBeforeInit().then(() => {
|
|
244
248
|
this.initColumnWidgetConfig(() => {
|
|
245
249
|
this.initTableList();
|
|
250
|
+
// 让不走 $excelExport 的旁路(vxe 工具栏自带导出)也受控:此刻用户上下文
|
|
251
|
+
// 多半尚未就绪,按 fail-closed 先剔除,之后每次 exportData 会自愈修正
|
|
252
|
+
this.$nextTick(() => {
|
|
253
|
+
this.markMaskedColumnsForExport();
|
|
254
|
+
});
|
|
246
255
|
});
|
|
247
256
|
});
|
|
248
257
|
},
|
|
@@ -631,22 +640,22 @@ modules = {
|
|
|
631
640
|
this.initRowIdData(true);
|
|
632
641
|
this.initFieldSchemaData();
|
|
633
642
|
},
|
|
634
|
-
/** @param {Array} val 外部传入数据。@returns {Array} 表单与 VXE 共用的标准化行。 */
|
|
635
|
-
initValue(val) {
|
|
636
|
-
// this.clearRowWidgets()
|
|
637
|
-
if (this.widget.options.isTreeTable) {
|
|
638
|
-
this.treeTemporaryKeyRegistry.clear();
|
|
639
|
-
this.treeKnownFormalKeyRegistry.clear();
|
|
640
|
-
}
|
|
641
|
-
let rows = this.canonicalizeTreeRows(val || []);
|
|
642
|
-
rows = this.normalizeTableRows(rows, false);
|
|
643
|
-
// this.handleNullValue(rows);
|
|
644
|
-
rows.forEach((row) => {
|
|
645
|
-
row._X_ROW_KEY = "row_" + generateId();
|
|
646
|
-
});
|
|
647
|
-
this.registerTreeKeys(rows);
|
|
648
|
-
this.formModel[this.fieldKeyName] = rows;
|
|
649
|
-
this.fieldModel = rows;
|
|
643
|
+
/** @param {Array} val 外部传入数据。@returns {Array} 表单与 VXE 共用的标准化行。 */
|
|
644
|
+
initValue(val) {
|
|
645
|
+
// this.clearRowWidgets()
|
|
646
|
+
if (this.widget.options.isTreeTable) {
|
|
647
|
+
this.treeTemporaryKeyRegistry.clear();
|
|
648
|
+
this.treeKnownFormalKeyRegistry.clear();
|
|
649
|
+
}
|
|
650
|
+
let rows = this.canonicalizeTreeRows(val || []);
|
|
651
|
+
rows = this.normalizeTableRows(rows, false);
|
|
652
|
+
// this.handleNullValue(rows);
|
|
653
|
+
rows.forEach((row) => {
|
|
654
|
+
row._X_ROW_KEY = "row_" + generateId();
|
|
655
|
+
});
|
|
656
|
+
this.registerTreeKeys(rows);
|
|
657
|
+
this.formModel[this.fieldKeyName] = rows;
|
|
658
|
+
this.fieldModel = rows;
|
|
650
659
|
this.initRowIdData(true);
|
|
651
660
|
this.initFieldSchemaData(true);
|
|
652
661
|
return rows;
|
|
@@ -656,38 +665,38 @@ modules = {
|
|
|
656
665
|
* @param {Array} rows 原始行数据。
|
|
657
666
|
* @returns {Array|undefined} 根节点优先、子节点紧随父节点的扁平数组。
|
|
658
667
|
*/
|
|
659
|
-
handleTreeData(rows) {
|
|
660
|
-
let isTreeTable = this.widget.options.isTreeTable;
|
|
661
|
-
if (isTreeTable) {
|
|
662
|
-
let $grid = this.getGridTable();
|
|
663
|
-
rows = this.canonicalizeTreeRows(rows || [], $grid);
|
|
664
|
-
let { rowField, parentField } = this.getTreeFields($grid);
|
|
665
|
-
if (parentField) {
|
|
668
|
+
handleTreeData(rows) {
|
|
669
|
+
let isTreeTable = this.widget.options.isTreeTable;
|
|
670
|
+
if (isTreeTable) {
|
|
671
|
+
let $grid = this.getGridTable();
|
|
672
|
+
rows = this.canonicalizeTreeRows(rows || [], $grid);
|
|
673
|
+
let { rowField, parentField } = this.getTreeFields($grid);
|
|
674
|
+
if (parentField) {
|
|
666
675
|
// 构建树结构并排序
|
|
667
676
|
let sortedRows = [];
|
|
668
677
|
let nodeMap = new Map();
|
|
669
678
|
|
|
670
|
-
// 第一步:构建节点映射
|
|
671
|
-
rows.forEach((row) => {
|
|
672
|
-
if (row[rowField] !== undefined && row[rowField] !== null) {
|
|
673
|
-
nodeMap.set(row[rowField], row);
|
|
674
|
-
}
|
|
675
|
-
});
|
|
679
|
+
// 第一步:构建节点映射
|
|
680
|
+
rows.forEach((row) => {
|
|
681
|
+
if (row[rowField] !== undefined && row[rowField] !== null) {
|
|
682
|
+
nodeMap.set(row[rowField], row);
|
|
683
|
+
}
|
|
684
|
+
});
|
|
676
685
|
|
|
677
686
|
// 第二步:按层次排序,先根节点,然后子节点
|
|
678
687
|
rows.forEach((row) => {
|
|
679
|
-
let parentValue = row[parentField];
|
|
680
|
-
// 根节点读取口径统一由树工具维护。
|
|
681
|
-
if (isRootParent(parentValue)) {
|
|
682
|
-
sortedRows.push(row);
|
|
683
|
-
// 递归添加子节点
|
|
684
|
-
this.addChildNodes(
|
|
685
|
-
row[rowField],
|
|
686
|
-
nodeMap,
|
|
687
|
-
parentField,
|
|
688
|
-
sortedRows
|
|
689
|
-
);
|
|
690
|
-
}
|
|
688
|
+
let parentValue = row[parentField];
|
|
689
|
+
// 根节点读取口径统一由树工具维护。
|
|
690
|
+
if (isRootParent(parentValue)) {
|
|
691
|
+
sortedRows.push(row);
|
|
692
|
+
// 递归添加子节点
|
|
693
|
+
this.addChildNodes(
|
|
694
|
+
row[rowField],
|
|
695
|
+
nodeMap,
|
|
696
|
+
parentField,
|
|
697
|
+
sortedRows
|
|
698
|
+
);
|
|
699
|
+
}
|
|
691
700
|
});
|
|
692
701
|
|
|
693
702
|
// 如果没有找到根节点,返回原始数组
|
|
@@ -712,12 +721,12 @@ modules = {
|
|
|
712
721
|
return rows;
|
|
713
722
|
},
|
|
714
723
|
/** @param {*} parentId 父节点 id。@param {Map} nodeMap 节点映射。@param {String} parentField 父字段。@param {Array} sortedRows 输出数组。 */
|
|
715
|
-
addChildNodes(parentId, nodeMap, parentField, sortedRows) {
|
|
716
|
-
// 遍历所有节点,找出当前父节点的子节点
|
|
717
|
-
for (let [id, node] of nodeMap.entries()) {
|
|
718
|
-
let nodeParentValue = node[parentField];
|
|
719
|
-
if (treeKeyEquals(nodeParentValue, parentId)) {
|
|
720
|
-
sortedRows.push(node);
|
|
724
|
+
addChildNodes(parentId, nodeMap, parentField, sortedRows) {
|
|
725
|
+
// 遍历所有节点,找出当前父节点的子节点
|
|
726
|
+
for (let [id, node] of nodeMap.entries()) {
|
|
727
|
+
let nodeParentValue = node[parentField];
|
|
728
|
+
if (treeKeyEquals(nodeParentValue, parentId)) {
|
|
729
|
+
sortedRows.push(node);
|
|
721
730
|
// 递归添加子节点的子节点
|
|
722
731
|
this.addChildNodes(id, nodeMap, parentField, sortedRows);
|
|
723
732
|
}
|
|
@@ -729,7 +738,7 @@ modules = {
|
|
|
729
738
|
* @param {Boolean} defaultValueEnabled 是否应用字段默认值。
|
|
730
739
|
* @returns {Array} 标准化后的新数组。
|
|
731
740
|
*/
|
|
732
|
-
normalizeTableRows(rows, defaultValueEnabled = false) {
|
|
741
|
+
normalizeTableRows(rows, defaultValueEnabled = false) {
|
|
733
742
|
if (!Array.isArray(rows) || !rows.length) {
|
|
734
743
|
return rows || [];
|
|
735
744
|
}
|
|
@@ -745,44 +754,44 @@ modules = {
|
|
|
745
754
|
nextRow._X_ROW_KEY = "row_" + generateId();
|
|
746
755
|
}
|
|
747
756
|
return nextRow;
|
|
748
|
-
});
|
|
749
|
-
},
|
|
750
|
-
/**
|
|
751
|
-
* 树数据进入 VXE 前统一转换为唯一平铺模型;非树表保持原样。
|
|
752
|
-
* @param {Array} rows 原始平铺或嵌套数据。
|
|
753
|
-
* @param {Object} $grid 可选的 VXE Grid。
|
|
754
|
-
* @returns {Array} 规范化后的行数组。
|
|
755
|
-
*/
|
|
756
|
-
canonicalizeTreeRows(rows, $grid) {
|
|
757
|
-
if (!this.widget.options.isTreeTable) {
|
|
758
|
-
return rows || [];
|
|
759
|
-
}
|
|
760
|
-
let treeConfig = this.resolvedTreeConfig
|
|
761
|
-
|| $grid?.treeConfig
|
|
762
|
-
|| $grid?.params?.originOption?.config?.treeConfig;
|
|
763
|
-
if (!treeConfig) {
|
|
764
|
-
return rows || [];
|
|
765
|
-
}
|
|
766
|
-
let context = this.getTreeContext($grid);
|
|
767
|
-
let nextRows = canonicalizeTreeInput(rows || [], context);
|
|
768
|
-
this.registerTreeKeys(nextRows, context);
|
|
769
|
-
return nextRows;
|
|
770
|
-
},
|
|
757
|
+
});
|
|
758
|
+
},
|
|
759
|
+
/**
|
|
760
|
+
* 树数据进入 VXE 前统一转换为唯一平铺模型;非树表保持原样。
|
|
761
|
+
* @param {Array} rows 原始平铺或嵌套数据。
|
|
762
|
+
* @param {Object} $grid 可选的 VXE Grid。
|
|
763
|
+
* @returns {Array} 规范化后的行数组。
|
|
764
|
+
*/
|
|
765
|
+
canonicalizeTreeRows(rows, $grid) {
|
|
766
|
+
if (!this.widget.options.isTreeTable) {
|
|
767
|
+
return rows || [];
|
|
768
|
+
}
|
|
769
|
+
let treeConfig = this.resolvedTreeConfig
|
|
770
|
+
|| $grid?.treeConfig
|
|
771
|
+
|| $grid?.params?.originOption?.config?.treeConfig;
|
|
772
|
+
if (!treeConfig) {
|
|
773
|
+
return rows || [];
|
|
774
|
+
}
|
|
775
|
+
let context = this.getTreeContext($grid);
|
|
776
|
+
let nextRows = canonicalizeTreeInput(rows || [], context);
|
|
777
|
+
this.registerTreeKeys(nextRows, context);
|
|
778
|
+
return nextRows;
|
|
779
|
+
},
|
|
771
780
|
/**
|
|
772
781
|
* 全量替换表格数据并重建行级 schema。
|
|
773
|
-
* 注意:该操作会触发 vxe-grid 重载;编辑表仅在服务端正式身份回填后使用。
|
|
782
|
+
* 注意:该操作会触发 vxe-grid 重载;编辑表仅在服务端正式身份回填后使用。
|
|
774
783
|
* @param {Array} val 新的完整数据集。
|
|
775
784
|
*/
|
|
776
|
-
setValue(val) {
|
|
777
|
-
// console.log("rows:",val);
|
|
778
|
-
this.clearRowWidgets();
|
|
779
|
-
if (this.widget.options.isTreeTable) {
|
|
780
|
-
this.treeTemporaryKeyRegistry.clear();
|
|
781
|
-
this.treeKnownFormalKeyRegistry.clear();
|
|
782
|
-
}
|
|
783
|
-
let rows = this.canonicalizeTreeRows(val || []);
|
|
784
|
-
rows = this.normalizeTableRows(rows, false);
|
|
785
|
-
this.registerTreeKeys(rows);
|
|
785
|
+
setValue(val) {
|
|
786
|
+
// console.log("rows:",val);
|
|
787
|
+
this.clearRowWidgets();
|
|
788
|
+
if (this.widget.options.isTreeTable) {
|
|
789
|
+
this.treeTemporaryKeyRegistry.clear();
|
|
790
|
+
this.treeKnownFormalKeyRegistry.clear();
|
|
791
|
+
}
|
|
792
|
+
let rows = this.canonicalizeTreeRows(val || []);
|
|
793
|
+
rows = this.normalizeTableRows(rows, false);
|
|
794
|
+
this.registerTreeKeys(rows);
|
|
786
795
|
this.formModel[this.fieldKeyName] = rows;
|
|
787
796
|
let $grid = this.getGridTable();
|
|
788
797
|
this.fieldModel = rows;
|
|
@@ -1563,7 +1572,7 @@ modules = {
|
|
|
1563
1572
|
}
|
|
1564
1573
|
this.searchEvent();
|
|
1565
1574
|
},
|
|
1566
|
-
/**
|
|
1575
|
+
/** 查询区“刷新”按钮入口。 */
|
|
1567
1576
|
handleResetClick() {
|
|
1568
1577
|
if (this.widget.options.onResetTable) {
|
|
1569
1578
|
this.handleCustomEvent(this.widget.options.onResetTable);
|
|
@@ -2140,11 +2149,11 @@ modules = {
|
|
|
2140
2149
|
lazy: false,
|
|
2141
2150
|
// 树表主键列显式声明为唯一事实源:vxe transform 建树(toArrayTree)
|
|
2142
2151
|
// 以 rowField 为 key,父子关联代码一律经 getTreeFields 取列名,
|
|
2143
|
-
// 不允许在别处写死 id,否则配置变化时两条链分叉、层级错乱。
|
|
2144
|
-
rowField: "id",
|
|
2145
|
-
children: "f_children",
|
|
2146
|
-
mapChildren: "_X_ROW_CHILD",
|
|
2147
|
-
hasChild: "f_has_child", // 设置是否有子节点标识
|
|
2152
|
+
// 不允许在别处写死 id,否则配置变化时两条链分叉、层级错乱。
|
|
2153
|
+
rowField: "id",
|
|
2154
|
+
children: "f_children",
|
|
2155
|
+
mapChildren: "_X_ROW_CHILD",
|
|
2156
|
+
hasChild: "f_has_child", // 设置是否有子节点标识
|
|
2148
2157
|
parentField: "f_parent",
|
|
2149
2158
|
transform: true,
|
|
2150
2159
|
expandAll: true,
|
|
@@ -2153,18 +2162,18 @@ modules = {
|
|
|
2153
2162
|
// 恢复展开状态(克隆保留该键),查询重载会重新生成键,互不干扰。
|
|
2154
2163
|
reserve: true,
|
|
2155
2164
|
loadMethod: ({ $table, row }) => {
|
|
2156
|
-
// 模拟后台接口
|
|
2157
|
-
let $grid = that.getGridTable();
|
|
2158
|
-
let { rowField, parentField } = that.getTreeFields($grid);
|
|
2165
|
+
// 模拟后台接口
|
|
2166
|
+
let $grid = that.getGridTable();
|
|
2167
|
+
let { rowField, parentField } = that.getTreeFields($grid);
|
|
2159
2168
|
return new Promise((resolve, reject) => {
|
|
2160
2169
|
let treeParam = tableConfig?.treeNodeParam;
|
|
2161
2170
|
let reqPram = {};
|
|
2162
2171
|
if (treeParam) {
|
|
2163
2172
|
reqPram = treeParam(row) || {};
|
|
2164
|
-
}
|
|
2165
|
-
Object.assign(reqPram, {
|
|
2166
|
-
[parentField]: row[rowField],
|
|
2167
|
-
});
|
|
2173
|
+
}
|
|
2174
|
+
Object.assign(reqPram, {
|
|
2175
|
+
[parentField]: row[rowField],
|
|
2176
|
+
});
|
|
2168
2177
|
let accessParam = that.getAccessParam() || {};
|
|
2169
2178
|
let defaultOption = that.getHttpConfigForUser();
|
|
2170
2179
|
that.formHttp({
|
|
@@ -2178,112 +2187,112 @@ modules = {
|
|
|
2178
2187
|
...otherParam,
|
|
2179
2188
|
...accessParam,
|
|
2180
2189
|
},
|
|
2181
|
-
},
|
|
2182
|
-
callback: (res) => {
|
|
2183
|
-
if (res.type === "success") {
|
|
2184
|
-
let rows;
|
|
2185
|
-
try {
|
|
2186
|
-
let treeContext = that.getTreeContext($grid);
|
|
2187
|
-
rows = canonicalizeTreeInput(
|
|
2188
|
-
res.objx?.records || res.objx || [],
|
|
2189
|
-
treeContext
|
|
2190
|
-
);
|
|
2191
|
-
rows.forEach((childRow) => {
|
|
2192
|
-
let parentValue = childRow[parentField];
|
|
2193
|
-
if (isRootParent(parentValue)) {
|
|
2194
|
-
childRow[parentField] = row[rowField];
|
|
2195
|
-
return;
|
|
2196
|
-
}
|
|
2197
|
-
if (treeKeyEquals(parentValue, row[rowField])) {
|
|
2198
|
-
childRow[parentField] = row[rowField];
|
|
2199
|
-
return;
|
|
2200
|
-
}
|
|
2201
|
-
let batchParent = rows.find((item) =>
|
|
2202
|
-
treeKeyEquals(item[rowField], parentValue)
|
|
2203
|
-
);
|
|
2204
|
-
if (!batchParent) {
|
|
2205
|
-
throw new Error(
|
|
2206
|
-
`懒加载节点 ${childRow[rowField]} 的父键 ${parentValue} 与请求父节点不一致`
|
|
2207
|
-
);
|
|
2208
|
-
}
|
|
2209
|
-
childRow[parentField] = batchParent[rowField];
|
|
2210
|
-
});
|
|
2211
|
-
|
|
2212
|
-
let currentRows
|
|
2213
|
-
= that.formModel[that.fieldKeyName] || [];
|
|
2214
|
-
let currentCanonical = canonicalizeTreeInput(
|
|
2215
|
-
currentRows,
|
|
2216
|
-
treeContext
|
|
2217
|
-
);
|
|
2218
|
-
rows.forEach((childRow) => {
|
|
2219
|
-
if (
|
|
2220
|
-
currentCanonical.some((item) =>
|
|
2221
|
-
treeKeyEquals(
|
|
2222
|
-
item[rowField],
|
|
2223
|
-
childRow[rowField]
|
|
2224
|
-
)
|
|
2225
|
-
)
|
|
2226
|
-
) {
|
|
2227
|
-
throw new Error(
|
|
2228
|
-
`懒加载节点 ${childRow[rowField]} 已存在`
|
|
2229
|
-
);
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2232
|
-
let candidateRows = canonicalizeTreeInput(
|
|
2233
|
-
currentRows.concat(rows),
|
|
2234
|
-
treeContext
|
|
2235
|
-
);
|
|
2236
|
-
let newRowKeys = new Set(
|
|
2237
|
-
rows.map((item) =>
|
|
2238
|
-
normalizeTreeKey(item[rowField])
|
|
2239
|
-
)
|
|
2240
|
-
);
|
|
2241
|
-
// canonicalizeTreeInput 已深克隆并移除 children /
|
|
2242
|
-
// mapChildren。formModel 只保存这份扁平快照,不能重新
|
|
2243
|
-
// 填回 VXE 的活动行对象,否则其内部树容器会泄漏到提交数据。
|
|
2244
|
-
let canonicalRows = candidateRows;
|
|
2245
|
-
rows = canonicalRows.filter((item) =>
|
|
2246
|
-
newRowKeys.has(normalizeTreeKey(item[rowField]))
|
|
2247
|
-
);
|
|
2248
|
-
that.initExportFieldSchemaData(rows);
|
|
2249
|
-
that.formModel[that.fieldKeyName] = canonicalRows;
|
|
2250
|
-
that.registerTreeKeys(rows, treeContext);
|
|
2251
|
-
} catch (error) {
|
|
2252
|
-
reject(error);
|
|
2253
|
-
return;
|
|
2254
|
-
}
|
|
2255
|
-
|
|
2256
|
-
if (res.objx?.records !== undefined) {
|
|
2257
|
-
res.objx.records = rows;
|
|
2258
|
-
} else {
|
|
2259
|
-
res.objx = rows;
|
|
2260
|
-
}
|
|
2261
|
-
|
|
2262
|
-
let hasChildField = $grid.treeConfig.hasChild;
|
|
2263
|
-
if (row[hasChildField] && !rows.length) {
|
|
2264
|
-
row[hasChildField] = false;
|
|
2265
|
-
}
|
|
2266
|
-
|
|
2267
|
-
resolve(rows);
|
|
2268
|
-
/* let treeCallback = tableConfig?.treeCallback;
|
|
2269
|
-
if (treeCallback) {
|
|
2270
|
-
that.$nextTick(() => {
|
|
2271
|
-
setTimeout(function () {
|
|
2272
|
-
treeCallback(rows);
|
|
2273
|
-
}, 0);
|
|
2274
|
-
});
|
|
2275
|
-
} */
|
|
2276
|
-
that.$nextTick(() => {
|
|
2277
|
-
setTimeout(function () {
|
|
2278
|
-
dataTableConfig.callback &&
|
|
2279
|
-
dataTableConfig.callback(rows);
|
|
2280
|
-
tableConfig.treeCallback &&
|
|
2281
|
-
tableConfig.treeCallback(rows);
|
|
2282
|
-
}, 0);
|
|
2283
|
-
});
|
|
2284
|
-
} else {
|
|
2285
|
-
reject(res);
|
|
2286
|
-
}
|
|
2190
|
+
},
|
|
2191
|
+
callback: (res) => {
|
|
2192
|
+
if (res.type === "success") {
|
|
2193
|
+
let rows;
|
|
2194
|
+
try {
|
|
2195
|
+
let treeContext = that.getTreeContext($grid);
|
|
2196
|
+
rows = canonicalizeTreeInput(
|
|
2197
|
+
res.objx?.records || res.objx || [],
|
|
2198
|
+
treeContext
|
|
2199
|
+
);
|
|
2200
|
+
rows.forEach((childRow) => {
|
|
2201
|
+
let parentValue = childRow[parentField];
|
|
2202
|
+
if (isRootParent(parentValue)) {
|
|
2203
|
+
childRow[parentField] = row[rowField];
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
if (treeKeyEquals(parentValue, row[rowField])) {
|
|
2207
|
+
childRow[parentField] = row[rowField];
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2210
|
+
let batchParent = rows.find((item) =>
|
|
2211
|
+
treeKeyEquals(item[rowField], parentValue)
|
|
2212
|
+
);
|
|
2213
|
+
if (!batchParent) {
|
|
2214
|
+
throw new Error(
|
|
2215
|
+
`懒加载节点 ${childRow[rowField]} 的父键 ${parentValue} 与请求父节点不一致`
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
childRow[parentField] = batchParent[rowField];
|
|
2219
|
+
});
|
|
2220
|
+
|
|
2221
|
+
let currentRows
|
|
2222
|
+
= that.formModel[that.fieldKeyName] || [];
|
|
2223
|
+
let currentCanonical = canonicalizeTreeInput(
|
|
2224
|
+
currentRows,
|
|
2225
|
+
treeContext
|
|
2226
|
+
);
|
|
2227
|
+
rows.forEach((childRow) => {
|
|
2228
|
+
if (
|
|
2229
|
+
currentCanonical.some((item) =>
|
|
2230
|
+
treeKeyEquals(
|
|
2231
|
+
item[rowField],
|
|
2232
|
+
childRow[rowField]
|
|
2233
|
+
)
|
|
2234
|
+
)
|
|
2235
|
+
) {
|
|
2236
|
+
throw new Error(
|
|
2237
|
+
`懒加载节点 ${childRow[rowField]} 已存在`
|
|
2238
|
+
);
|
|
2239
|
+
}
|
|
2240
|
+
});
|
|
2241
|
+
let candidateRows = canonicalizeTreeInput(
|
|
2242
|
+
currentRows.concat(rows),
|
|
2243
|
+
treeContext
|
|
2244
|
+
);
|
|
2245
|
+
let newRowKeys = new Set(
|
|
2246
|
+
rows.map((item) =>
|
|
2247
|
+
normalizeTreeKey(item[rowField])
|
|
2248
|
+
)
|
|
2249
|
+
);
|
|
2250
|
+
// canonicalizeTreeInput 已深克隆并移除 children /
|
|
2251
|
+
// mapChildren。formModel 只保存这份扁平快照,不能重新
|
|
2252
|
+
// 填回 VXE 的活动行对象,否则其内部树容器会泄漏到提交数据。
|
|
2253
|
+
let canonicalRows = candidateRows;
|
|
2254
|
+
rows = canonicalRows.filter((item) =>
|
|
2255
|
+
newRowKeys.has(normalizeTreeKey(item[rowField]))
|
|
2256
|
+
);
|
|
2257
|
+
that.initExportFieldSchemaData(rows);
|
|
2258
|
+
that.formModel[that.fieldKeyName] = canonicalRows;
|
|
2259
|
+
that.registerTreeKeys(rows, treeContext);
|
|
2260
|
+
} catch (error) {
|
|
2261
|
+
reject(error);
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
if (res.objx?.records !== undefined) {
|
|
2266
|
+
res.objx.records = rows;
|
|
2267
|
+
} else {
|
|
2268
|
+
res.objx = rows;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
let hasChildField = $grid.treeConfig.hasChild;
|
|
2272
|
+
if (row[hasChildField] && !rows.length) {
|
|
2273
|
+
row[hasChildField] = false;
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
resolve(rows);
|
|
2277
|
+
/* let treeCallback = tableConfig?.treeCallback;
|
|
2278
|
+
if (treeCallback) {
|
|
2279
|
+
that.$nextTick(() => {
|
|
2280
|
+
setTimeout(function () {
|
|
2281
|
+
treeCallback(rows);
|
|
2282
|
+
}, 0);
|
|
2283
|
+
});
|
|
2284
|
+
} */
|
|
2285
|
+
that.$nextTick(() => {
|
|
2286
|
+
setTimeout(function () {
|
|
2287
|
+
dataTableConfig.callback &&
|
|
2288
|
+
dataTableConfig.callback(rows);
|
|
2289
|
+
tableConfig.treeCallback &&
|
|
2290
|
+
tableConfig.treeCallback(rows);
|
|
2291
|
+
}, 0);
|
|
2292
|
+
});
|
|
2293
|
+
} else {
|
|
2294
|
+
reject(res);
|
|
2295
|
+
}
|
|
2287
2296
|
},
|
|
2288
2297
|
});
|
|
2289
2298
|
});
|
|
@@ -2291,13 +2300,13 @@ modules = {
|
|
|
2291
2300
|
};
|
|
2292
2301
|
// 懒加载子节点的请求参数:父键/主键列名取自 treeConfig。
|
|
2293
2302
|
// (此前误读 widget.options.parentField——该选项不存在,恒为 undefined,
|
|
2294
|
-
// 会生成 {undefined: id} 的脏参数)
|
|
2295
|
-
treeNodeParam = (row) => {
|
|
2296
|
-
let fields = this.getTreeFields();
|
|
2297
|
-
return {
|
|
2298
|
-
[fields.parentField]: row[fields.rowField],
|
|
2299
|
-
};
|
|
2300
|
-
};
|
|
2303
|
+
// 会生成 {undefined: id} 的脏参数)
|
|
2304
|
+
treeNodeParam = (row) => {
|
|
2305
|
+
let fields = this.getTreeFields();
|
|
2306
|
+
return {
|
|
2307
|
+
[fields.parentField]: row[fields.rowField],
|
|
2308
|
+
};
|
|
2309
|
+
};
|
|
2301
2310
|
}
|
|
2302
2311
|
let editOpts = {};
|
|
2303
2312
|
if (this.widget.options.isEditTable) {
|
|
@@ -2455,25 +2464,25 @@ modules = {
|
|
|
2455
2464
|
// parentField/children 一并丢掉,使树主键链与建树逻辑分叉。
|
|
2456
2465
|
// 不直接改 dataTableConfig——它是宿主经 $attrs 传入的对象。
|
|
2457
2466
|
let hostTableConfig = dataTableConfig.config || {};
|
|
2458
|
-
if (treeConfig && hostTableConfig.treeConfig) {
|
|
2459
|
-
hostTableConfig = {
|
|
2460
|
-
...hostTableConfig,
|
|
2461
|
-
treeConfig: { ...treeConfig, ...hostTableConfig.treeConfig },
|
|
2462
|
-
};
|
|
2463
|
-
}
|
|
2464
|
-
let hostTreeIdentityConfig = {
|
|
2465
|
-
...(dataTableConfig.otherConfig?.treeIdentityConfig || {}),
|
|
2466
|
-
...(dataTableConfig.treeIdentityConfig || {}),
|
|
2467
|
-
};
|
|
2468
|
-
let hostTreeCopyConfig = {
|
|
2469
|
-
...(dataTableConfig.otherConfig?.treeCopyConfig || {}),
|
|
2470
|
-
...(dataTableConfig.treeCopyConfig || {}),
|
|
2471
|
-
};
|
|
2472
|
-
let hostTreeSubmitConfig = {
|
|
2473
|
-
...(dataTableConfig.otherConfig?.treeSubmitConfig || {}),
|
|
2474
|
-
...(dataTableConfig.treeSubmitConfig || {}),
|
|
2475
|
-
};
|
|
2476
|
-
tableOption = {
|
|
2467
|
+
if (treeConfig && hostTableConfig.treeConfig) {
|
|
2468
|
+
hostTableConfig = {
|
|
2469
|
+
...hostTableConfig,
|
|
2470
|
+
treeConfig: { ...treeConfig, ...hostTableConfig.treeConfig },
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
let hostTreeIdentityConfig = {
|
|
2474
|
+
...(dataTableConfig.otherConfig?.treeIdentityConfig || {}),
|
|
2475
|
+
...(dataTableConfig.treeIdentityConfig || {}),
|
|
2476
|
+
};
|
|
2477
|
+
let hostTreeCopyConfig = {
|
|
2478
|
+
...(dataTableConfig.otherConfig?.treeCopyConfig || {}),
|
|
2479
|
+
...(dataTableConfig.treeCopyConfig || {}),
|
|
2480
|
+
};
|
|
2481
|
+
let hostTreeSubmitConfig = {
|
|
2482
|
+
...(dataTableConfig.otherConfig?.treeSubmitConfig || {}),
|
|
2483
|
+
...(dataTableConfig.treeSubmitConfig || {}),
|
|
2484
|
+
};
|
|
2485
|
+
tableOption = {
|
|
2477
2486
|
// vue: this,
|
|
2478
2487
|
tableRef: tableRef,
|
|
2479
2488
|
tableName: this.getGridTableName(),
|
|
@@ -2484,18 +2493,18 @@ modules = {
|
|
|
2484
2493
|
isQueryAllPage,
|
|
2485
2494
|
exportItemConfig,
|
|
2486
2495
|
vform: true,
|
|
2487
|
-
...(this.getDynamicColumnSourceType() !== "none"
|
|
2488
|
-
? { visibleSync: false }
|
|
2489
|
-
: {}),
|
|
2490
|
-
...(dataTableConfig.otherConfig || {}),
|
|
2491
|
-
...(isTreeTable
|
|
2492
|
-
? {
|
|
2493
|
-
treeIdentityConfig: hostTreeIdentityConfig,
|
|
2494
|
-
treeCopyConfig: hostTreeCopyConfig,
|
|
2495
|
-
treeSubmitConfig: hostTreeSubmitConfig,
|
|
2496
|
-
}
|
|
2497
|
-
: {}),
|
|
2498
|
-
config: {
|
|
2496
|
+
...(this.getDynamicColumnSourceType() !== "none"
|
|
2497
|
+
? { visibleSync: false }
|
|
2498
|
+
: {}),
|
|
2499
|
+
...(dataTableConfig.otherConfig || {}),
|
|
2500
|
+
...(isTreeTable
|
|
2501
|
+
? {
|
|
2502
|
+
treeIdentityConfig: hostTreeIdentityConfig,
|
|
2503
|
+
treeCopyConfig: hostTreeCopyConfig,
|
|
2504
|
+
treeSubmitConfig: hostTreeSubmitConfig,
|
|
2505
|
+
}
|
|
2506
|
+
: {}),
|
|
2507
|
+
config: {
|
|
2499
2508
|
height: height,
|
|
2500
2509
|
showFooter,
|
|
2501
2510
|
pagerConfig,
|
|
@@ -2649,26 +2658,26 @@ modules = {
|
|
|
2649
2658
|
if (res.type === "success") {
|
|
2650
2659
|
if (that.widget.options.isTreeTable) {
|
|
2651
2660
|
if (rows.length > 0) {
|
|
2652
|
-
let fullAllDataRowMap =
|
|
2653
|
-
$grid.$refs.xTable.fullAllDataRowMap;
|
|
2654
|
-
let treeFields = that.getTreeFields($grid);
|
|
2655
|
-
let rowField = treeFields.rowField;
|
|
2656
|
-
let parentField = treeFields.parentField;
|
|
2661
|
+
let fullAllDataRowMap =
|
|
2662
|
+
$grid.$refs.xTable.fullAllDataRowMap;
|
|
2663
|
+
let treeFields = that.getTreeFields($grid);
|
|
2664
|
+
let rowField = treeFields.rowField;
|
|
2665
|
+
let parentField = treeFields.parentField;
|
|
2657
2666
|
let expandAll = $grid.treeConfig.expandAll || false;
|
|
2658
|
-
let isLazy = $grid.treeConfig.lazy;
|
|
2659
|
-
let expandIds = rows
|
|
2660
|
-
.filter(
|
|
2661
|
-
(item) =>
|
|
2662
|
-
!isRootParent(item[parentField])
|
|
2663
|
-
)
|
|
2664
|
-
.map((item) => item[parentField]);
|
|
2665
|
-
let expandRows = expandIds.length
|
|
2666
|
-
? rows.filter((item) =>
|
|
2667
|
-
expandIds.some((id) =>
|
|
2668
|
-
treeKeyEquals(id, item[rowField])
|
|
2669
|
-
)
|
|
2670
|
-
)
|
|
2671
|
-
: [];
|
|
2667
|
+
let isLazy = $grid.treeConfig.lazy;
|
|
2668
|
+
let expandIds = rows
|
|
2669
|
+
.filter(
|
|
2670
|
+
(item) =>
|
|
2671
|
+
!isRootParent(item[parentField])
|
|
2672
|
+
)
|
|
2673
|
+
.map((item) => item[parentField]);
|
|
2674
|
+
let expandRows = expandIds.length
|
|
2675
|
+
? rows.filter((item) =>
|
|
2676
|
+
expandIds.some((id) =>
|
|
2677
|
+
treeKeyEquals(id, item[rowField])
|
|
2678
|
+
)
|
|
2679
|
+
)
|
|
2680
|
+
: [];
|
|
2672
2681
|
if (expandAll && expandRows.length) {
|
|
2673
2682
|
that.$nextTick(() => {
|
|
2674
2683
|
setTimeout(function () {
|
|
@@ -2691,16 +2700,16 @@ modules = {
|
|
|
2691
2700
|
});
|
|
2692
2701
|
}
|
|
2693
2702
|
|
|
2694
|
-
let row = rows.find((item) =>
|
|
2695
|
-
isRootParent(item[parentField])
|
|
2696
|
-
);
|
|
2697
|
-
if (
|
|
2698
|
-
row
|
|
2699
|
-
&& (!expandAll
|
|
2700
|
-
|| !expandIds.some((id) =>
|
|
2701
|
-
treeKeyEquals(id, row[rowField])
|
|
2702
|
-
))
|
|
2703
|
-
) {
|
|
2703
|
+
let row = rows.find((item) =>
|
|
2704
|
+
isRootParent(item[parentField])
|
|
2705
|
+
);
|
|
2706
|
+
if (
|
|
2707
|
+
row
|
|
2708
|
+
&& (!expandAll
|
|
2709
|
+
|| !expandIds.some((id) =>
|
|
2710
|
+
treeKeyEquals(id, row[rowField])
|
|
2711
|
+
))
|
|
2712
|
+
) {
|
|
2704
2713
|
let hasChild = $grid.treeConfig.hasChild;
|
|
2705
2714
|
if (row[hasChild]) {
|
|
2706
2715
|
that.$nextTick(() => {
|
|
@@ -2748,63 +2757,63 @@ modules = {
|
|
|
2748
2757
|
},
|
|
2749
2758
|
},
|
|
2750
2759
|
};
|
|
2751
|
-
tableOption.callback = (rows) => {
|
|
2752
|
-
// this.fieldModel = rows;
|
|
2753
|
-
this.formModel[this.fieldKeyName] = rows;
|
|
2754
|
-
};
|
|
2755
|
-
}
|
|
2756
|
-
|
|
2757
|
-
if (isTreeTable) {
|
|
2758
|
-
tableOption.filterType = false;
|
|
2759
|
-
}
|
|
2760
|
-
tableOption = extendDeeply(tableOption, tableConfig);
|
|
2761
|
-
if (isTreeTable) {
|
|
2762
|
-
let mergedTreeConfig = {
|
|
2763
|
-
...(tableOption.config?.treeConfig || {}),
|
|
2764
|
-
};
|
|
2765
|
-
if (mergedTreeConfig.transform !== true) {
|
|
2766
|
-
// eslint-disable-next-line no-console
|
|
2767
|
-
console.error(
|
|
2768
|
-
"[xform tree-table] transform 必须为 true,已恢复为规范平铺模式。"
|
|
2769
|
-
);
|
|
2770
|
-
}
|
|
2771
|
-
mergedTreeConfig.transform = true;
|
|
2772
|
-
let resolvedFields = resolveTreeFields(mergedTreeConfig, {
|
|
2773
|
-
strict: true,
|
|
2774
|
-
});
|
|
2775
|
-
let resolvedTreeConfig = {
|
|
2776
|
-
...mergedTreeConfig,
|
|
2777
|
-
rowField: resolvedFields.rowField,
|
|
2778
|
-
parentField: resolvedFields.parentField,
|
|
2779
|
-
children: resolvedFields.childrenField,
|
|
2780
|
-
mapChildren: resolvedFields.mapChildrenField,
|
|
2781
|
-
hasChild: resolvedFields.hasChildField,
|
|
2782
|
-
lazy: resolvedFields.lazy,
|
|
2783
|
-
transform: true,
|
|
2784
|
-
};
|
|
2785
|
-
let resolvedIdentityConfig = resolveTreeIdentityConfig(
|
|
2786
|
-
resolvedTreeConfig,
|
|
2787
|
-
tableOption.treeIdentityConfig || {}
|
|
2788
|
-
);
|
|
2789
|
-
let resolvedCopyConfig = resolveTreeCopyConfig(
|
|
2790
|
-
resolvedFields,
|
|
2791
|
-
resolvedIdentityConfig,
|
|
2792
|
-
tableOption.treeCopyConfig || {}
|
|
2793
|
-
);
|
|
2794
|
-
let resolvedSubmitConfig = resolveTreeSubmitConfig(
|
|
2795
|
-
tableOption.treeSubmitConfig || {}
|
|
2796
|
-
);
|
|
2797
|
-
|
|
2798
|
-
this.resolvedTreeConfig = resolvedTreeConfig;
|
|
2799
|
-
this.resolvedTreeIdentityConfig = resolvedIdentityConfig;
|
|
2800
|
-
this.resolvedTreeCopyConfig = resolvedCopyConfig;
|
|
2801
|
-
this.resolvedTreeSubmitConfig = resolvedSubmitConfig;
|
|
2802
|
-
tableOption.config.treeConfig = resolvedTreeConfig;
|
|
2803
|
-
tableOption.treeIdentityConfig = resolvedIdentityConfig;
|
|
2804
|
-
tableOption.treeCopyConfig = resolvedCopyConfig;
|
|
2805
|
-
tableOption.treeSubmitConfig = resolvedSubmitConfig;
|
|
2806
|
-
}
|
|
2807
|
-
/* if (this.widget.options.tableConfig) {
|
|
2760
|
+
tableOption.callback = (rows) => {
|
|
2761
|
+
// this.fieldModel = rows;
|
|
2762
|
+
this.formModel[this.fieldKeyName] = rows;
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
if (isTreeTable) {
|
|
2767
|
+
tableOption.filterType = false;
|
|
2768
|
+
}
|
|
2769
|
+
tableOption = extendDeeply(tableOption, tableConfig);
|
|
2770
|
+
if (isTreeTable) {
|
|
2771
|
+
let mergedTreeConfig = {
|
|
2772
|
+
...(tableOption.config?.treeConfig || {}),
|
|
2773
|
+
};
|
|
2774
|
+
if (mergedTreeConfig.transform !== true) {
|
|
2775
|
+
// eslint-disable-next-line no-console
|
|
2776
|
+
console.error(
|
|
2777
|
+
"[xform tree-table] transform 必须为 true,已恢复为规范平铺模式。"
|
|
2778
|
+
);
|
|
2779
|
+
}
|
|
2780
|
+
mergedTreeConfig.transform = true;
|
|
2781
|
+
let resolvedFields = resolveTreeFields(mergedTreeConfig, {
|
|
2782
|
+
strict: true,
|
|
2783
|
+
});
|
|
2784
|
+
let resolvedTreeConfig = {
|
|
2785
|
+
...mergedTreeConfig,
|
|
2786
|
+
rowField: resolvedFields.rowField,
|
|
2787
|
+
parentField: resolvedFields.parentField,
|
|
2788
|
+
children: resolvedFields.childrenField,
|
|
2789
|
+
mapChildren: resolvedFields.mapChildrenField,
|
|
2790
|
+
hasChild: resolvedFields.hasChildField,
|
|
2791
|
+
lazy: resolvedFields.lazy,
|
|
2792
|
+
transform: true,
|
|
2793
|
+
};
|
|
2794
|
+
let resolvedIdentityConfig = resolveTreeIdentityConfig(
|
|
2795
|
+
resolvedTreeConfig,
|
|
2796
|
+
tableOption.treeIdentityConfig || {}
|
|
2797
|
+
);
|
|
2798
|
+
let resolvedCopyConfig = resolveTreeCopyConfig(
|
|
2799
|
+
resolvedFields,
|
|
2800
|
+
resolvedIdentityConfig,
|
|
2801
|
+
tableOption.treeCopyConfig || {}
|
|
2802
|
+
);
|
|
2803
|
+
let resolvedSubmitConfig = resolveTreeSubmitConfig(
|
|
2804
|
+
tableOption.treeSubmitConfig || {}
|
|
2805
|
+
);
|
|
2806
|
+
|
|
2807
|
+
this.resolvedTreeConfig = resolvedTreeConfig;
|
|
2808
|
+
this.resolvedTreeIdentityConfig = resolvedIdentityConfig;
|
|
2809
|
+
this.resolvedTreeCopyConfig = resolvedCopyConfig;
|
|
2810
|
+
this.resolvedTreeSubmitConfig = resolvedSubmitConfig;
|
|
2811
|
+
tableOption.config.treeConfig = resolvedTreeConfig;
|
|
2812
|
+
tableOption.treeIdentityConfig = resolvedIdentityConfig;
|
|
2813
|
+
tableOption.treeCopyConfig = resolvedCopyConfig;
|
|
2814
|
+
tableOption.treeSubmitConfig = resolvedSubmitConfig;
|
|
2815
|
+
}
|
|
2816
|
+
/* if (this.widget.options.tableConfig) {
|
|
2808
2817
|
let tableConfig =
|
|
2809
2818
|
this.handleCustomEvent(this.widget.options.tableConfig) || {};
|
|
2810
2819
|
tableOption = extendDeeply(tableOption, tableConfig);
|
|
@@ -2862,15 +2871,15 @@ modules = {
|
|
|
2862
2871
|
if (mergeRowEnabled && unikey) {
|
|
2863
2872
|
tableOption.config.spanMethod = this.mergeRowMethod;
|
|
2864
2873
|
}
|
|
2865
|
-
this.$vxeTableUtil.initVxeTable(tableOption).then((opts) => {
|
|
2866
|
-
this.vxeOption = opts;
|
|
2867
|
-
this.applyCompareRowClassName();
|
|
2868
|
-
if (isTreeTable) {
|
|
2869
|
-
this.$nextTick(() => {
|
|
2870
|
-
this.validateResolvedTreeConfig(this.getGridTable());
|
|
2871
|
-
});
|
|
2872
|
-
}
|
|
2873
|
-
// 列已就绪,补建 created 阶段被延后的行 schema
|
|
2874
|
+
this.$vxeTableUtil.initVxeTable(tableOption).then((opts) => {
|
|
2875
|
+
this.vxeOption = opts;
|
|
2876
|
+
this.applyCompareRowClassName();
|
|
2877
|
+
if (isTreeTable) {
|
|
2878
|
+
this.$nextTick(() => {
|
|
2879
|
+
this.validateResolvedTreeConfig(this.getGridTable());
|
|
2880
|
+
});
|
|
2881
|
+
}
|
|
2882
|
+
// 列已就绪,补建 created 阶段被延后的行 schema
|
|
2874
2883
|
this.flushPendingSchemaInit();
|
|
2875
2884
|
this.tryAutoLoadDynamicColumns().finally(() => {
|
|
2876
2885
|
if (!isQueryTable) {
|
|
@@ -3218,11 +3227,22 @@ modules = {
|
|
|
3218
3227
|
let tableRef = this.widget.id;
|
|
3219
3228
|
return tableRef;
|
|
3220
3229
|
},
|
|
3230
|
+
/** 导出前按脱敏规则剔除列,实现见 textMaskUtil.markMaskedExportColumns。 */
|
|
3231
|
+
markMaskedColumnsForExport() {
|
|
3232
|
+
markMaskedExportColumns(
|
|
3233
|
+
this.getGridTable(),
|
|
3234
|
+
buildTextMaskContext(
|
|
3235
|
+
this.getFormRef(),
|
|
3236
|
+
this.$store.getters.companyCode
|
|
3237
|
+
)
|
|
3238
|
+
);
|
|
3239
|
+
},
|
|
3221
3240
|
/**
|
|
3222
3241
|
* 使用统一 Excel 导出器导出当前表格。
|
|
3223
3242
|
* @param {Object} option 导出参数;prefix 为空时自动使用当前服务前缀。
|
|
3224
3243
|
*/
|
|
3225
3244
|
exportData(option) {
|
|
3245
|
+
this.markMaskedColumnsForExport();
|
|
3226
3246
|
let tableRef = this.getTableRef();
|
|
3227
3247
|
let serviceName = this.getFormRef().reportTemplate.serviceName;
|
|
3228
3248
|
option.prefix = option.prefix || "/" + serviceName;
|
|
@@ -3550,411 +3570,411 @@ modules = {
|
|
|
3550
3570
|
let $grid = this.$refs[this.getTableRef()];
|
|
3551
3571
|
return $grid;
|
|
3552
3572
|
},
|
|
3553
|
-
/**
|
|
3554
|
-
* 树表字段统一读取口。rowField 是树关系键,idField 仅作为旧调用方别名保留。
|
|
3555
|
-
* @param {Object} $grid VXE Grid 实例;缺省取当前组件的表格。
|
|
3556
|
-
* @returns {Object} 解析后的树字段以及兼容别名 idField。
|
|
3557
|
-
*/
|
|
3558
|
-
getTreeFields($grid) {
|
|
3559
|
-
let grid = $grid || this.getGridTable();
|
|
3560
|
-
let treeConfig = this.resolvedTreeConfig
|
|
3561
|
-
|| grid?.treeConfig
|
|
3562
|
-
|| grid?.params?.originOption?.config?.treeConfig
|
|
3563
|
-
|| {};
|
|
3564
|
-
let fields = resolveTreeFields(treeConfig, {
|
|
3565
|
-
strict: !!this.widget.options.isTreeTable,
|
|
3566
|
-
});
|
|
3567
|
-
return {
|
|
3568
|
-
...fields,
|
|
3569
|
-
// 兼容存量调用;新增代码只使用 rowField。
|
|
3570
|
-
idField: fields.rowField,
|
|
3571
|
-
};
|
|
3572
|
-
},
|
|
3573
|
-
/**
|
|
3574
|
-
* 汇总当前树表纯函数所需上下文。挂载后优先读取 originOption 中的已解析配置。
|
|
3575
|
-
* @param {Object} $grid 可选的 VXE Grid。
|
|
3576
|
-
* @param {Object} extra 调用场景附加上下文。
|
|
3577
|
-
* @returns {Object} 树工具上下文。
|
|
3578
|
-
*/
|
|
3579
|
-
getTreeContext($grid, extra) {
|
|
3580
|
-
let grid = $grid || this.getGridTable();
|
|
3581
|
-
let originOption = grid?.params?.originOption || grid?.originOption || {};
|
|
3582
|
-
let treeConfig = this.resolvedTreeConfig
|
|
3583
|
-
|| grid?.treeConfig
|
|
3584
|
-
|| originOption.config?.treeConfig
|
|
3585
|
-
|| {};
|
|
3586
|
-
let fields = this.getTreeFields(grid);
|
|
3587
|
-
let identityConfig = this.resolvedTreeIdentityConfig
|
|
3588
|
-
|| originOption.treeIdentityConfig
|
|
3589
|
-
|| resolveTreeIdentityConfig(treeConfig, {});
|
|
3590
|
-
let copyConfig = this.resolvedTreeCopyConfig
|
|
3591
|
-
|| originOption.treeCopyConfig
|
|
3592
|
-
|| resolveTreeCopyConfig(fields, identityConfig, {});
|
|
3593
|
-
let submitConfig = this.resolvedTreeSubmitConfig
|
|
3594
|
-
|| originOption.treeSubmitConfig
|
|
3595
|
-
|| resolveTreeSubmitConfig({});
|
|
3596
|
-
return {
|
|
3597
|
-
treeConfig,
|
|
3598
|
-
fields,
|
|
3599
|
-
identityConfig,
|
|
3600
|
-
copyConfig,
|
|
3601
|
-
submitConfig,
|
|
3602
|
-
temporaryKeyRegistry: this.treeTemporaryKeyRegistry,
|
|
3603
|
-
knownFormalKeyRegistry: this.treeKnownFormalKeyRegistry,
|
|
3604
|
-
...(extra || {}),
|
|
3605
|
-
};
|
|
3606
|
-
},
|
|
3607
|
-
/**
|
|
3608
|
-
* VXE 挂载后确认实际字段没有偏离初始化阶段唯一解析结果。
|
|
3609
|
-
* @param {Object} $grid VXE Grid。
|
|
3610
|
-
* @returns {Boolean} 校验通过或尚未挂载。
|
|
3611
|
-
*/
|
|
3612
|
-
validateResolvedTreeConfig($grid) {
|
|
3613
|
-
if (!$grid || !this.resolvedTreeConfig) {
|
|
3614
|
-
return true;
|
|
3615
|
-
}
|
|
3616
|
-
let actual = resolveTreeFields($grid.treeConfig || {}, {
|
|
3617
|
-
strict: true,
|
|
3618
|
-
});
|
|
3619
|
-
let expected = resolveTreeFields(this.resolvedTreeConfig, {
|
|
3620
|
-
strict: true,
|
|
3621
|
-
});
|
|
3622
|
-
let fieldNames = [
|
|
3623
|
-
"rowField",
|
|
3624
|
-
"parentField",
|
|
3625
|
-
"childrenField",
|
|
3626
|
-
"mapChildrenField",
|
|
3627
|
-
"hasChildField",
|
|
3628
|
-
];
|
|
3629
|
-
let mismatch = fieldNames.filter(
|
|
3630
|
-
(name) => actual[name] !== expected[name]
|
|
3631
|
-
);
|
|
3632
|
-
if (
|
|
3633
|
-
mismatch.length
|
|
3634
|
-
|| $grid.treeConfig?.transform !== true
|
|
3635
|
-
) {
|
|
3636
|
-
throw new Error(
|
|
3637
|
-
`[xform tree-table] VXE 树配置与 resolvedTreeConfig 不一致:${mismatch.join(
|
|
3638
|
-
", "
|
|
3639
|
-
) || "transform"}`
|
|
3640
|
-
);
|
|
3641
|
-
}
|
|
3642
|
-
return true;
|
|
3643
|
-
},
|
|
3644
|
-
/**
|
|
3645
|
-
* 记录当前表已知的临时键和正式键,供单行保存的外部父引用守卫使用。
|
|
3646
|
-
* @param {Array} rows 规范平铺行。
|
|
3647
|
-
* @param {Object} context 可选树上下文。
|
|
3648
|
-
*/
|
|
3649
|
-
registerTreeKeys(rows, context) {
|
|
3650
|
-
if (!this.widget.options.isTreeTable || !Array.isArray(rows)) {
|
|
3651
|
-
return;
|
|
3652
|
-
}
|
|
3653
|
-
let grid = this.getGridTable();
|
|
3654
|
-
if (
|
|
3655
|
-
!context
|
|
3656
|
-
&& !grid?.treeConfig
|
|
3657
|
-
&& !this.resolvedTreeConfig
|
|
3658
|
-
) {
|
|
3659
|
-
return;
|
|
3660
|
-
}
|
|
3661
|
-
let treeContext = context || this.getTreeContext();
|
|
3662
|
-
let { rowField, parentField } = treeContext.fields;
|
|
3663
|
-
rows.forEach((row) => {
|
|
3664
|
-
if (!row) return;
|
|
3665
|
-
let rowValue = row[rowField];
|
|
3666
|
-
if (isTemporaryTreeKey(row, rowField, treeContext.identityConfig)) {
|
|
3667
|
-
this.treeTemporaryKeyRegistry.add(rowValue);
|
|
3668
|
-
} else if (!isRootParent(rowValue)) {
|
|
3669
|
-
this.treeKnownFormalKeyRegistry.add(rowValue);
|
|
3670
|
-
}
|
|
3671
|
-
let parentValue = row[parentField];
|
|
3672
|
-
if (
|
|
3673
|
-
!isRootParent(parentValue)
|
|
3674
|
-
&& !this.registryHasTreeKey(
|
|
3675
|
-
this.treeTemporaryKeyRegistry,
|
|
3676
|
-
parentValue
|
|
3677
|
-
)
|
|
3678
|
-
) {
|
|
3679
|
-
this.treeKnownFormalKeyRegistry.add(parentValue);
|
|
3680
|
-
}
|
|
3681
|
-
});
|
|
3682
|
-
},
|
|
3683
|
-
/** @param {Set} registry 键注册表。@param {*} value 待匹配值。 */
|
|
3684
|
-
registryHasTreeKey(registry, value) {
|
|
3685
|
-
if (!registry || isRootParent(value)) {
|
|
3686
|
-
return false;
|
|
3687
|
-
}
|
|
3688
|
-
return Array.from(registry).some((item) =>
|
|
3689
|
-
treeKeyEquals(item, value)
|
|
3690
|
-
);
|
|
3691
|
-
},
|
|
3692
|
-
/** @param {Set} registry 键注册表。@param {*} value 待注销值。 */
|
|
3693
|
-
unregisterTreeKey(registry, value) {
|
|
3694
|
-
if (!registry) return;
|
|
3695
|
-
Array.from(registry).forEach((item) => {
|
|
3696
|
-
if (treeKeyEquals(item, value)) {
|
|
3697
|
-
registry.delete(item);
|
|
3698
|
-
}
|
|
3699
|
-
});
|
|
3700
|
-
},
|
|
3701
|
-
/**
|
|
3702
|
-
* 确保新增树行具有有效关系键;只有实际生成临时值时才写临时标记。
|
|
3703
|
-
* @param {Object} row 新行。
|
|
3704
|
-
* @param {Object} context 树上下文。
|
|
3705
|
-
* @returns {*} 最终 rowField 值。
|
|
3706
|
-
*/
|
|
3707
|
-
ensureNewTreeRowKey(row, context) {
|
|
3708
|
-
let treeContext = context || this.getTreeContext();
|
|
3709
|
-
let rowField = treeContext.fields.rowField;
|
|
3710
|
-
let rowValue = row[rowField];
|
|
3711
|
-
let isMarkedTemporary = isTemporaryTreeKey(
|
|
3712
|
-
row,
|
|
3713
|
-
rowField,
|
|
3714
|
-
treeContext.identityConfig
|
|
3715
|
-
);
|
|
3716
|
-
if (
|
|
3717
|
-
isRootParent(rowValue)
|
|
3718
|
-
|| (rowField === treeContext.identityConfig.physicalIdField
|
|
3719
|
-
&& !isMarkedTemporary)
|
|
3720
|
-
) {
|
|
3721
|
-
rowValue = makeTreeTempKey();
|
|
3722
|
-
markTemporaryTreeKey(row, rowField, rowValue);
|
|
3723
|
-
} else if (
|
|
3724
|
-
row._X_TREE_TEMP_KEY != null
|
|
3725
|
-
&& !treeKeyEquals(row._X_TREE_TEMP_KEY, rowValue)
|
|
3726
|
-
) {
|
|
3727
|
-
delete row._X_TREE_TEMP_KEY;
|
|
3728
|
-
}
|
|
3729
|
-
if (isTemporaryTreeKey(row, rowField, treeContext.identityConfig)) {
|
|
3730
|
-
this.treeTemporaryKeyRegistry.add(rowValue);
|
|
3731
|
-
} else {
|
|
3732
|
-
this.treeKnownFormalKeyRegistry.add(rowValue);
|
|
3733
|
-
}
|
|
3734
|
-
return rowValue;
|
|
3735
|
-
},
|
|
3736
|
-
/**
|
|
3737
|
-
* 在修改当前表数组前验证新增行不会造成树键冲突、父边冲突或环。
|
|
3738
|
-
* @param {Array} rows 待插入行。
|
|
3739
|
-
* @param {Object} context 树上下文。
|
|
3740
|
-
*/
|
|
3741
|
-
validateNewTreeRows(rows, context) {
|
|
3742
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
3743
|
-
canonicalizeTreeInput(tableRows.concat(rows || []), context);
|
|
3744
|
-
},
|
|
3745
|
-
/**
|
|
3746
|
-
* 树关系键变更唯一入口。负责持久化策略、唯一性、临时标记和直接子引用同步。
|
|
3747
|
-
* 业务选择器可直接 await 调用;单行保存也会用编辑快照兜底调用。
|
|
3748
|
-
* @param {Object} row 当前行。
|
|
3749
|
-
* @param {*} newValue 新树键。
|
|
3750
|
-
* @param {Object} options 可传 oldValue、$grid 和 reason。
|
|
3751
|
-
* @returns {Promise<Object>} 变更结果。
|
|
3752
|
-
*/
|
|
3753
|
-
async changeTreeRowField(row, newValue, options = {}) {
|
|
3754
|
-
if (!this.widget.options.isTreeTable || !row) {
|
|
3755
|
-
return { changed: false, transactional: false };
|
|
3756
|
-
}
|
|
3757
|
-
let $grid = options.$grid || this.getGridTable();
|
|
3758
|
-
let context = this.getTreeContext($grid);
|
|
3759
|
-
let { rowField } = context.fields;
|
|
3760
|
-
let hasExplicitOldValue = Object.prototype.hasOwnProperty.call(
|
|
3761
|
-
options,
|
|
3762
|
-
"oldValue"
|
|
3763
|
-
);
|
|
3764
|
-
let oldValue = hasExplicitOldValue
|
|
3765
|
-
? options.oldValue
|
|
3766
|
-
: row[rowField];
|
|
3767
|
-
if (
|
|
3768
|
-
!hasExplicitOldValue
|
|
3769
|
-
&& row._X_TREE_TEMP_KEY != null
|
|
3770
|
-
&& !treeKeyEquals(row._X_TREE_TEMP_KEY, newValue)
|
|
3771
|
-
) {
|
|
3772
|
-
oldValue = row._X_TREE_TEMP_KEY;
|
|
3773
|
-
}
|
|
3774
|
-
let rejectChange = async (messageOrError) => {
|
|
3775
|
-
row[rowField] = oldValue;
|
|
3776
|
-
if ($grid?.updateData) {
|
|
3777
|
-
await $grid.updateData();
|
|
3778
|
-
}
|
|
3779
|
-
throw messageOrError instanceof Error
|
|
3780
|
-
? messageOrError
|
|
3781
|
-
: new Error(messageOrError);
|
|
3782
|
-
};
|
|
3783
|
-
if (isRootParent(newValue)) {
|
|
3784
|
-
return rejectChange(`${rowField} 不能为空或根哨兵值。`);
|
|
3785
|
-
}
|
|
3786
|
-
if (treeKeyEquals(oldValue, newValue)) {
|
|
3787
|
-
row[rowField] = newValue;
|
|
3788
|
-
if (
|
|
3789
|
-
row._X_TREE_TEMP_KEY != null
|
|
3790
|
-
&& !treeKeyEquals(row._X_TREE_TEMP_KEY, newValue)
|
|
3791
|
-
) {
|
|
3792
|
-
delete row._X_TREE_TEMP_KEY;
|
|
3793
|
-
}
|
|
3794
|
-
return { changed: false, transactional: false };
|
|
3795
|
-
}
|
|
3796
|
-
|
|
3797
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
3798
|
-
let conflict = tableRows.some(
|
|
3799
|
-
(item) =>
|
|
3800
|
-
item !== row
|
|
3801
|
-
&& treeKeyEquals(item?.[rowField], newValue)
|
|
3802
|
-
);
|
|
3803
|
-
if (conflict) {
|
|
3804
|
-
return rejectChange(`树键 ${newValue} 已存在。`);
|
|
3805
|
-
}
|
|
3806
|
-
|
|
3807
|
-
let physicalIdField = context.identityConfig.physicalIdField;
|
|
3808
|
-
let physicalId = row[physicalIdField];
|
|
3809
|
-
let persisted = physicalId !== undefined
|
|
3810
|
-
&& physicalId !== null
|
|
3811
|
-
&& physicalId !== "";
|
|
3812
|
-
if (
|
|
3813
|
-
physicalIdField === rowField
|
|
3814
|
-
&& treeKeyEquals(physicalId, oldValue)
|
|
3815
|
-
&& isTemporaryTreeKey(
|
|
3816
|
-
{
|
|
3817
|
-
...row,
|
|
3818
|
-
[rowField]: oldValue,
|
|
3819
|
-
},
|
|
3820
|
-
rowField,
|
|
3821
|
-
context.identityConfig
|
|
3822
|
-
)
|
|
3823
|
-
) {
|
|
3824
|
-
persisted = false;
|
|
3825
|
-
}
|
|
3826
|
-
|
|
3827
|
-
let transactional = false;
|
|
3828
|
-
if (physicalIdField === rowField) {
|
|
3829
|
-
return rejectChange(
|
|
3830
|
-
persisted
|
|
3831
|
-
? "已持久化的物理主键不可修改。"
|
|
3832
|
-
: "物理主键兼作树键时只能由保存响应回填正式值。"
|
|
3833
|
-
);
|
|
3834
|
-
}
|
|
3835
|
-
if (persisted) {
|
|
3836
|
-
if (
|
|
3837
|
-
context.identityConfig
|
|
3838
|
-
.persistedRowFieldChangeStrategy !== "transactional"
|
|
3839
|
-
) {
|
|
3840
|
-
return rejectChange("已持久化节点的树键不允许直接修改。");
|
|
3841
|
-
}
|
|
3842
|
-
let changeHandler = context.identityConfig.changePersistedRowField;
|
|
3843
|
-
try {
|
|
3844
|
-
let result = await changeHandler({
|
|
3845
|
-
row: this.$baseLodash.cloneDeep(row),
|
|
3846
|
-
oldValue,
|
|
3847
|
-
newValue,
|
|
3848
|
-
fields: context.fields,
|
|
3849
|
-
reason: options.reason || "edit",
|
|
3850
|
-
});
|
|
3851
|
-
if (result === false) {
|
|
3852
|
-
throw new Error("树键事务更新未成功。");
|
|
3853
|
-
}
|
|
3854
|
-
transactional = true;
|
|
3855
|
-
} catch (error) {
|
|
3856
|
-
return rejectChange(error);
|
|
3857
|
-
}
|
|
3858
|
-
}
|
|
3859
|
-
|
|
3860
|
-
row[rowField] = newValue;
|
|
3861
|
-
syncTreeKeyReferences(tableRows, oldValue, newValue, {
|
|
3862
|
-
fields: context.fields,
|
|
3863
|
-
});
|
|
3864
|
-
delete row._X_TREE_TEMP_KEY;
|
|
3865
|
-
this.unregisterTreeKey(
|
|
3866
|
-
this.treeTemporaryKeyRegistry,
|
|
3867
|
-
oldValue
|
|
3868
|
-
);
|
|
3869
|
-
this.treeKnownFormalKeyRegistry.add(newValue);
|
|
3870
|
-
if ($grid?.updateData) {
|
|
3871
|
-
await $grid.updateData();
|
|
3872
|
-
}
|
|
3873
|
-
if (transactional) {
|
|
3874
|
-
let formRef = this.getFormRef();
|
|
3875
|
-
let reloadMethod
|
|
3876
|
-
= typeof formRef?.reloadSavedFormData === "function"
|
|
3877
|
-
? formRef.reloadSavedFormData
|
|
3878
|
-
: formRef?.reloadForm;
|
|
3879
|
-
if (typeof reloadMethod === "function") {
|
|
3880
|
-
try {
|
|
3881
|
-
await reloadMethod.call(formRef);
|
|
3882
|
-
} catch (error) {
|
|
3883
|
-
let reloadError = error instanceof Error
|
|
3884
|
-
? error
|
|
3885
|
-
: new Error(error || "树表重新加载失败。");
|
|
3886
|
-
reloadError.treeReloadFailed = true;
|
|
3887
|
-
throw reloadError;
|
|
3888
|
-
}
|
|
3889
|
-
}
|
|
3890
|
-
}
|
|
3891
|
-
return { changed: true, transactional };
|
|
3892
|
-
},
|
|
3893
|
-
/**
|
|
3894
|
-
* 单行保存前确认父节点已持久化,或外部父键已被登记为正式键。
|
|
3895
|
-
* @param {Object} row 当前行。
|
|
3896
|
-
* @param {Object} $grid VXE Grid。
|
|
3897
|
-
* @returns {String|null} 阻断原因。
|
|
3898
|
-
*/
|
|
3899
|
-
getTreeSingleSaveBlockReason(row, $grid) {
|
|
3900
|
-
if (!this.widget.options.isTreeTable || !row) {
|
|
3901
|
-
return null;
|
|
3902
|
-
}
|
|
3903
|
-
let context = this.getTreeContext($grid);
|
|
3904
|
-
let { rowField, parentField } = context.fields;
|
|
3905
|
-
let parentValue = row[parentField];
|
|
3906
|
-
if (isRootParent(parentValue)) {
|
|
3907
|
-
return null;
|
|
3908
|
-
}
|
|
3909
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
3910
|
-
let parentRow = tableRows.find(
|
|
3911
|
-
(item) =>
|
|
3912
|
-
item && treeKeyEquals(item[rowField], parentValue)
|
|
3913
|
-
);
|
|
3914
|
-
if (parentRow) {
|
|
3915
|
-
let physicalId = parentRow[context.identityConfig.physicalIdField];
|
|
3916
|
-
if (
|
|
3917
|
-
physicalId == null
|
|
3918
|
-
|| physicalId === ""
|
|
3919
|
-
|| isTemporaryTreeKey(
|
|
3920
|
-
parentRow,
|
|
3921
|
-
rowField,
|
|
3922
|
-
context.identityConfig
|
|
3923
|
-
)
|
|
3924
|
-
) {
|
|
3925
|
-
return "请先保存父节点,再保存当前子节点。";
|
|
3926
|
-
}
|
|
3927
|
-
return null;
|
|
3928
|
-
}
|
|
3929
|
-
if (
|
|
3930
|
-
this.registryHasTreeKey(
|
|
3931
|
-
this.treeTemporaryKeyRegistry,
|
|
3932
|
-
parentValue
|
|
3933
|
-
)
|
|
3934
|
-
) {
|
|
3935
|
-
return "当前行引用了尚未保存的父节点,请先保存父节点。";
|
|
3936
|
-
}
|
|
3937
|
-
if (
|
|
3938
|
-
this.registryHasTreeKey(
|
|
3939
|
-
this.treeKnownFormalKeyRegistry,
|
|
3940
|
-
parentValue
|
|
3941
|
-
)
|
|
3942
|
-
) {
|
|
3943
|
-
return null;
|
|
3944
|
-
}
|
|
3945
|
-
let validator = context.identityConfig.validateExternalParentKey;
|
|
3946
|
-
if (typeof validator === "function") {
|
|
3947
|
-
let result = validator(parentValue, row, "single");
|
|
3948
|
-
if (result && typeof result.then === "function") {
|
|
3949
|
-
return "外部父节点校验必须同步完成。";
|
|
3950
|
-
}
|
|
3951
|
-
if (result === true) {
|
|
3952
|
-
this.treeKnownFormalKeyRegistry.add(parentValue);
|
|
3953
|
-
return null;
|
|
3954
|
-
}
|
|
3955
|
-
}
|
|
3956
|
-
return "无法确认当前行的父节点已保存,请先保存或加载父节点。";
|
|
3957
|
-
},
|
|
3573
|
+
/**
|
|
3574
|
+
* 树表字段统一读取口。rowField 是树关系键,idField 仅作为旧调用方别名保留。
|
|
3575
|
+
* @param {Object} $grid VXE Grid 实例;缺省取当前组件的表格。
|
|
3576
|
+
* @returns {Object} 解析后的树字段以及兼容别名 idField。
|
|
3577
|
+
*/
|
|
3578
|
+
getTreeFields($grid) {
|
|
3579
|
+
let grid = $grid || this.getGridTable();
|
|
3580
|
+
let treeConfig = this.resolvedTreeConfig
|
|
3581
|
+
|| grid?.treeConfig
|
|
3582
|
+
|| grid?.params?.originOption?.config?.treeConfig
|
|
3583
|
+
|| {};
|
|
3584
|
+
let fields = resolveTreeFields(treeConfig, {
|
|
3585
|
+
strict: !!this.widget.options.isTreeTable,
|
|
3586
|
+
});
|
|
3587
|
+
return {
|
|
3588
|
+
...fields,
|
|
3589
|
+
// 兼容存量调用;新增代码只使用 rowField。
|
|
3590
|
+
idField: fields.rowField,
|
|
3591
|
+
};
|
|
3592
|
+
},
|
|
3593
|
+
/**
|
|
3594
|
+
* 汇总当前树表纯函数所需上下文。挂载后优先读取 originOption 中的已解析配置。
|
|
3595
|
+
* @param {Object} $grid 可选的 VXE Grid。
|
|
3596
|
+
* @param {Object} extra 调用场景附加上下文。
|
|
3597
|
+
* @returns {Object} 树工具上下文。
|
|
3598
|
+
*/
|
|
3599
|
+
getTreeContext($grid, extra) {
|
|
3600
|
+
let grid = $grid || this.getGridTable();
|
|
3601
|
+
let originOption = grid?.params?.originOption || grid?.originOption || {};
|
|
3602
|
+
let treeConfig = this.resolvedTreeConfig
|
|
3603
|
+
|| grid?.treeConfig
|
|
3604
|
+
|| originOption.config?.treeConfig
|
|
3605
|
+
|| {};
|
|
3606
|
+
let fields = this.getTreeFields(grid);
|
|
3607
|
+
let identityConfig = this.resolvedTreeIdentityConfig
|
|
3608
|
+
|| originOption.treeIdentityConfig
|
|
3609
|
+
|| resolveTreeIdentityConfig(treeConfig, {});
|
|
3610
|
+
let copyConfig = this.resolvedTreeCopyConfig
|
|
3611
|
+
|| originOption.treeCopyConfig
|
|
3612
|
+
|| resolveTreeCopyConfig(fields, identityConfig, {});
|
|
3613
|
+
let submitConfig = this.resolvedTreeSubmitConfig
|
|
3614
|
+
|| originOption.treeSubmitConfig
|
|
3615
|
+
|| resolveTreeSubmitConfig({});
|
|
3616
|
+
return {
|
|
3617
|
+
treeConfig,
|
|
3618
|
+
fields,
|
|
3619
|
+
identityConfig,
|
|
3620
|
+
copyConfig,
|
|
3621
|
+
submitConfig,
|
|
3622
|
+
temporaryKeyRegistry: this.treeTemporaryKeyRegistry,
|
|
3623
|
+
knownFormalKeyRegistry: this.treeKnownFormalKeyRegistry,
|
|
3624
|
+
...(extra || {}),
|
|
3625
|
+
};
|
|
3626
|
+
},
|
|
3627
|
+
/**
|
|
3628
|
+
* VXE 挂载后确认实际字段没有偏离初始化阶段唯一解析结果。
|
|
3629
|
+
* @param {Object} $grid VXE Grid。
|
|
3630
|
+
* @returns {Boolean} 校验通过或尚未挂载。
|
|
3631
|
+
*/
|
|
3632
|
+
validateResolvedTreeConfig($grid) {
|
|
3633
|
+
if (!$grid || !this.resolvedTreeConfig) {
|
|
3634
|
+
return true;
|
|
3635
|
+
}
|
|
3636
|
+
let actual = resolveTreeFields($grid.treeConfig || {}, {
|
|
3637
|
+
strict: true,
|
|
3638
|
+
});
|
|
3639
|
+
let expected = resolveTreeFields(this.resolvedTreeConfig, {
|
|
3640
|
+
strict: true,
|
|
3641
|
+
});
|
|
3642
|
+
let fieldNames = [
|
|
3643
|
+
"rowField",
|
|
3644
|
+
"parentField",
|
|
3645
|
+
"childrenField",
|
|
3646
|
+
"mapChildrenField",
|
|
3647
|
+
"hasChildField",
|
|
3648
|
+
];
|
|
3649
|
+
let mismatch = fieldNames.filter(
|
|
3650
|
+
(name) => actual[name] !== expected[name]
|
|
3651
|
+
);
|
|
3652
|
+
if (
|
|
3653
|
+
mismatch.length
|
|
3654
|
+
|| $grid.treeConfig?.transform !== true
|
|
3655
|
+
) {
|
|
3656
|
+
throw new Error(
|
|
3657
|
+
`[xform tree-table] VXE 树配置与 resolvedTreeConfig 不一致:${mismatch.join(
|
|
3658
|
+
", "
|
|
3659
|
+
) || "transform"}`
|
|
3660
|
+
);
|
|
3661
|
+
}
|
|
3662
|
+
return true;
|
|
3663
|
+
},
|
|
3664
|
+
/**
|
|
3665
|
+
* 记录当前表已知的临时键和正式键,供单行保存的外部父引用守卫使用。
|
|
3666
|
+
* @param {Array} rows 规范平铺行。
|
|
3667
|
+
* @param {Object} context 可选树上下文。
|
|
3668
|
+
*/
|
|
3669
|
+
registerTreeKeys(rows, context) {
|
|
3670
|
+
if (!this.widget.options.isTreeTable || !Array.isArray(rows)) {
|
|
3671
|
+
return;
|
|
3672
|
+
}
|
|
3673
|
+
let grid = this.getGridTable();
|
|
3674
|
+
if (
|
|
3675
|
+
!context
|
|
3676
|
+
&& !grid?.treeConfig
|
|
3677
|
+
&& !this.resolvedTreeConfig
|
|
3678
|
+
) {
|
|
3679
|
+
return;
|
|
3680
|
+
}
|
|
3681
|
+
let treeContext = context || this.getTreeContext();
|
|
3682
|
+
let { rowField, parentField } = treeContext.fields;
|
|
3683
|
+
rows.forEach((row) => {
|
|
3684
|
+
if (!row) return;
|
|
3685
|
+
let rowValue = row[rowField];
|
|
3686
|
+
if (isTemporaryTreeKey(row, rowField, treeContext.identityConfig)) {
|
|
3687
|
+
this.treeTemporaryKeyRegistry.add(rowValue);
|
|
3688
|
+
} else if (!isRootParent(rowValue)) {
|
|
3689
|
+
this.treeKnownFormalKeyRegistry.add(rowValue);
|
|
3690
|
+
}
|
|
3691
|
+
let parentValue = row[parentField];
|
|
3692
|
+
if (
|
|
3693
|
+
!isRootParent(parentValue)
|
|
3694
|
+
&& !this.registryHasTreeKey(
|
|
3695
|
+
this.treeTemporaryKeyRegistry,
|
|
3696
|
+
parentValue
|
|
3697
|
+
)
|
|
3698
|
+
) {
|
|
3699
|
+
this.treeKnownFormalKeyRegistry.add(parentValue);
|
|
3700
|
+
}
|
|
3701
|
+
});
|
|
3702
|
+
},
|
|
3703
|
+
/** @param {Set} registry 键注册表。@param {*} value 待匹配值。 */
|
|
3704
|
+
registryHasTreeKey(registry, value) {
|
|
3705
|
+
if (!registry || isRootParent(value)) {
|
|
3706
|
+
return false;
|
|
3707
|
+
}
|
|
3708
|
+
return Array.from(registry).some((item) =>
|
|
3709
|
+
treeKeyEquals(item, value)
|
|
3710
|
+
);
|
|
3711
|
+
},
|
|
3712
|
+
/** @param {Set} registry 键注册表。@param {*} value 待注销值。 */
|
|
3713
|
+
unregisterTreeKey(registry, value) {
|
|
3714
|
+
if (!registry) return;
|
|
3715
|
+
Array.from(registry).forEach((item) => {
|
|
3716
|
+
if (treeKeyEquals(item, value)) {
|
|
3717
|
+
registry.delete(item);
|
|
3718
|
+
}
|
|
3719
|
+
});
|
|
3720
|
+
},
|
|
3721
|
+
/**
|
|
3722
|
+
* 确保新增树行具有有效关系键;只有实际生成临时值时才写临时标记。
|
|
3723
|
+
* @param {Object} row 新行。
|
|
3724
|
+
* @param {Object} context 树上下文。
|
|
3725
|
+
* @returns {*} 最终 rowField 值。
|
|
3726
|
+
*/
|
|
3727
|
+
ensureNewTreeRowKey(row, context) {
|
|
3728
|
+
let treeContext = context || this.getTreeContext();
|
|
3729
|
+
let rowField = treeContext.fields.rowField;
|
|
3730
|
+
let rowValue = row[rowField];
|
|
3731
|
+
let isMarkedTemporary = isTemporaryTreeKey(
|
|
3732
|
+
row,
|
|
3733
|
+
rowField,
|
|
3734
|
+
treeContext.identityConfig
|
|
3735
|
+
);
|
|
3736
|
+
if (
|
|
3737
|
+
isRootParent(rowValue)
|
|
3738
|
+
|| (rowField === treeContext.identityConfig.physicalIdField
|
|
3739
|
+
&& !isMarkedTemporary)
|
|
3740
|
+
) {
|
|
3741
|
+
rowValue = makeTreeTempKey();
|
|
3742
|
+
markTemporaryTreeKey(row, rowField, rowValue);
|
|
3743
|
+
} else if (
|
|
3744
|
+
row._X_TREE_TEMP_KEY != null
|
|
3745
|
+
&& !treeKeyEquals(row._X_TREE_TEMP_KEY, rowValue)
|
|
3746
|
+
) {
|
|
3747
|
+
delete row._X_TREE_TEMP_KEY;
|
|
3748
|
+
}
|
|
3749
|
+
if (isTemporaryTreeKey(row, rowField, treeContext.identityConfig)) {
|
|
3750
|
+
this.treeTemporaryKeyRegistry.add(rowValue);
|
|
3751
|
+
} else {
|
|
3752
|
+
this.treeKnownFormalKeyRegistry.add(rowValue);
|
|
3753
|
+
}
|
|
3754
|
+
return rowValue;
|
|
3755
|
+
},
|
|
3756
|
+
/**
|
|
3757
|
+
* 在修改当前表数组前验证新增行不会造成树键冲突、父边冲突或环。
|
|
3758
|
+
* @param {Array} rows 待插入行。
|
|
3759
|
+
* @param {Object} context 树上下文。
|
|
3760
|
+
*/
|
|
3761
|
+
validateNewTreeRows(rows, context) {
|
|
3762
|
+
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
3763
|
+
canonicalizeTreeInput(tableRows.concat(rows || []), context);
|
|
3764
|
+
},
|
|
3765
|
+
/**
|
|
3766
|
+
* 树关系键变更唯一入口。负责持久化策略、唯一性、临时标记和直接子引用同步。
|
|
3767
|
+
* 业务选择器可直接 await 调用;单行保存也会用编辑快照兜底调用。
|
|
3768
|
+
* @param {Object} row 当前行。
|
|
3769
|
+
* @param {*} newValue 新树键。
|
|
3770
|
+
* @param {Object} options 可传 oldValue、$grid 和 reason。
|
|
3771
|
+
* @returns {Promise<Object>} 变更结果。
|
|
3772
|
+
*/
|
|
3773
|
+
async changeTreeRowField(row, newValue, options = {}) {
|
|
3774
|
+
if (!this.widget.options.isTreeTable || !row) {
|
|
3775
|
+
return { changed: false, transactional: false };
|
|
3776
|
+
}
|
|
3777
|
+
let $grid = options.$grid || this.getGridTable();
|
|
3778
|
+
let context = this.getTreeContext($grid);
|
|
3779
|
+
let { rowField } = context.fields;
|
|
3780
|
+
let hasExplicitOldValue = Object.prototype.hasOwnProperty.call(
|
|
3781
|
+
options,
|
|
3782
|
+
"oldValue"
|
|
3783
|
+
);
|
|
3784
|
+
let oldValue = hasExplicitOldValue
|
|
3785
|
+
? options.oldValue
|
|
3786
|
+
: row[rowField];
|
|
3787
|
+
if (
|
|
3788
|
+
!hasExplicitOldValue
|
|
3789
|
+
&& row._X_TREE_TEMP_KEY != null
|
|
3790
|
+
&& !treeKeyEquals(row._X_TREE_TEMP_KEY, newValue)
|
|
3791
|
+
) {
|
|
3792
|
+
oldValue = row._X_TREE_TEMP_KEY;
|
|
3793
|
+
}
|
|
3794
|
+
let rejectChange = async (messageOrError) => {
|
|
3795
|
+
row[rowField] = oldValue;
|
|
3796
|
+
if ($grid?.updateData) {
|
|
3797
|
+
await $grid.updateData();
|
|
3798
|
+
}
|
|
3799
|
+
throw messageOrError instanceof Error
|
|
3800
|
+
? messageOrError
|
|
3801
|
+
: new Error(messageOrError);
|
|
3802
|
+
};
|
|
3803
|
+
if (isRootParent(newValue)) {
|
|
3804
|
+
return rejectChange(`${rowField} 不能为空或根哨兵值。`);
|
|
3805
|
+
}
|
|
3806
|
+
if (treeKeyEquals(oldValue, newValue)) {
|
|
3807
|
+
row[rowField] = newValue;
|
|
3808
|
+
if (
|
|
3809
|
+
row._X_TREE_TEMP_KEY != null
|
|
3810
|
+
&& !treeKeyEquals(row._X_TREE_TEMP_KEY, newValue)
|
|
3811
|
+
) {
|
|
3812
|
+
delete row._X_TREE_TEMP_KEY;
|
|
3813
|
+
}
|
|
3814
|
+
return { changed: false, transactional: false };
|
|
3815
|
+
}
|
|
3816
|
+
|
|
3817
|
+
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
3818
|
+
let conflict = tableRows.some(
|
|
3819
|
+
(item) =>
|
|
3820
|
+
item !== row
|
|
3821
|
+
&& treeKeyEquals(item?.[rowField], newValue)
|
|
3822
|
+
);
|
|
3823
|
+
if (conflict) {
|
|
3824
|
+
return rejectChange(`树键 ${newValue} 已存在。`);
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3827
|
+
let physicalIdField = context.identityConfig.physicalIdField;
|
|
3828
|
+
let physicalId = row[physicalIdField];
|
|
3829
|
+
let persisted = physicalId !== undefined
|
|
3830
|
+
&& physicalId !== null
|
|
3831
|
+
&& physicalId !== "";
|
|
3832
|
+
if (
|
|
3833
|
+
physicalIdField === rowField
|
|
3834
|
+
&& treeKeyEquals(physicalId, oldValue)
|
|
3835
|
+
&& isTemporaryTreeKey(
|
|
3836
|
+
{
|
|
3837
|
+
...row,
|
|
3838
|
+
[rowField]: oldValue,
|
|
3839
|
+
},
|
|
3840
|
+
rowField,
|
|
3841
|
+
context.identityConfig
|
|
3842
|
+
)
|
|
3843
|
+
) {
|
|
3844
|
+
persisted = false;
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3847
|
+
let transactional = false;
|
|
3848
|
+
if (physicalIdField === rowField) {
|
|
3849
|
+
return rejectChange(
|
|
3850
|
+
persisted
|
|
3851
|
+
? "已持久化的物理主键不可修改。"
|
|
3852
|
+
: "物理主键兼作树键时只能由保存响应回填正式值。"
|
|
3853
|
+
);
|
|
3854
|
+
}
|
|
3855
|
+
if (persisted) {
|
|
3856
|
+
if (
|
|
3857
|
+
context.identityConfig
|
|
3858
|
+
.persistedRowFieldChangeStrategy !== "transactional"
|
|
3859
|
+
) {
|
|
3860
|
+
return rejectChange("已持久化节点的树键不允许直接修改。");
|
|
3861
|
+
}
|
|
3862
|
+
let changeHandler = context.identityConfig.changePersistedRowField;
|
|
3863
|
+
try {
|
|
3864
|
+
let result = await changeHandler({
|
|
3865
|
+
row: this.$baseLodash.cloneDeep(row),
|
|
3866
|
+
oldValue,
|
|
3867
|
+
newValue,
|
|
3868
|
+
fields: context.fields,
|
|
3869
|
+
reason: options.reason || "edit",
|
|
3870
|
+
});
|
|
3871
|
+
if (result === false) {
|
|
3872
|
+
throw new Error("树键事务更新未成功。");
|
|
3873
|
+
}
|
|
3874
|
+
transactional = true;
|
|
3875
|
+
} catch (error) {
|
|
3876
|
+
return rejectChange(error);
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
row[rowField] = newValue;
|
|
3881
|
+
syncTreeKeyReferences(tableRows, oldValue, newValue, {
|
|
3882
|
+
fields: context.fields,
|
|
3883
|
+
});
|
|
3884
|
+
delete row._X_TREE_TEMP_KEY;
|
|
3885
|
+
this.unregisterTreeKey(
|
|
3886
|
+
this.treeTemporaryKeyRegistry,
|
|
3887
|
+
oldValue
|
|
3888
|
+
);
|
|
3889
|
+
this.treeKnownFormalKeyRegistry.add(newValue);
|
|
3890
|
+
if ($grid?.updateData) {
|
|
3891
|
+
await $grid.updateData();
|
|
3892
|
+
}
|
|
3893
|
+
if (transactional) {
|
|
3894
|
+
let formRef = this.getFormRef();
|
|
3895
|
+
let reloadMethod
|
|
3896
|
+
= typeof formRef?.reloadSavedFormData === "function"
|
|
3897
|
+
? formRef.reloadSavedFormData
|
|
3898
|
+
: formRef?.reloadForm;
|
|
3899
|
+
if (typeof reloadMethod === "function") {
|
|
3900
|
+
try {
|
|
3901
|
+
await reloadMethod.call(formRef);
|
|
3902
|
+
} catch (error) {
|
|
3903
|
+
let reloadError = error instanceof Error
|
|
3904
|
+
? error
|
|
3905
|
+
: new Error(error || "树表重新加载失败。");
|
|
3906
|
+
reloadError.treeReloadFailed = true;
|
|
3907
|
+
throw reloadError;
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
return { changed: true, transactional };
|
|
3912
|
+
},
|
|
3913
|
+
/**
|
|
3914
|
+
* 单行保存前确认父节点已持久化,或外部父键已被登记为正式键。
|
|
3915
|
+
* @param {Object} row 当前行。
|
|
3916
|
+
* @param {Object} $grid VXE Grid。
|
|
3917
|
+
* @returns {String|null} 阻断原因。
|
|
3918
|
+
*/
|
|
3919
|
+
getTreeSingleSaveBlockReason(row, $grid) {
|
|
3920
|
+
if (!this.widget.options.isTreeTable || !row) {
|
|
3921
|
+
return null;
|
|
3922
|
+
}
|
|
3923
|
+
let context = this.getTreeContext($grid);
|
|
3924
|
+
let { rowField, parentField } = context.fields;
|
|
3925
|
+
let parentValue = row[parentField];
|
|
3926
|
+
if (isRootParent(parentValue)) {
|
|
3927
|
+
return null;
|
|
3928
|
+
}
|
|
3929
|
+
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
3930
|
+
let parentRow = tableRows.find(
|
|
3931
|
+
(item) =>
|
|
3932
|
+
item && treeKeyEquals(item[rowField], parentValue)
|
|
3933
|
+
);
|
|
3934
|
+
if (parentRow) {
|
|
3935
|
+
let physicalId = parentRow[context.identityConfig.physicalIdField];
|
|
3936
|
+
if (
|
|
3937
|
+
physicalId == null
|
|
3938
|
+
|| physicalId === ""
|
|
3939
|
+
|| isTemporaryTreeKey(
|
|
3940
|
+
parentRow,
|
|
3941
|
+
rowField,
|
|
3942
|
+
context.identityConfig
|
|
3943
|
+
)
|
|
3944
|
+
) {
|
|
3945
|
+
return "请先保存父节点,再保存当前子节点。";
|
|
3946
|
+
}
|
|
3947
|
+
return null;
|
|
3948
|
+
}
|
|
3949
|
+
if (
|
|
3950
|
+
this.registryHasTreeKey(
|
|
3951
|
+
this.treeTemporaryKeyRegistry,
|
|
3952
|
+
parentValue
|
|
3953
|
+
)
|
|
3954
|
+
) {
|
|
3955
|
+
return "当前行引用了尚未保存的父节点,请先保存父节点。";
|
|
3956
|
+
}
|
|
3957
|
+
if (
|
|
3958
|
+
this.registryHasTreeKey(
|
|
3959
|
+
this.treeKnownFormalKeyRegistry,
|
|
3960
|
+
parentValue
|
|
3961
|
+
)
|
|
3962
|
+
) {
|
|
3963
|
+
return null;
|
|
3964
|
+
}
|
|
3965
|
+
let validator = context.identityConfig.validateExternalParentKey;
|
|
3966
|
+
if (typeof validator === "function") {
|
|
3967
|
+
let result = validator(parentValue, row, "single");
|
|
3968
|
+
if (result && typeof result.then === "function") {
|
|
3969
|
+
return "外部父节点校验必须同步完成。";
|
|
3970
|
+
}
|
|
3971
|
+
if (result === true) {
|
|
3972
|
+
this.treeKnownFormalKeyRegistry.add(parentValue);
|
|
3973
|
+
return null;
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
return "无法确认当前行的父节点已保存,请先保存或加载父节点。";
|
|
3977
|
+
},
|
|
3958
3978
|
/** @param {Object} e 容器组件 schema。@returns {String} 动态组件名称。 */
|
|
3959
3979
|
getContainerWidgetName: function (e) {
|
|
3960
3980
|
return "grid" === e.type ? "grid-item" : e.type + "-item";
|
|
@@ -4029,431 +4049,431 @@ modules = {
|
|
|
4029
4049
|
|
|
4030
4050
|
//editTable begin
|
|
4031
4051
|
/**
|
|
4032
|
-
* 保存当前编辑行。持久化行原位合并;新身份以回查结果重建树关系。
|
|
4052
|
+
* 保存当前编辑行。持久化行原位合并;新身份以回查结果重建树关系。
|
|
4033
4053
|
* @param {Object} obj VXE 插槽参数,必须包含 row 和 $table。
|
|
4034
4054
|
*/
|
|
4035
|
-
async saveEditRow(obj) {
|
|
4036
|
-
let formRef = this.getFormRef();
|
|
4037
|
-
let formConfig = this.formConfig;
|
|
4038
|
-
let entity = formConfig.entity;
|
|
4039
|
-
if (!entity) return;
|
|
4040
|
-
let reportTemplate = formRef?.reportTemplate;
|
|
4041
|
-
let formCode = reportTemplate?.formCode;
|
|
4042
|
-
let scriptCode = formConfig.saveScriptCode || "saveUpdate";
|
|
4043
|
-
|
|
4044
|
-
let $grid = obj.$table.$xegrid;
|
|
4045
|
-
if (typeof this.treeSingleSaveReconcileTask === "function") {
|
|
4046
|
-
return this.treeSingleSaveReconcileTask();
|
|
4047
|
-
}
|
|
4048
|
-
if (this.treeSingleSavePending) {
|
|
4049
|
-
this.$message.warning("当前行正在保存,请勿重复操作。");
|
|
4050
|
-
return false;
|
|
4051
|
-
}
|
|
4052
|
-
this.treeSingleSavePending = true;
|
|
4053
|
-
let keepSaveLocked = false;
|
|
4054
|
-
let reloadMethod
|
|
4055
|
-
= typeof formRef.reloadSavedFormData === "function"
|
|
4056
|
-
? formRef.reloadSavedFormData
|
|
4057
|
-
: formRef.reloadForm;
|
|
4058
|
-
let installReloadRetry = () => {
|
|
4059
|
-
let retryPromise = null;
|
|
4060
|
-
this.treeSingleSaveReconcileTask = () => {
|
|
4061
|
-
if (retryPromise) return retryPromise;
|
|
4062
|
-
retryPromise = (async () => {
|
|
4063
|
-
try {
|
|
4064
|
-
await reloadMethod.call(formRef);
|
|
4065
|
-
delete obj.$table.editCloneRow;
|
|
4066
|
-
this.treeSingleSaveReconcileTask = null;
|
|
4067
|
-
this.treeSingleSavePending = false;
|
|
4068
|
-
return true;
|
|
4069
|
-
} catch (error) {
|
|
4070
|
-
this.$message.error(
|
|
4071
|
-
"重新加载仍未成功,请手动刷新后再操作。"
|
|
4072
|
-
);
|
|
4073
|
-
return false;
|
|
4074
|
-
} finally {
|
|
4075
|
-
retryPromise = null;
|
|
4076
|
-
}
|
|
4077
|
-
})();
|
|
4078
|
-
return retryPromise;
|
|
4079
|
-
};
|
|
4080
|
-
};
|
|
4081
|
-
let isTreeTable = this.widget.options.isTreeTable || false;
|
|
4082
|
-
let treeContext = isTreeTable
|
|
4083
|
-
? this.getTreeContext($grid, { mode: "single" })
|
|
4084
|
-
: null;
|
|
4085
|
-
let oldTreeKey = null;
|
|
4086
|
-
let rebuildTreeAfterSave = false;
|
|
4087
|
-
let treePhysicalIdWasMissing = false;
|
|
4088
|
-
let treeKeyWasTemporary = false;
|
|
4089
|
-
let treeSnapshotApplied = false;
|
|
4090
|
-
let logicalRowKey = obj.row?._X_ROW_KEY || null;
|
|
4091
|
-
let originalPhysicalId = null;
|
|
4092
|
-
try {
|
|
4093
|
-
let valid = await new Promise((resolve, reject) => {
|
|
4094
|
-
try {
|
|
4095
|
-
formRef.validate(resolve);
|
|
4096
|
-
} catch (error) {
|
|
4097
|
-
reject(error);
|
|
4098
|
-
}
|
|
4099
|
-
});
|
|
4100
|
-
if (!valid) return false;
|
|
4101
|
-
|
|
4102
|
-
let requestRow = obj.row;
|
|
4103
|
-
if (treeContext) {
|
|
4104
|
-
let blockReason = this.getTreeSingleSaveBlockReason(
|
|
4105
|
-
obj.row,
|
|
4106
|
-
$grid
|
|
4107
|
-
);
|
|
4108
|
-
if (blockReason) {
|
|
4109
|
-
this.$message.error(blockReason);
|
|
4110
|
-
return false;
|
|
4111
|
-
}
|
|
4112
|
-
let rowField = treeContext.fields.rowField;
|
|
4113
|
-
let currentTreeKey = obj.row[rowField];
|
|
4114
|
-
let editCloneRow = obj.$table.editCloneRow;
|
|
4115
|
-
let previousTreeKey = editCloneRow?.[rowField];
|
|
4116
|
-
if (
|
|
4117
|
-
obj.row._X_TREE_TEMP_KEY != null
|
|
4118
|
-
&& !treeKeyEquals(
|
|
4119
|
-
obj.row._X_TREE_TEMP_KEY,
|
|
4120
|
-
currentTreeKey
|
|
4121
|
-
)
|
|
4122
|
-
) {
|
|
4123
|
-
previousTreeKey = obj.row._X_TREE_TEMP_KEY;
|
|
4124
|
-
}
|
|
4125
|
-
if (
|
|
4126
|
-
previousTreeKey !== undefined
|
|
4127
|
-
&& previousTreeKey !== null
|
|
4128
|
-
&& !treeKeyEquals(previousTreeKey, currentTreeKey)
|
|
4129
|
-
) {
|
|
4130
|
-
let changeResult = await this.changeTreeRowField(
|
|
4131
|
-
obj.row,
|
|
4132
|
-
currentTreeKey,
|
|
4133
|
-
{
|
|
4134
|
-
oldValue: previousTreeKey,
|
|
4135
|
-
$grid,
|
|
4136
|
-
reason: "single-save",
|
|
4137
|
-
}
|
|
4138
|
-
);
|
|
4139
|
-
if (changeResult.transactional) {
|
|
4140
|
-
delete obj.$table.editCloneRow;
|
|
4141
|
-
return true;
|
|
4142
|
-
}
|
|
4143
|
-
}
|
|
4144
|
-
oldTreeKey = obj.row[rowField];
|
|
4145
|
-
let physicalIdField
|
|
4146
|
-
= treeContext.identityConfig.physicalIdField;
|
|
4147
|
-
let physicalId = obj.row[physicalIdField];
|
|
4148
|
-
originalPhysicalId = physicalId;
|
|
4149
|
-
treeKeyWasTemporary = isTemporaryTreeKey(
|
|
4150
|
-
obj.row,
|
|
4151
|
-
rowField,
|
|
4152
|
-
treeContext.identityConfig
|
|
4153
|
-
);
|
|
4154
|
-
treePhysicalIdWasMissing
|
|
4155
|
-
= physicalId == null
|
|
4156
|
-
|| physicalId === ""
|
|
4157
|
-
|| (
|
|
4158
|
-
physicalIdField === rowField
|
|
4159
|
-
&& treeKeyWasTemporary
|
|
4160
|
-
);
|
|
4161
|
-
rebuildTreeAfterSave
|
|
4162
|
-
= treePhysicalIdWasMissing
|
|
4163
|
-
|| treeKeyWasTemporary;
|
|
4164
|
-
requestRow = sanitizeTreeRow(
|
|
4165
|
-
this.$baseLodash.cloneDeep(obj.row),
|
|
4166
|
-
treeContext
|
|
4167
|
-
);
|
|
4168
|
-
}
|
|
4169
|
-
|
|
4170
|
-
try {
|
|
4171
|
-
await this.$baseConfirm("您确定要保存吗?");
|
|
4172
|
-
} catch (error) {
|
|
4173
|
-
return false;
|
|
4174
|
-
}
|
|
4175
|
-
|
|
4176
|
-
await $grid.clearActived();
|
|
4177
|
-
await $grid.setActiveRow(obj.row);
|
|
4178
|
-
let mainData = commonDataUtil.handleForm(requestRow);
|
|
4179
|
-
|
|
4180
|
-
delete mainData._createNickName;
|
|
4181
|
-
delete mainData._createMobile;
|
|
4182
|
-
delete mainData._modifyNickName;
|
|
4183
|
-
delete mainData._modifyMobile;
|
|
4184
|
-
delete mainData._createBy;
|
|
4185
|
-
delete mainData._modifyBy;
|
|
4186
|
-
|
|
4187
|
-
let formData = {
|
|
4188
|
-
[entity]: mainData,
|
|
4189
|
-
};
|
|
4190
|
-
Object.keys(mainData).forEach((key) => {
|
|
4191
|
-
if (key.startsWith("attachments_")) {
|
|
4192
|
-
formData[key] = mainData[key];
|
|
4193
|
-
}
|
|
4194
|
-
});
|
|
4195
|
-
|
|
4196
|
-
let reqData = {
|
|
4197
|
-
formCode: formCode,
|
|
4198
|
-
formVersion: reportTemplate.formVersion,
|
|
4199
|
-
taBm: entity,
|
|
4200
|
-
data: formData,
|
|
4201
|
-
};
|
|
4202
|
-
let saveResponse = await new Promise((resolve, reject) => {
|
|
4203
|
-
let requestTask = this.formHttp({
|
|
4204
|
-
scriptCode: scriptCode,
|
|
4205
|
-
data: reqData,
|
|
4206
|
-
successMsg: true,
|
|
4207
|
-
isConfirm: false,
|
|
4208
|
-
success: resolve,
|
|
4209
|
-
fail: (res) => {
|
|
4210
|
-
reject(new Error(res?.content || "当前行保存失败。"));
|
|
4211
|
-
},
|
|
4212
|
-
error: reject,
|
|
4213
|
-
});
|
|
4214
|
-
if (requestTask && typeof requestTask.catch === "function") {
|
|
4215
|
-
requestTask.catch(reject);
|
|
4216
|
-
}
|
|
4217
|
-
});
|
|
4218
|
-
|
|
4219
|
-
let querySavedRow = () =>
|
|
4220
|
-
new Promise((resolve, reject) => {
|
|
4221
|
-
let requestTask = this.getRowData(
|
|
4222
|
-
saveResponse.objx,
|
|
4223
|
-
resolve,
|
|
4224
|
-
(res) => {
|
|
4225
|
-
reject(new Error(res?.content || "保存结果重新查询失败。"));
|
|
4226
|
-
},
|
|
4227
|
-
reject
|
|
4228
|
-
);
|
|
4229
|
-
if (requestTask && typeof requestTask.catch === "function") {
|
|
4230
|
-
requestTask.catch(reject);
|
|
4231
|
-
}
|
|
4232
|
-
});
|
|
4233
|
-
let reconcileSavedRow = async (rowResponse) => {
|
|
4234
|
-
let responseRow = { ...(rowResponse?.objx || {}) };
|
|
4235
|
-
if (treeContext) {
|
|
4236
|
-
let { rowField } = treeContext.fields;
|
|
4237
|
-
let physicalIdField
|
|
4238
|
-
= treeContext.identityConfig.physicalIdField;
|
|
4239
|
-
let hasIdentityValue = (value) =>
|
|
4240
|
-
value !== null
|
|
4241
|
-
&& value !== undefined
|
|
4242
|
-
&& value !== "";
|
|
4243
|
-
if (
|
|
4244
|
-
treePhysicalIdWasMissing
|
|
4245
|
-
&& !hasIdentityValue(responseRow[physicalIdField])
|
|
4246
|
-
) {
|
|
4247
|
-
throw new Error(
|
|
4248
|
-
`保存响应未返回正式物理 ID 字段 ${physicalIdField}。`
|
|
4249
|
-
);
|
|
4250
|
-
}
|
|
4251
|
-
|
|
4252
|
-
let treeTableRows = this.formModel[this.fieldKeyName] || [];
|
|
4253
|
-
let currentLogicalRow = null;
|
|
4254
|
-
if (hasIdentityValue(logicalRowKey)) {
|
|
4255
|
-
currentLogicalRow = treeTableRows.find(
|
|
4256
|
-
(item) => item?._X_ROW_KEY === logicalRowKey
|
|
4257
|
-
);
|
|
4258
|
-
}
|
|
4259
|
-
if (!currentLogicalRow && treeTableRows.includes(obj.row)) {
|
|
4260
|
-
currentLogicalRow = obj.row;
|
|
4261
|
-
}
|
|
4262
|
-
if (!currentLogicalRow) {
|
|
4263
|
-
let physicalCandidates = [
|
|
4264
|
-
originalPhysicalId,
|
|
4265
|
-
responseRow[physicalIdField],
|
|
4266
|
-
obj.row?.[physicalIdField],
|
|
4267
|
-
].filter(hasIdentityValue);
|
|
4268
|
-
currentLogicalRow = treeTableRows.find(
|
|
4269
|
-
(item) =>
|
|
4270
|
-
item
|
|
4271
|
-
&& physicalCandidates.some((physicalId) =>
|
|
4272
|
-
treeKeyEquals(
|
|
4273
|
-
item[physicalIdField],
|
|
4274
|
-
physicalId
|
|
4275
|
-
)
|
|
4276
|
-
)
|
|
4277
|
-
);
|
|
4278
|
-
}
|
|
4279
|
-
if (!currentLogicalRow) {
|
|
4280
|
-
throw new Error("无法定位保存响应对应的当前树表行。");
|
|
4281
|
-
}
|
|
4282
|
-
if (!hasIdentityValue(logicalRowKey)) {
|
|
4283
|
-
logicalRowKey = currentLogicalRow._X_ROW_KEY || null;
|
|
4284
|
-
}
|
|
4285
|
-
obj.row = currentLogicalRow;
|
|
4286
|
-
|
|
4287
|
-
let responseHasTreeKey = Object.prototype.hasOwnProperty.call(
|
|
4288
|
-
responseRow,
|
|
4289
|
-
rowField
|
|
4290
|
-
);
|
|
4291
|
-
let nextTreeKey = responseHasTreeKey
|
|
4292
|
-
? responseRow[rowField]
|
|
4293
|
-
: currentLogicalRow[rowField];
|
|
4294
|
-
let wasTemporary
|
|
4295
|
-
= treeKeyWasTemporary
|
|
4296
|
-
|| isTemporaryTreeKey(
|
|
4297
|
-
currentLogicalRow,
|
|
4298
|
-
rowField,
|
|
4299
|
-
treeContext.identityConfig
|
|
4300
|
-
);
|
|
4301
|
-
if (
|
|
4302
|
-
wasTemporary
|
|
4303
|
-
&& treeContext.identityConfig.serverGeneratesRowField
|
|
4304
|
-
&& (isRootParent(nextTreeKey)
|
|
4305
|
-
|| treeKeyEquals(nextTreeKey, oldTreeKey))
|
|
4306
|
-
) {
|
|
4307
|
-
throw new Error(
|
|
4308
|
-
`保存响应未返回正式树键字段 ${rowField}。`
|
|
4309
|
-
);
|
|
4310
|
-
}
|
|
4311
|
-
|
|
4312
|
-
let isCurrentLogicalRow = (item) =>
|
|
4313
|
-
item === currentLogicalRow
|
|
4314
|
-
|| (
|
|
4315
|
-
hasIdentityValue(logicalRowKey)
|
|
4316
|
-
&& item?._X_ROW_KEY === logicalRowKey
|
|
4317
|
-
);
|
|
4318
|
-
let keyConflict = treeTableRows.some(
|
|
4319
|
-
(item) =>
|
|
4320
|
-
!isCurrentLogicalRow(item)
|
|
4321
|
-
&& treeKeyEquals(item?.[rowField], nextTreeKey)
|
|
4322
|
-
);
|
|
4323
|
-
if (keyConflict) {
|
|
4324
|
-
throw new Error(
|
|
4325
|
-
`保存响应中的树键 ${nextTreeKey} 已存在。`
|
|
4326
|
-
);
|
|
4327
|
-
}
|
|
4328
|
-
|
|
4329
|
-
let currentTreeKey = currentLogicalRow[rowField];
|
|
4330
|
-
let treeKeyChanged = !treeKeyEquals(
|
|
4331
|
-
currentTreeKey,
|
|
4332
|
-
nextTreeKey
|
|
4333
|
-
);
|
|
4334
|
-
rebuildTreeAfterSave
|
|
4335
|
-
= rebuildTreeAfterSave || treeKeyChanged;
|
|
4336
|
-
if (
|
|
4337
|
-
responseHasTreeKey
|
|
4338
|
-
&& currentTreeKey !== nextTreeKey
|
|
4339
|
-
&& !treeKeyChanged
|
|
4340
|
-
) {
|
|
4341
|
-
responseRow[rowField] = currentTreeKey;
|
|
4342
|
-
nextTreeKey = currentTreeKey;
|
|
4343
|
-
}
|
|
4344
|
-
let responsePhysicalId = responseRow[physicalIdField];
|
|
4345
|
-
let responseAlreadyApplied
|
|
4346
|
-
= treeSnapshotApplied
|
|
4347
|
-
&& !treeKeyChanged
|
|
4348
|
-
&& (
|
|
4349
|
-
!hasIdentityValue(responsePhysicalId)
|
|
4350
|
-
|| treeKeyEquals(
|
|
4351
|
-
currentLogicalRow[physicalIdField],
|
|
4352
|
-
responsePhysicalId
|
|
4353
|
-
)
|
|
4354
|
-
)
|
|
4355
|
-
&& currentLogicalRow._X_TREE_TEMP_KEY == null;
|
|
4356
|
-
let stableRowKey
|
|
4357
|
-
= currentLogicalRow._X_ROW_KEY || logicalRowKey;
|
|
4358
|
-
Object.assign(currentLogicalRow, responseRow);
|
|
4359
|
-
if (hasIdentityValue(stableRowKey)) {
|
|
4360
|
-
currentLogicalRow._X_ROW_KEY = stableRowKey;
|
|
4361
|
-
logicalRowKey = stableRowKey;
|
|
4362
|
-
}
|
|
4363
|
-
if (treeKeyChanged) {
|
|
4364
|
-
syncTreeKeyReferences(
|
|
4365
|
-
treeTableRows,
|
|
4366
|
-
currentTreeKey,
|
|
4367
|
-
nextTreeKey,
|
|
4368
|
-
{ fields: treeContext.fields }
|
|
4369
|
-
);
|
|
4370
|
-
}
|
|
4371
|
-
delete currentLogicalRow._X_TREE_TEMP_KEY;
|
|
4372
|
-
this.unregisterTreeKey(
|
|
4373
|
-
this.treeTemporaryKeyRegistry,
|
|
4374
|
-
oldTreeKey
|
|
4375
|
-
);
|
|
4376
|
-
this.treeKnownFormalKeyRegistry.add(
|
|
4377
|
-
currentLogicalRow[rowField]
|
|
4378
|
-
);
|
|
4379
|
-
|
|
4380
|
-
let reconcileGrid = this.getGridTable?.() || $grid;
|
|
4381
|
-
if (reconcileGrid?.clearActived) {
|
|
4382
|
-
await reconcileGrid.clearActived();
|
|
4383
|
-
}
|
|
4384
|
-
if (rebuildTreeAfterSave && !responseAlreadyApplied) {
|
|
4385
|
-
this.setValue(treeTableRows);
|
|
4386
|
-
treeSnapshotApplied = true;
|
|
4387
|
-
await new Promise((resolve) => this.$nextTick(resolve));
|
|
4388
|
-
}
|
|
4389
|
-
reconcileGrid = this.getGridTable?.() || reconcileGrid;
|
|
4390
|
-
if (reconcileGrid?.updateData) {
|
|
4391
|
-
await reconcileGrid.updateData();
|
|
4392
|
-
}
|
|
4393
|
-
} else {
|
|
4394
|
-
Object.assign(obj.row, responseRow);
|
|
4395
|
-
await $grid.clearActived();
|
|
4396
|
-
await $grid.updateData();
|
|
4397
|
-
}
|
|
4398
|
-
delete obj.$table.editCloneRow;
|
|
4399
|
-
return true;
|
|
4400
|
-
};
|
|
4401
|
-
let runRowReconcile = async () =>
|
|
4402
|
-
reconcileSavedRow(await querySavedRow());
|
|
4403
|
-
try {
|
|
4404
|
-
return await runRowReconcile();
|
|
4405
|
-
} catch (error) {
|
|
4406
|
-
keepSaveLocked = true;
|
|
4407
|
-
let retryPromise = null;
|
|
4408
|
-
this.treeSingleSaveReconcileTask = () => {
|
|
4409
|
-
if (retryPromise) return retryPromise;
|
|
4410
|
-
retryPromise = runRowReconcile()
|
|
4411
|
-
.then((result) => {
|
|
4412
|
-
this.treeSingleSaveReconcileTask = null;
|
|
4413
|
-
this.treeSingleSavePending = false;
|
|
4414
|
-
return result;
|
|
4415
|
-
})
|
|
4416
|
-
.catch((retryError) => {
|
|
4417
|
-
this.$message.error(
|
|
4418
|
-
retryError?.message
|
|
4419
|
-
|| "保存结果仍未能重新加载,请手动刷新后再操作。"
|
|
4420
|
-
);
|
|
4421
|
-
return false;
|
|
4422
|
-
})
|
|
4423
|
-
.finally(() => {
|
|
4424
|
-
retryPromise = null;
|
|
4425
|
-
});
|
|
4426
|
-
return retryPromise;
|
|
4427
|
-
};
|
|
4428
|
-
this.$message.error(
|
|
4429
|
-
error?.message
|
|
4430
|
-
|| "保存已成功,但结果重新加载失败,请重试。"
|
|
4431
|
-
);
|
|
4432
|
-
return false;
|
|
4433
|
-
}
|
|
4434
|
-
} catch (error) {
|
|
4435
|
-
if (error?.treeReloadFailed) {
|
|
4436
|
-
keepSaveLocked = true;
|
|
4437
|
-
installReloadRetry();
|
|
4438
|
-
this.$message.error(
|
|
4439
|
-
"树键已更新,但重新加载失败,请手动刷新后再操作。"
|
|
4440
|
-
);
|
|
4441
|
-
return false;
|
|
4442
|
-
}
|
|
4443
|
-
if (!keepSaveLocked) {
|
|
4444
|
-
this.$message.error(
|
|
4445
|
-
error?.message || "当前行保存失败。"
|
|
4446
|
-
);
|
|
4447
|
-
}
|
|
4448
|
-
return false;
|
|
4449
|
-
} finally {
|
|
4450
|
-
if (!keepSaveLocked) {
|
|
4451
|
-
this.treeSingleSavePending = false;
|
|
4452
|
-
}
|
|
4453
|
-
}
|
|
4454
|
-
},
|
|
4455
|
-
/** @param {*} dataId 行数据 id。@param {Function} callback 查询成功回调。加载保存后的完整行。 */
|
|
4456
|
-
getRowData(dataId, callback, fail, error) {
|
|
4055
|
+
async saveEditRow(obj) {
|
|
4056
|
+
let formRef = this.getFormRef();
|
|
4057
|
+
let formConfig = this.formConfig;
|
|
4058
|
+
let entity = formConfig.entity;
|
|
4059
|
+
if (!entity) return;
|
|
4060
|
+
let reportTemplate = formRef?.reportTemplate;
|
|
4061
|
+
let formCode = reportTemplate?.formCode;
|
|
4062
|
+
let scriptCode = formConfig.saveScriptCode || "saveUpdate";
|
|
4063
|
+
|
|
4064
|
+
let $grid = obj.$table.$xegrid;
|
|
4065
|
+
if (typeof this.treeSingleSaveReconcileTask === "function") {
|
|
4066
|
+
return this.treeSingleSaveReconcileTask();
|
|
4067
|
+
}
|
|
4068
|
+
if (this.treeSingleSavePending) {
|
|
4069
|
+
this.$message.warning("当前行正在保存,请勿重复操作。");
|
|
4070
|
+
return false;
|
|
4071
|
+
}
|
|
4072
|
+
this.treeSingleSavePending = true;
|
|
4073
|
+
let keepSaveLocked = false;
|
|
4074
|
+
let reloadMethod
|
|
4075
|
+
= typeof formRef.reloadSavedFormData === "function"
|
|
4076
|
+
? formRef.reloadSavedFormData
|
|
4077
|
+
: formRef.reloadForm;
|
|
4078
|
+
let installReloadRetry = () => {
|
|
4079
|
+
let retryPromise = null;
|
|
4080
|
+
this.treeSingleSaveReconcileTask = () => {
|
|
4081
|
+
if (retryPromise) return retryPromise;
|
|
4082
|
+
retryPromise = (async () => {
|
|
4083
|
+
try {
|
|
4084
|
+
await reloadMethod.call(formRef);
|
|
4085
|
+
delete obj.$table.editCloneRow;
|
|
4086
|
+
this.treeSingleSaveReconcileTask = null;
|
|
4087
|
+
this.treeSingleSavePending = false;
|
|
4088
|
+
return true;
|
|
4089
|
+
} catch (error) {
|
|
4090
|
+
this.$message.error(
|
|
4091
|
+
"重新加载仍未成功,请手动刷新后再操作。"
|
|
4092
|
+
);
|
|
4093
|
+
return false;
|
|
4094
|
+
} finally {
|
|
4095
|
+
retryPromise = null;
|
|
4096
|
+
}
|
|
4097
|
+
})();
|
|
4098
|
+
return retryPromise;
|
|
4099
|
+
};
|
|
4100
|
+
};
|
|
4101
|
+
let isTreeTable = this.widget.options.isTreeTable || false;
|
|
4102
|
+
let treeContext = isTreeTable
|
|
4103
|
+
? this.getTreeContext($grid, { mode: "single" })
|
|
4104
|
+
: null;
|
|
4105
|
+
let oldTreeKey = null;
|
|
4106
|
+
let rebuildTreeAfterSave = false;
|
|
4107
|
+
let treePhysicalIdWasMissing = false;
|
|
4108
|
+
let treeKeyWasTemporary = false;
|
|
4109
|
+
let treeSnapshotApplied = false;
|
|
4110
|
+
let logicalRowKey = obj.row?._X_ROW_KEY || null;
|
|
4111
|
+
let originalPhysicalId = null;
|
|
4112
|
+
try {
|
|
4113
|
+
let valid = await new Promise((resolve, reject) => {
|
|
4114
|
+
try {
|
|
4115
|
+
formRef.validate(resolve);
|
|
4116
|
+
} catch (error) {
|
|
4117
|
+
reject(error);
|
|
4118
|
+
}
|
|
4119
|
+
});
|
|
4120
|
+
if (!valid) return false;
|
|
4121
|
+
|
|
4122
|
+
let requestRow = obj.row;
|
|
4123
|
+
if (treeContext) {
|
|
4124
|
+
let blockReason = this.getTreeSingleSaveBlockReason(
|
|
4125
|
+
obj.row,
|
|
4126
|
+
$grid
|
|
4127
|
+
);
|
|
4128
|
+
if (blockReason) {
|
|
4129
|
+
this.$message.error(blockReason);
|
|
4130
|
+
return false;
|
|
4131
|
+
}
|
|
4132
|
+
let rowField = treeContext.fields.rowField;
|
|
4133
|
+
let currentTreeKey = obj.row[rowField];
|
|
4134
|
+
let editCloneRow = obj.$table.editCloneRow;
|
|
4135
|
+
let previousTreeKey = editCloneRow?.[rowField];
|
|
4136
|
+
if (
|
|
4137
|
+
obj.row._X_TREE_TEMP_KEY != null
|
|
4138
|
+
&& !treeKeyEquals(
|
|
4139
|
+
obj.row._X_TREE_TEMP_KEY,
|
|
4140
|
+
currentTreeKey
|
|
4141
|
+
)
|
|
4142
|
+
) {
|
|
4143
|
+
previousTreeKey = obj.row._X_TREE_TEMP_KEY;
|
|
4144
|
+
}
|
|
4145
|
+
if (
|
|
4146
|
+
previousTreeKey !== undefined
|
|
4147
|
+
&& previousTreeKey !== null
|
|
4148
|
+
&& !treeKeyEquals(previousTreeKey, currentTreeKey)
|
|
4149
|
+
) {
|
|
4150
|
+
let changeResult = await this.changeTreeRowField(
|
|
4151
|
+
obj.row,
|
|
4152
|
+
currentTreeKey,
|
|
4153
|
+
{
|
|
4154
|
+
oldValue: previousTreeKey,
|
|
4155
|
+
$grid,
|
|
4156
|
+
reason: "single-save",
|
|
4157
|
+
}
|
|
4158
|
+
);
|
|
4159
|
+
if (changeResult.transactional) {
|
|
4160
|
+
delete obj.$table.editCloneRow;
|
|
4161
|
+
return true;
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
oldTreeKey = obj.row[rowField];
|
|
4165
|
+
let physicalIdField
|
|
4166
|
+
= treeContext.identityConfig.physicalIdField;
|
|
4167
|
+
let physicalId = obj.row[physicalIdField];
|
|
4168
|
+
originalPhysicalId = physicalId;
|
|
4169
|
+
treeKeyWasTemporary = isTemporaryTreeKey(
|
|
4170
|
+
obj.row,
|
|
4171
|
+
rowField,
|
|
4172
|
+
treeContext.identityConfig
|
|
4173
|
+
);
|
|
4174
|
+
treePhysicalIdWasMissing
|
|
4175
|
+
= physicalId == null
|
|
4176
|
+
|| physicalId === ""
|
|
4177
|
+
|| (
|
|
4178
|
+
physicalIdField === rowField
|
|
4179
|
+
&& treeKeyWasTemporary
|
|
4180
|
+
);
|
|
4181
|
+
rebuildTreeAfterSave
|
|
4182
|
+
= treePhysicalIdWasMissing
|
|
4183
|
+
|| treeKeyWasTemporary;
|
|
4184
|
+
requestRow = sanitizeTreeRow(
|
|
4185
|
+
this.$baseLodash.cloneDeep(obj.row),
|
|
4186
|
+
treeContext
|
|
4187
|
+
);
|
|
4188
|
+
}
|
|
4189
|
+
|
|
4190
|
+
try {
|
|
4191
|
+
await this.$baseConfirm("您确定要保存吗?");
|
|
4192
|
+
} catch (error) {
|
|
4193
|
+
return false;
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
await $grid.clearActived();
|
|
4197
|
+
await $grid.setActiveRow(obj.row);
|
|
4198
|
+
let mainData = commonDataUtil.handleForm(requestRow);
|
|
4199
|
+
|
|
4200
|
+
delete mainData._createNickName;
|
|
4201
|
+
delete mainData._createMobile;
|
|
4202
|
+
delete mainData._modifyNickName;
|
|
4203
|
+
delete mainData._modifyMobile;
|
|
4204
|
+
delete mainData._createBy;
|
|
4205
|
+
delete mainData._modifyBy;
|
|
4206
|
+
|
|
4207
|
+
let formData = {
|
|
4208
|
+
[entity]: mainData,
|
|
4209
|
+
};
|
|
4210
|
+
Object.keys(mainData).forEach((key) => {
|
|
4211
|
+
if (key.startsWith("attachments_")) {
|
|
4212
|
+
formData[key] = mainData[key];
|
|
4213
|
+
}
|
|
4214
|
+
});
|
|
4215
|
+
|
|
4216
|
+
let reqData = {
|
|
4217
|
+
formCode: formCode,
|
|
4218
|
+
formVersion: reportTemplate.formVersion,
|
|
4219
|
+
taBm: entity,
|
|
4220
|
+
data: formData,
|
|
4221
|
+
};
|
|
4222
|
+
let saveResponse = await new Promise((resolve, reject) => {
|
|
4223
|
+
let requestTask = this.formHttp({
|
|
4224
|
+
scriptCode: scriptCode,
|
|
4225
|
+
data: reqData,
|
|
4226
|
+
successMsg: true,
|
|
4227
|
+
isConfirm: false,
|
|
4228
|
+
success: resolve,
|
|
4229
|
+
fail: (res) => {
|
|
4230
|
+
reject(new Error(res?.content || "当前行保存失败。"));
|
|
4231
|
+
},
|
|
4232
|
+
error: reject,
|
|
4233
|
+
});
|
|
4234
|
+
if (requestTask && typeof requestTask.catch === "function") {
|
|
4235
|
+
requestTask.catch(reject);
|
|
4236
|
+
}
|
|
4237
|
+
});
|
|
4238
|
+
|
|
4239
|
+
let querySavedRow = () =>
|
|
4240
|
+
new Promise((resolve, reject) => {
|
|
4241
|
+
let requestTask = this.getRowData(
|
|
4242
|
+
saveResponse.objx,
|
|
4243
|
+
resolve,
|
|
4244
|
+
(res) => {
|
|
4245
|
+
reject(new Error(res?.content || "保存结果重新查询失败。"));
|
|
4246
|
+
},
|
|
4247
|
+
reject
|
|
4248
|
+
);
|
|
4249
|
+
if (requestTask && typeof requestTask.catch === "function") {
|
|
4250
|
+
requestTask.catch(reject);
|
|
4251
|
+
}
|
|
4252
|
+
});
|
|
4253
|
+
let reconcileSavedRow = async (rowResponse) => {
|
|
4254
|
+
let responseRow = { ...(rowResponse?.objx || {}) };
|
|
4255
|
+
if (treeContext) {
|
|
4256
|
+
let { rowField } = treeContext.fields;
|
|
4257
|
+
let physicalIdField
|
|
4258
|
+
= treeContext.identityConfig.physicalIdField;
|
|
4259
|
+
let hasIdentityValue = (value) =>
|
|
4260
|
+
value !== null
|
|
4261
|
+
&& value !== undefined
|
|
4262
|
+
&& value !== "";
|
|
4263
|
+
if (
|
|
4264
|
+
treePhysicalIdWasMissing
|
|
4265
|
+
&& !hasIdentityValue(responseRow[physicalIdField])
|
|
4266
|
+
) {
|
|
4267
|
+
throw new Error(
|
|
4268
|
+
`保存响应未返回正式物理 ID 字段 ${physicalIdField}。`
|
|
4269
|
+
);
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
let treeTableRows = this.formModel[this.fieldKeyName] || [];
|
|
4273
|
+
let currentLogicalRow = null;
|
|
4274
|
+
if (hasIdentityValue(logicalRowKey)) {
|
|
4275
|
+
currentLogicalRow = treeTableRows.find(
|
|
4276
|
+
(item) => item?._X_ROW_KEY === logicalRowKey
|
|
4277
|
+
);
|
|
4278
|
+
}
|
|
4279
|
+
if (!currentLogicalRow && treeTableRows.includes(obj.row)) {
|
|
4280
|
+
currentLogicalRow = obj.row;
|
|
4281
|
+
}
|
|
4282
|
+
if (!currentLogicalRow) {
|
|
4283
|
+
let physicalCandidates = [
|
|
4284
|
+
originalPhysicalId,
|
|
4285
|
+
responseRow[physicalIdField],
|
|
4286
|
+
obj.row?.[physicalIdField],
|
|
4287
|
+
].filter(hasIdentityValue);
|
|
4288
|
+
currentLogicalRow = treeTableRows.find(
|
|
4289
|
+
(item) =>
|
|
4290
|
+
item
|
|
4291
|
+
&& physicalCandidates.some((physicalId) =>
|
|
4292
|
+
treeKeyEquals(
|
|
4293
|
+
item[physicalIdField],
|
|
4294
|
+
physicalId
|
|
4295
|
+
)
|
|
4296
|
+
)
|
|
4297
|
+
);
|
|
4298
|
+
}
|
|
4299
|
+
if (!currentLogicalRow) {
|
|
4300
|
+
throw new Error("无法定位保存响应对应的当前树表行。");
|
|
4301
|
+
}
|
|
4302
|
+
if (!hasIdentityValue(logicalRowKey)) {
|
|
4303
|
+
logicalRowKey = currentLogicalRow._X_ROW_KEY || null;
|
|
4304
|
+
}
|
|
4305
|
+
obj.row = currentLogicalRow;
|
|
4306
|
+
|
|
4307
|
+
let responseHasTreeKey = Object.prototype.hasOwnProperty.call(
|
|
4308
|
+
responseRow,
|
|
4309
|
+
rowField
|
|
4310
|
+
);
|
|
4311
|
+
let nextTreeKey = responseHasTreeKey
|
|
4312
|
+
? responseRow[rowField]
|
|
4313
|
+
: currentLogicalRow[rowField];
|
|
4314
|
+
let wasTemporary
|
|
4315
|
+
= treeKeyWasTemporary
|
|
4316
|
+
|| isTemporaryTreeKey(
|
|
4317
|
+
currentLogicalRow,
|
|
4318
|
+
rowField,
|
|
4319
|
+
treeContext.identityConfig
|
|
4320
|
+
);
|
|
4321
|
+
if (
|
|
4322
|
+
wasTemporary
|
|
4323
|
+
&& treeContext.identityConfig.serverGeneratesRowField
|
|
4324
|
+
&& (isRootParent(nextTreeKey)
|
|
4325
|
+
|| treeKeyEquals(nextTreeKey, oldTreeKey))
|
|
4326
|
+
) {
|
|
4327
|
+
throw new Error(
|
|
4328
|
+
`保存响应未返回正式树键字段 ${rowField}。`
|
|
4329
|
+
);
|
|
4330
|
+
}
|
|
4331
|
+
|
|
4332
|
+
let isCurrentLogicalRow = (item) =>
|
|
4333
|
+
item === currentLogicalRow
|
|
4334
|
+
|| (
|
|
4335
|
+
hasIdentityValue(logicalRowKey)
|
|
4336
|
+
&& item?._X_ROW_KEY === logicalRowKey
|
|
4337
|
+
);
|
|
4338
|
+
let keyConflict = treeTableRows.some(
|
|
4339
|
+
(item) =>
|
|
4340
|
+
!isCurrentLogicalRow(item)
|
|
4341
|
+
&& treeKeyEquals(item?.[rowField], nextTreeKey)
|
|
4342
|
+
);
|
|
4343
|
+
if (keyConflict) {
|
|
4344
|
+
throw new Error(
|
|
4345
|
+
`保存响应中的树键 ${nextTreeKey} 已存在。`
|
|
4346
|
+
);
|
|
4347
|
+
}
|
|
4348
|
+
|
|
4349
|
+
let currentTreeKey = currentLogicalRow[rowField];
|
|
4350
|
+
let treeKeyChanged = !treeKeyEquals(
|
|
4351
|
+
currentTreeKey,
|
|
4352
|
+
nextTreeKey
|
|
4353
|
+
);
|
|
4354
|
+
rebuildTreeAfterSave
|
|
4355
|
+
= rebuildTreeAfterSave || treeKeyChanged;
|
|
4356
|
+
if (
|
|
4357
|
+
responseHasTreeKey
|
|
4358
|
+
&& currentTreeKey !== nextTreeKey
|
|
4359
|
+
&& !treeKeyChanged
|
|
4360
|
+
) {
|
|
4361
|
+
responseRow[rowField] = currentTreeKey;
|
|
4362
|
+
nextTreeKey = currentTreeKey;
|
|
4363
|
+
}
|
|
4364
|
+
let responsePhysicalId = responseRow[physicalIdField];
|
|
4365
|
+
let responseAlreadyApplied
|
|
4366
|
+
= treeSnapshotApplied
|
|
4367
|
+
&& !treeKeyChanged
|
|
4368
|
+
&& (
|
|
4369
|
+
!hasIdentityValue(responsePhysicalId)
|
|
4370
|
+
|| treeKeyEquals(
|
|
4371
|
+
currentLogicalRow[physicalIdField],
|
|
4372
|
+
responsePhysicalId
|
|
4373
|
+
)
|
|
4374
|
+
)
|
|
4375
|
+
&& currentLogicalRow._X_TREE_TEMP_KEY == null;
|
|
4376
|
+
let stableRowKey
|
|
4377
|
+
= currentLogicalRow._X_ROW_KEY || logicalRowKey;
|
|
4378
|
+
Object.assign(currentLogicalRow, responseRow);
|
|
4379
|
+
if (hasIdentityValue(stableRowKey)) {
|
|
4380
|
+
currentLogicalRow._X_ROW_KEY = stableRowKey;
|
|
4381
|
+
logicalRowKey = stableRowKey;
|
|
4382
|
+
}
|
|
4383
|
+
if (treeKeyChanged) {
|
|
4384
|
+
syncTreeKeyReferences(
|
|
4385
|
+
treeTableRows,
|
|
4386
|
+
currentTreeKey,
|
|
4387
|
+
nextTreeKey,
|
|
4388
|
+
{ fields: treeContext.fields }
|
|
4389
|
+
);
|
|
4390
|
+
}
|
|
4391
|
+
delete currentLogicalRow._X_TREE_TEMP_KEY;
|
|
4392
|
+
this.unregisterTreeKey(
|
|
4393
|
+
this.treeTemporaryKeyRegistry,
|
|
4394
|
+
oldTreeKey
|
|
4395
|
+
);
|
|
4396
|
+
this.treeKnownFormalKeyRegistry.add(
|
|
4397
|
+
currentLogicalRow[rowField]
|
|
4398
|
+
);
|
|
4399
|
+
|
|
4400
|
+
let reconcileGrid = this.getGridTable?.() || $grid;
|
|
4401
|
+
if (reconcileGrid?.clearActived) {
|
|
4402
|
+
await reconcileGrid.clearActived();
|
|
4403
|
+
}
|
|
4404
|
+
if (rebuildTreeAfterSave && !responseAlreadyApplied) {
|
|
4405
|
+
this.setValue(treeTableRows);
|
|
4406
|
+
treeSnapshotApplied = true;
|
|
4407
|
+
await new Promise((resolve) => this.$nextTick(resolve));
|
|
4408
|
+
}
|
|
4409
|
+
reconcileGrid = this.getGridTable?.() || reconcileGrid;
|
|
4410
|
+
if (reconcileGrid?.updateData) {
|
|
4411
|
+
await reconcileGrid.updateData();
|
|
4412
|
+
}
|
|
4413
|
+
} else {
|
|
4414
|
+
Object.assign(obj.row, responseRow);
|
|
4415
|
+
await $grid.clearActived();
|
|
4416
|
+
await $grid.updateData();
|
|
4417
|
+
}
|
|
4418
|
+
delete obj.$table.editCloneRow;
|
|
4419
|
+
return true;
|
|
4420
|
+
};
|
|
4421
|
+
let runRowReconcile = async () =>
|
|
4422
|
+
reconcileSavedRow(await querySavedRow());
|
|
4423
|
+
try {
|
|
4424
|
+
return await runRowReconcile();
|
|
4425
|
+
} catch (error) {
|
|
4426
|
+
keepSaveLocked = true;
|
|
4427
|
+
let retryPromise = null;
|
|
4428
|
+
this.treeSingleSaveReconcileTask = () => {
|
|
4429
|
+
if (retryPromise) return retryPromise;
|
|
4430
|
+
retryPromise = runRowReconcile()
|
|
4431
|
+
.then((result) => {
|
|
4432
|
+
this.treeSingleSaveReconcileTask = null;
|
|
4433
|
+
this.treeSingleSavePending = false;
|
|
4434
|
+
return result;
|
|
4435
|
+
})
|
|
4436
|
+
.catch((retryError) => {
|
|
4437
|
+
this.$message.error(
|
|
4438
|
+
retryError?.message
|
|
4439
|
+
|| "保存结果仍未能重新加载,请手动刷新后再操作。"
|
|
4440
|
+
);
|
|
4441
|
+
return false;
|
|
4442
|
+
})
|
|
4443
|
+
.finally(() => {
|
|
4444
|
+
retryPromise = null;
|
|
4445
|
+
});
|
|
4446
|
+
return retryPromise;
|
|
4447
|
+
};
|
|
4448
|
+
this.$message.error(
|
|
4449
|
+
error?.message
|
|
4450
|
+
|| "保存已成功,但结果重新加载失败,请重试。"
|
|
4451
|
+
);
|
|
4452
|
+
return false;
|
|
4453
|
+
}
|
|
4454
|
+
} catch (error) {
|
|
4455
|
+
if (error?.treeReloadFailed) {
|
|
4456
|
+
keepSaveLocked = true;
|
|
4457
|
+
installReloadRetry();
|
|
4458
|
+
this.$message.error(
|
|
4459
|
+
"树键已更新,但重新加载失败,请手动刷新后再操作。"
|
|
4460
|
+
);
|
|
4461
|
+
return false;
|
|
4462
|
+
}
|
|
4463
|
+
if (!keepSaveLocked) {
|
|
4464
|
+
this.$message.error(
|
|
4465
|
+
error?.message || "当前行保存失败。"
|
|
4466
|
+
);
|
|
4467
|
+
}
|
|
4468
|
+
return false;
|
|
4469
|
+
} finally {
|
|
4470
|
+
if (!keepSaveLocked) {
|
|
4471
|
+
this.treeSingleSavePending = false;
|
|
4472
|
+
}
|
|
4473
|
+
}
|
|
4474
|
+
},
|
|
4475
|
+
/** @param {*} dataId 行数据 id。@param {Function} callback 查询成功回调。加载保存后的完整行。 */
|
|
4476
|
+
getRowData(dataId, callback, fail, error) {
|
|
4457
4477
|
let reportTemplate = this.getFormRef()?.reportTemplate;
|
|
4458
4478
|
let formCode = reportTemplate.formCode;
|
|
4459
4479
|
let formConfig = this.formConfig;
|
|
@@ -4461,7 +4481,7 @@ modules = {
|
|
|
4461
4481
|
let entity = formConfig.entity;
|
|
4462
4482
|
let scriptCode = formConfig.formScriptCode || "getOne";
|
|
4463
4483
|
let defaultOption = this.getHttpConfigForUser();
|
|
4464
|
-
return this.formHttp({
|
|
4484
|
+
return this.formHttp({
|
|
4465
4485
|
scriptCode: scriptCode,
|
|
4466
4486
|
data: {
|
|
4467
4487
|
formCode: formCode,
|
|
@@ -4472,12 +4492,12 @@ modules = {
|
|
|
4472
4492
|
},
|
|
4473
4493
|
},
|
|
4474
4494
|
...defaultOption,
|
|
4475
|
-
success: (res) => {
|
|
4476
|
-
callback && callback(res);
|
|
4477
|
-
},
|
|
4478
|
-
fail,
|
|
4479
|
-
error,
|
|
4480
|
-
});
|
|
4495
|
+
success: (res) => {
|
|
4496
|
+
callback && callback(res);
|
|
4497
|
+
},
|
|
4498
|
+
fail,
|
|
4499
|
+
error,
|
|
4500
|
+
});
|
|
4481
4501
|
},
|
|
4482
4502
|
/** @param {Object} rowData 新行数据。@param {Object} obj 父行参数。@param {Boolean} toTop 是否插到顶部。 */
|
|
4483
4503
|
addChildTreeRow(rowData, obj, toTop) {
|
|
@@ -4504,12 +4524,12 @@ modules = {
|
|
|
4504
4524
|
let isEditTable = this.widget.options.isEditTable || false;
|
|
4505
4525
|
let parent = obj?.row;
|
|
4506
4526
|
let $grid = this.getGridTable();
|
|
4507
|
-
if (isEditTable && this.hasEditingRow($grid, 1)) {
|
|
4508
|
-
return false;
|
|
4509
|
-
}
|
|
4510
|
-
let treeContext = this.getTreeContext($grid);
|
|
4511
|
-
let { rowField, parentField } = treeContext.fields;
|
|
4512
|
-
let newRow = {};
|
|
4527
|
+
if (isEditTable && this.hasEditingRow($grid, 1)) {
|
|
4528
|
+
return false;
|
|
4529
|
+
}
|
|
4530
|
+
let treeContext = this.getTreeContext($grid);
|
|
4531
|
+
let { rowField, parentField } = treeContext.fields;
|
|
4532
|
+
let newRow = {};
|
|
4513
4533
|
let originOption = $grid.params.originOption;
|
|
4514
4534
|
let editDefaultRow;
|
|
4515
4535
|
if (originOption.editDefaultRow) {
|
|
@@ -4520,27 +4540,27 @@ modules = {
|
|
|
4520
4540
|
}
|
|
4521
4541
|
}
|
|
4522
4542
|
|
|
4523
|
-
let newData = this.createNewTableData(isEditTable);
|
|
4524
|
-
newRow = Object.assign({}, newData, editDefaultRow, rowData);
|
|
4525
|
-
newRow[treeContext.identityConfig.physicalIdField] = null;
|
|
4526
|
-
this.ensureNewTreeRowKey(newRow, treeContext);
|
|
4527
|
-
if (!toSibling) {
|
|
4528
|
-
if (parent && isRootParent(parent[rowField])) {
|
|
4529
|
-
this.$message.error("父节点缺少有效树键,无法新增子节点。");
|
|
4530
|
-
return false;
|
|
4531
|
-
}
|
|
4532
|
-
newRow[parentField] = parent
|
|
4533
|
-
? parent[rowField]
|
|
4534
|
-
: treeContext.identityConfig.rootParentValue;
|
|
4535
|
-
} else {
|
|
4536
|
-
let siblingParentValue = obj?.row[parentField];
|
|
4537
|
-
newRow[parentField] = isRootParent(siblingParentValue)
|
|
4538
|
-
? treeContext.identityConfig.rootParentValue
|
|
4539
|
-
: siblingParentValue;
|
|
4540
|
-
}
|
|
4541
|
-
this.validateNewTreeRows([newRow], treeContext);
|
|
4542
|
-
|
|
4543
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4543
|
+
let newData = this.createNewTableData(isEditTable);
|
|
4544
|
+
newRow = Object.assign({}, newData, editDefaultRow, rowData);
|
|
4545
|
+
newRow[treeContext.identityConfig.physicalIdField] = null;
|
|
4546
|
+
this.ensureNewTreeRowKey(newRow, treeContext);
|
|
4547
|
+
if (!toSibling) {
|
|
4548
|
+
if (parent && isRootParent(parent[rowField])) {
|
|
4549
|
+
this.$message.error("父节点缺少有效树键,无法新增子节点。");
|
|
4550
|
+
return false;
|
|
4551
|
+
}
|
|
4552
|
+
newRow[parentField] = parent
|
|
4553
|
+
? parent[rowField]
|
|
4554
|
+
: treeContext.identityConfig.rootParentValue;
|
|
4555
|
+
} else {
|
|
4556
|
+
let siblingParentValue = obj?.row[parentField];
|
|
4557
|
+
newRow[parentField] = isRootParent(siblingParentValue)
|
|
4558
|
+
? treeContext.identityConfig.rootParentValue
|
|
4559
|
+
: siblingParentValue;
|
|
4560
|
+
}
|
|
4561
|
+
this.validateNewTreeRows([newRow], treeContext);
|
|
4562
|
+
|
|
4563
|
+
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4544
4564
|
if (!parent) {
|
|
4545
4565
|
if (toEnd === true) {
|
|
4546
4566
|
tableRows.push(newRow);
|
|
@@ -4556,9 +4576,9 @@ modules = {
|
|
|
4556
4576
|
}
|
|
4557
4577
|
this.setValue(tableRows);
|
|
4558
4578
|
this.$nextTick(() => {
|
|
4559
|
-
this.handleWbs();
|
|
4560
|
-
if (isEditTable) {
|
|
4561
|
-
this.setActiveRowById($grid, newRow[rowField]);
|
|
4579
|
+
this.handleWbs();
|
|
4580
|
+
if (isEditTable) {
|
|
4581
|
+
this.setActiveRowById($grid, newRow[rowField]);
|
|
4562
4582
|
}
|
|
4563
4583
|
});
|
|
4564
4584
|
|
|
@@ -4580,9 +4600,9 @@ modules = {
|
|
|
4580
4600
|
this.$nextTick(() => {
|
|
4581
4601
|
this.handleWbs();
|
|
4582
4602
|
// setValue 已浅克隆所有行,obj.row 是失效引用,须按 _X_ROW_KEY 找回新行
|
|
4583
|
-
this.setTreeExpandByRowKey($grid, obj.row._X_ROW_KEY);
|
|
4584
|
-
if (isEditTable) {
|
|
4585
|
-
this.setActiveRowById($grid, newRow[rowField]);
|
|
4603
|
+
this.setTreeExpandByRowKey($grid, obj.row._X_ROW_KEY);
|
|
4604
|
+
if (isEditTable) {
|
|
4605
|
+
this.setActiveRowById($grid, newRow[rowField]);
|
|
4586
4606
|
}
|
|
4587
4607
|
});
|
|
4588
4608
|
});
|
|
@@ -4616,16 +4636,16 @@ modules = {
|
|
|
4616
4636
|
addTreeRows(rowsData, obj, field, sanitize) {
|
|
4617
4637
|
if (!Array.isArray(rowsData) || !rowsData.length) {
|
|
4618
4638
|
return;
|
|
4619
|
-
}
|
|
4620
|
-
let $grid = this.getGridTable();
|
|
4621
|
-
let parent = obj?.row;
|
|
4622
|
-
let treeContext = this.getTreeContext($grid);
|
|
4623
|
-
let { rowField, parentField } = treeContext.fields;
|
|
4624
|
-
if (parent && isRootParent(parent[rowField])) {
|
|
4625
|
-
this.$message.error("父节点缺少有效树键,无法新增子节点。");
|
|
4626
|
-
return false;
|
|
4627
|
-
}
|
|
4628
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4639
|
+
}
|
|
4640
|
+
let $grid = this.getGridTable();
|
|
4641
|
+
let parent = obj?.row;
|
|
4642
|
+
let treeContext = this.getTreeContext($grid);
|
|
4643
|
+
let { rowField, parentField } = treeContext.fields;
|
|
4644
|
+
if (parent && isRootParent(parent[rowField])) {
|
|
4645
|
+
this.$message.error("父节点缺少有效树键,无法新增子节点。");
|
|
4646
|
+
return false;
|
|
4647
|
+
}
|
|
4648
|
+
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4629
4649
|
let items = rowsData;
|
|
4630
4650
|
if (field) {
|
|
4631
4651
|
let keys = tableRows.map((item) => item[field] + "");
|
|
@@ -4642,29 +4662,29 @@ modules = {
|
|
|
4642
4662
|
} else {
|
|
4643
4663
|
editDefaultRow = originOption.editDefaultRow || {};
|
|
4644
4664
|
}
|
|
4645
|
-
}
|
|
4646
|
-
let newData = this.createNewTableData(false);
|
|
4647
|
-
let extraStrip = Array.isArray(sanitize) ? sanitize : null;
|
|
4648
|
-
let newRows = [];
|
|
4649
|
-
items.forEach((rowData) => {
|
|
4650
|
-
// 复制来的数据先剔除系统字段,避免旧审计/外键随 assign 泄入
|
|
4651
|
-
let source = rowData;
|
|
4652
|
-
if (sanitize) {
|
|
4653
|
-
source = this.stripRowSystemFields(rowData, extraStrip);
|
|
4654
|
-
}
|
|
4655
|
-
let newRow = Object.assign({}, newData, editDefaultRow, source);
|
|
4656
|
-
newRow[treeContext.identityConfig.physicalIdField] = null;
|
|
4657
|
-
this.ensureNewTreeRowKey(newRow, treeContext);
|
|
4658
|
-
if (parentField) {
|
|
4659
|
-
newRow[parentField] = parent
|
|
4660
|
-
? parent[rowField]
|
|
4661
|
-
: treeContext.identityConfig.rootParentValue;
|
|
4662
|
-
}
|
|
4663
|
-
newRows.push(newRow);
|
|
4664
|
-
});
|
|
4665
|
-
this.validateNewTreeRows(newRows, treeContext);
|
|
4666
|
-
tableRows.push(...newRows);
|
|
4667
|
-
this.setValue(tableRows);
|
|
4665
|
+
}
|
|
4666
|
+
let newData = this.createNewTableData(false);
|
|
4667
|
+
let extraStrip = Array.isArray(sanitize) ? sanitize : null;
|
|
4668
|
+
let newRows = [];
|
|
4669
|
+
items.forEach((rowData) => {
|
|
4670
|
+
// 复制来的数据先剔除系统字段,避免旧审计/外键随 assign 泄入
|
|
4671
|
+
let source = rowData;
|
|
4672
|
+
if (sanitize) {
|
|
4673
|
+
source = this.stripRowSystemFields(rowData, extraStrip);
|
|
4674
|
+
}
|
|
4675
|
+
let newRow = Object.assign({}, newData, editDefaultRow, source);
|
|
4676
|
+
newRow[treeContext.identityConfig.physicalIdField] = null;
|
|
4677
|
+
this.ensureNewTreeRowKey(newRow, treeContext);
|
|
4678
|
+
if (parentField) {
|
|
4679
|
+
newRow[parentField] = parent
|
|
4680
|
+
? parent[rowField]
|
|
4681
|
+
: treeContext.identityConfig.rootParentValue;
|
|
4682
|
+
}
|
|
4683
|
+
newRows.push(newRow);
|
|
4684
|
+
});
|
|
4685
|
+
this.validateNewTreeRows(newRows, treeContext);
|
|
4686
|
+
tableRows.push(...newRows);
|
|
4687
|
+
this.setValue(tableRows);
|
|
4668
4688
|
this.$nextTick(() => {
|
|
4669
4689
|
this.handleWbs();
|
|
4670
4690
|
if (parent) {
|
|
@@ -4681,36 +4701,36 @@ modules = {
|
|
|
4681
4701
|
* @returns {Set} 后代行的 _X_ROW_KEY 集合。
|
|
4682
4702
|
*/
|
|
4683
4703
|
collectDescendantKeys(row, tableRows) {
|
|
4684
|
-
let $grid = this.getGridTable();
|
|
4685
|
-
let isTreeTable = this.widget.options.isTreeTable || false;
|
|
4686
|
-
let treeFields = this.getTreeFields($grid);
|
|
4687
|
-
let childFields = [
|
|
4688
|
-
treeFields.childrenField,
|
|
4689
|
-
treeFields.mapChildrenField,
|
|
4690
|
-
].filter((field, index, values) => field && values.indexOf(field) === index);
|
|
4691
|
-
let keys = new Set();
|
|
4692
|
-
let visited = new WeakSet();
|
|
4693
|
-
// 若数据是嵌套结构,收集 children 下的子节点
|
|
4694
|
-
let loopDo = (item) => {
|
|
4695
|
-
if (!item || typeof item !== "object" || visited.has(item)) {
|
|
4696
|
-
return;
|
|
4697
|
-
}
|
|
4698
|
-
visited.add(item);
|
|
4699
|
-
childFields.forEach((childrenField) => {
|
|
4700
|
-
if (!item || !Array.isArray(item[childrenField])) {
|
|
4701
|
-
return;
|
|
4702
|
-
}
|
|
4703
|
-
item[childrenField].forEach((subItem) => {
|
|
4704
|
-
if (subItem && subItem._X_ROW_KEY) keys.add(subItem._X_ROW_KEY);
|
|
4705
|
-
loopDo(subItem);
|
|
4706
|
-
});
|
|
4707
|
-
});
|
|
4708
|
-
};
|
|
4704
|
+
let $grid = this.getGridTable();
|
|
4705
|
+
let isTreeTable = this.widget.options.isTreeTable || false;
|
|
4706
|
+
let treeFields = this.getTreeFields($grid);
|
|
4707
|
+
let childFields = [
|
|
4708
|
+
treeFields.childrenField,
|
|
4709
|
+
treeFields.mapChildrenField,
|
|
4710
|
+
].filter((field, index, values) => field && values.indexOf(field) === index);
|
|
4711
|
+
let keys = new Set();
|
|
4712
|
+
let visited = new WeakSet();
|
|
4713
|
+
// 若数据是嵌套结构,收集 children 下的子节点
|
|
4714
|
+
let loopDo = (item) => {
|
|
4715
|
+
if (!item || typeof item !== "object" || visited.has(item)) {
|
|
4716
|
+
return;
|
|
4717
|
+
}
|
|
4718
|
+
visited.add(item);
|
|
4719
|
+
childFields.forEach((childrenField) => {
|
|
4720
|
+
if (!item || !Array.isArray(item[childrenField])) {
|
|
4721
|
+
return;
|
|
4722
|
+
}
|
|
4723
|
+
item[childrenField].forEach((subItem) => {
|
|
4724
|
+
if (subItem && subItem._X_ROW_KEY) keys.add(subItem._X_ROW_KEY);
|
|
4725
|
+
loopDo(subItem);
|
|
4726
|
+
});
|
|
4727
|
+
});
|
|
4728
|
+
};
|
|
4709
4729
|
loopDo(row);
|
|
4710
4730
|
// 树表使用扁平数据(transform),子节点通过 parentField 关联,
|
|
4711
|
-
// 需按 parentField 递归收集所有后代,避免删除父节点后子节点残留
|
|
4712
|
-
if (isTreeTable && $grid.treeConfig) {
|
|
4713
|
-
let { rowField, parentField } = treeFields;
|
|
4731
|
+
// 需按 parentField 递归收集所有后代,避免删除父节点后子节点残留
|
|
4732
|
+
if (isTreeTable && $grid.treeConfig) {
|
|
4733
|
+
let { rowField, parentField } = treeFields;
|
|
4714
4734
|
let pending = [row];
|
|
4715
4735
|
while (pending.length) {
|
|
4716
4736
|
let cur = pending.shift();
|
|
@@ -4722,9 +4742,9 @@ modules = {
|
|
|
4722
4742
|
// 数据成环时防止把起始节点收进后代集合
|
|
4723
4743
|
if (item._X_ROW_KEY === row._X_ROW_KEY) {
|
|
4724
4744
|
return;
|
|
4725
|
-
}
|
|
4726
|
-
let parentValue = item[parentField];
|
|
4727
|
-
if (treeKeyEquals(parentValue, curId)) {
|
|
4745
|
+
}
|
|
4746
|
+
let parentValue = item[parentField];
|
|
4747
|
+
if (treeKeyEquals(parentValue, curId)) {
|
|
4728
4748
|
keys.add(item._X_ROW_KEY);
|
|
4729
4749
|
pending.push(item);
|
|
4730
4750
|
}
|
|
@@ -4739,19 +4759,19 @@ modules = {
|
|
|
4739
4759
|
* @param {Array} tableRows 当前扁平数据。
|
|
4740
4760
|
* @param {Set} delKeys 待删除行的 _X_ROW_KEY 集合。
|
|
4741
4761
|
*/
|
|
4742
|
-
removeTreeRowsByKeys(tableRows, delKeys) {
|
|
4743
|
-
if (this.widget.options.isTreeTable) {
|
|
4744
|
-
let { rowField } = this.getTreeFields();
|
|
4745
|
-
tableRows.forEach((item) => {
|
|
4746
|
-
if (item && delKeys.has(item._X_ROW_KEY)) {
|
|
4747
|
-
this.unregisterTreeKey(
|
|
4748
|
-
this.treeTemporaryKeyRegistry,
|
|
4749
|
-
item[rowField]
|
|
4750
|
-
);
|
|
4751
|
-
}
|
|
4752
|
-
});
|
|
4753
|
-
}
|
|
4754
|
-
let newRows = tableRows.filter((item) => !delKeys.has(item._X_ROW_KEY));
|
|
4762
|
+
removeTreeRowsByKeys(tableRows, delKeys) {
|
|
4763
|
+
if (this.widget.options.isTreeTable) {
|
|
4764
|
+
let { rowField } = this.getTreeFields();
|
|
4765
|
+
tableRows.forEach((item) => {
|
|
4766
|
+
if (item && delKeys.has(item._X_ROW_KEY)) {
|
|
4767
|
+
this.unregisterTreeKey(
|
|
4768
|
+
this.treeTemporaryKeyRegistry,
|
|
4769
|
+
item[rowField]
|
|
4770
|
+
);
|
|
4771
|
+
}
|
|
4772
|
+
});
|
|
4773
|
+
}
|
|
4774
|
+
let newRows = tableRows.filter((item) => !delKeys.has(item._X_ROW_KEY));
|
|
4755
4775
|
this.setValue(newRows);
|
|
4756
4776
|
this.$nextTick(() => {
|
|
4757
4777
|
this.handleWbs();
|
|
@@ -4905,43 +4925,43 @@ modules = {
|
|
|
4905
4925
|
}
|
|
4906
4926
|
}
|
|
4907
4927
|
|
|
4908
|
-
let treeContext = isTreeTable
|
|
4909
|
-
? this.getTreeContext($grid)
|
|
4910
|
-
: null;
|
|
4911
|
-
let { rowField, parentField } = treeContext
|
|
4912
|
-
? treeContext.fields
|
|
4913
|
-
: this.getTreeFields($grid);
|
|
4914
|
-
|
|
4915
|
-
let newData = this.createNewTableData(isEditTable);
|
|
4916
|
-
newRow = Object.assign({}, newData, editDefaultRow, rowData);
|
|
4917
|
-
if (isTreeTable) {
|
|
4918
|
-
newRow[treeContext.identityConfig.physicalIdField] = null;
|
|
4919
|
-
this.ensureNewTreeRowKey(newRow, treeContext);
|
|
4920
|
-
if (!toSibling) {
|
|
4921
|
-
if (parent && isRootParent(parent[rowField])) {
|
|
4922
|
-
this.$message.error("父节点缺少有效树键,无法新增子节点。");
|
|
4923
|
-
return false;
|
|
4924
|
-
}
|
|
4925
|
-
newRow[parentField] = parent
|
|
4926
|
-
? parent[rowField]
|
|
4927
|
-
: treeContext.identityConfig.rootParentValue;
|
|
4928
|
-
} else {
|
|
4929
|
-
let siblingParentValue = obj?.row[parentField];
|
|
4930
|
-
newRow[parentField] = isRootParent(siblingParentValue)
|
|
4931
|
-
? treeContext.identityConfig.rootParentValue
|
|
4932
|
-
: siblingParentValue;
|
|
4933
|
-
}
|
|
4934
|
-
} else {
|
|
4935
|
-
// 普通编辑表沿用原有临时 id 协议。
|
|
4936
|
-
newRow[rowField] = "row_"
|
|
4937
|
-
+ new Date().valueOf()
|
|
4938
|
-
+ Math.floor(Math.random() * 1000000);
|
|
4939
|
-
}
|
|
4940
|
-
if (treeContext) {
|
|
4941
|
-
this.validateNewTreeRows([newRow], treeContext);
|
|
4942
|
-
}
|
|
4943
|
-
|
|
4944
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4928
|
+
let treeContext = isTreeTable
|
|
4929
|
+
? this.getTreeContext($grid)
|
|
4930
|
+
: null;
|
|
4931
|
+
let { rowField, parentField } = treeContext
|
|
4932
|
+
? treeContext.fields
|
|
4933
|
+
: this.getTreeFields($grid);
|
|
4934
|
+
|
|
4935
|
+
let newData = this.createNewTableData(isEditTable);
|
|
4936
|
+
newRow = Object.assign({}, newData, editDefaultRow, rowData);
|
|
4937
|
+
if (isTreeTable) {
|
|
4938
|
+
newRow[treeContext.identityConfig.physicalIdField] = null;
|
|
4939
|
+
this.ensureNewTreeRowKey(newRow, treeContext);
|
|
4940
|
+
if (!toSibling) {
|
|
4941
|
+
if (parent && isRootParent(parent[rowField])) {
|
|
4942
|
+
this.$message.error("父节点缺少有效树键,无法新增子节点。");
|
|
4943
|
+
return false;
|
|
4944
|
+
}
|
|
4945
|
+
newRow[parentField] = parent
|
|
4946
|
+
? parent[rowField]
|
|
4947
|
+
: treeContext.identityConfig.rootParentValue;
|
|
4948
|
+
} else {
|
|
4949
|
+
let siblingParentValue = obj?.row[parentField];
|
|
4950
|
+
newRow[parentField] = isRootParent(siblingParentValue)
|
|
4951
|
+
? treeContext.identityConfig.rootParentValue
|
|
4952
|
+
: siblingParentValue;
|
|
4953
|
+
}
|
|
4954
|
+
} else {
|
|
4955
|
+
// 普通编辑表沿用原有临时 id 协议。
|
|
4956
|
+
newRow[rowField] = "row_"
|
|
4957
|
+
+ new Date().valueOf()
|
|
4958
|
+
+ Math.floor(Math.random() * 1000000);
|
|
4959
|
+
}
|
|
4960
|
+
if (treeContext) {
|
|
4961
|
+
this.validateNewTreeRows([newRow], treeContext);
|
|
4962
|
+
}
|
|
4963
|
+
|
|
4964
|
+
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4945
4965
|
// 编辑表统一使用 vxe 内部插入,避免 setValue 重载整表并丢失编辑状态。
|
|
4946
4966
|
if (isEditTable) {
|
|
4947
4967
|
let insertTarget = toEnd === true ? -1 : null;
|
|
@@ -4954,14 +4974,14 @@ modules = {
|
|
|
4954
4974
|
insertTarget = -1;
|
|
4955
4975
|
} else if (isTreeTable) {
|
|
4956
4976
|
let nextSibling = tableRows
|
|
4957
|
-
.slice(currentIndex + 1)
|
|
4958
|
-
.find(
|
|
4959
|
-
(item) =>
|
|
4960
|
-
treeKeyEquals(
|
|
4961
|
-
item[parentField],
|
|
4962
|
-
obj.row[parentField]
|
|
4963
|
-
)
|
|
4964
|
-
);
|
|
4977
|
+
.slice(currentIndex + 1)
|
|
4978
|
+
.find(
|
|
4979
|
+
(item) =>
|
|
4980
|
+
treeKeyEquals(
|
|
4981
|
+
item[parentField],
|
|
4982
|
+
obj.row[parentField]
|
|
4983
|
+
)
|
|
4984
|
+
);
|
|
4965
4985
|
insertTarget = nextSibling || -1;
|
|
4966
4986
|
} else {
|
|
4967
4987
|
insertTarget = tableRows[currentIndex + 1] || -1;
|
|
@@ -5047,10 +5067,10 @@ modules = {
|
|
|
5047
5067
|
if (!$grid || rowId == null) {
|
|
5048
5068
|
return;
|
|
5049
5069
|
}
|
|
5050
|
-
let { rowField } = this.getTreeFields($grid);
|
|
5051
|
-
let sourceRow = (this.getValue() || []).find(
|
|
5052
|
-
(item) => item && treeKeyEquals(item[rowField], rowId)
|
|
5053
|
-
);
|
|
5070
|
+
let { rowField } = this.getTreeFields($grid);
|
|
5071
|
+
let sourceRow = (this.getValue() || []).find(
|
|
5072
|
+
(item) => item && treeKeyEquals(item[rowField], rowId)
|
|
5073
|
+
);
|
|
5054
5074
|
if (!sourceRow) {
|
|
5055
5075
|
return;
|
|
5056
5076
|
}
|
|
@@ -5106,18 +5126,18 @@ modules = {
|
|
|
5106
5126
|
* @param {Object} obj VXE 行参数。
|
|
5107
5127
|
*/
|
|
5108
5128
|
async removeEditRow(obj) {
|
|
5109
|
-
let row = obj.row;
|
|
5110
|
-
let $grid = this.getGridTable();
|
|
5111
|
-
await $grid.remove(row);
|
|
5112
|
-
if (this.widget.options.isTreeTable) {
|
|
5113
|
-
let { rowField } = this.getTreeFields($grid);
|
|
5114
|
-
this.unregisterTreeKey(
|
|
5115
|
-
this.treeTemporaryKeyRegistry,
|
|
5116
|
-
row[rowField]
|
|
5117
|
-
);
|
|
5118
|
-
}
|
|
5119
|
-
|
|
5120
|
-
// 临时编辑行由 vxe 内部删除;仅同步表单模型,避免 setValue 重载整表。
|
|
5129
|
+
let row = obj.row;
|
|
5130
|
+
let $grid = this.getGridTable();
|
|
5131
|
+
await $grid.remove(row);
|
|
5132
|
+
if (this.widget.options.isTreeTable) {
|
|
5133
|
+
let { rowField } = this.getTreeFields($grid);
|
|
5134
|
+
this.unregisterTreeKey(
|
|
5135
|
+
this.treeTemporaryKeyRegistry,
|
|
5136
|
+
row[rowField]
|
|
5137
|
+
);
|
|
5138
|
+
}
|
|
5139
|
+
|
|
5140
|
+
// 临时编辑行由 vxe 内部删除;仅同步表单模型,避免 setValue 重载整表。
|
|
5121
5141
|
let tableRows = this.getValue() || [];
|
|
5122
5142
|
this.formModel[this.fieldKeyName] = tableRows.filter(
|
|
5123
5143
|
(item) => item._X_ROW_KEY !== row._X_ROW_KEY
|
|
@@ -5147,9 +5167,9 @@ modules = {
|
|
|
5147
5167
|
* @returns {Promise} VXE 数据刷新结果。
|
|
5148
5168
|
*/
|
|
5149
5169
|
updateWbs() {
|
|
5150
|
-
let that = this;
|
|
5151
|
-
let $grid = that.getGridTable();
|
|
5152
|
-
let { childrenField, mapChildrenField } = this.getTreeFields($grid);
|
|
5170
|
+
let that = this;
|
|
5171
|
+
let $grid = that.getGridTable();
|
|
5172
|
+
let { childrenField, mapChildrenField } = this.getTreeFields($grid);
|
|
5153
5173
|
let fullData = $grid.getTableData().fullData;
|
|
5154
5174
|
let isEditTable = this.widget.options.isEditTable || false;
|
|
5155
5175
|
let isTreeTable = this.widget.options.isTreeTable || false;
|
|
@@ -5161,26 +5181,26 @@ modules = {
|
|
|
5161
5181
|
fullData = $grid.$refs.xTable.tableFullTreeData;
|
|
5162
5182
|
}
|
|
5163
5183
|
let tableRows = this.formModel[that.fieldKeyName] || [];
|
|
5164
|
-
let map = {};
|
|
5165
|
-
let loopDo = (item, wbs) => {
|
|
5166
|
-
item.f_wbs = wbs;
|
|
5167
|
-
map[item._X_ROW_KEY] = wbs;
|
|
5168
|
-
let mappedChildren = mapChildrenField
|
|
5169
|
-
&& Array.isArray(item[mapChildrenField])
|
|
5170
|
-
? item[mapChildrenField]
|
|
5171
|
-
: [];
|
|
5172
|
-
let sourceChildren = childrenField
|
|
5173
|
-
&& Array.isArray(item[childrenField])
|
|
5174
|
-
? item[childrenField]
|
|
5175
|
-
: [];
|
|
5176
|
-
let children = mappedChildren.length
|
|
5177
|
-
? mappedChildren
|
|
5178
|
-
: sourceChildren;
|
|
5179
|
-
children.forEach((subitem, subindex) => {
|
|
5180
|
-
let sub_wbs = wbs + "." + (subindex + 1) + "";
|
|
5181
|
-
loopDo(subitem, sub_wbs);
|
|
5182
|
-
});
|
|
5183
|
-
};
|
|
5184
|
+
let map = {};
|
|
5185
|
+
let loopDo = (item, wbs) => {
|
|
5186
|
+
item.f_wbs = wbs;
|
|
5187
|
+
map[item._X_ROW_KEY] = wbs;
|
|
5188
|
+
let mappedChildren = mapChildrenField
|
|
5189
|
+
&& Array.isArray(item[mapChildrenField])
|
|
5190
|
+
? item[mapChildrenField]
|
|
5191
|
+
: [];
|
|
5192
|
+
let sourceChildren = childrenField
|
|
5193
|
+
&& Array.isArray(item[childrenField])
|
|
5194
|
+
? item[childrenField]
|
|
5195
|
+
: [];
|
|
5196
|
+
let children = mappedChildren.length
|
|
5197
|
+
? mappedChildren
|
|
5198
|
+
: sourceChildren;
|
|
5199
|
+
children.forEach((subitem, subindex) => {
|
|
5200
|
+
let sub_wbs = wbs + "." + (subindex + 1) + "";
|
|
5201
|
+
loopDo(subitem, sub_wbs);
|
|
5202
|
+
});
|
|
5203
|
+
};
|
|
5184
5204
|
fullData.forEach((item, index) => {
|
|
5185
5205
|
let wbs = index + 1 + "";
|
|
5186
5206
|
loopDo(item, wbs);
|
|
@@ -5202,26 +5222,26 @@ modules = {
|
|
|
5202
5222
|
let row = obj.row;
|
|
5203
5223
|
let $grid = this.getGridTable();
|
|
5204
5224
|
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
5205
|
-
let isTreeTable = this.widget.options.isTreeTable;
|
|
5206
|
-
if (isTreeTable) {
|
|
5207
|
-
let { rowField, parentField } = this.getTreeFields($grid);
|
|
5208
|
-
let paretValue = row[parentField];
|
|
5209
|
-
let siblingRows = tableRows.filter(
|
|
5210
|
-
(item) => treeKeyEquals(item[parentField], paretValue)
|
|
5211
|
-
);
|
|
5212
|
-
if (siblingRows.length > 1) {
|
|
5213
|
-
let currentIndex = tableRows.findIndex(
|
|
5214
|
-
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5215
|
-
);
|
|
5216
|
-
let index1 = siblingRows.findIndex(
|
|
5217
|
-
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5218
|
-
);
|
|
5225
|
+
let isTreeTable = this.widget.options.isTreeTable;
|
|
5226
|
+
if (isTreeTable) {
|
|
5227
|
+
let { rowField, parentField } = this.getTreeFields($grid);
|
|
5228
|
+
let paretValue = row[parentField];
|
|
5229
|
+
let siblingRows = tableRows.filter(
|
|
5230
|
+
(item) => treeKeyEquals(item[parentField], paretValue)
|
|
5231
|
+
);
|
|
5232
|
+
if (siblingRows.length > 1) {
|
|
5233
|
+
let currentIndex = tableRows.findIndex(
|
|
5234
|
+
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5235
|
+
);
|
|
5236
|
+
let index1 = siblingRows.findIndex(
|
|
5237
|
+
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5238
|
+
);
|
|
5219
5239
|
if (index1 > 0) {
|
|
5220
|
-
let prevRow = siblingRows[index1 - 1];
|
|
5221
|
-
let prevIndex = tableRows.findIndex(
|
|
5222
|
-
(item) =>
|
|
5223
|
-
treeKeyEquals(item[rowField], prevRow[rowField])
|
|
5224
|
-
);
|
|
5240
|
+
let prevRow = siblingRows[index1 - 1];
|
|
5241
|
+
let prevIndex = tableRows.findIndex(
|
|
5242
|
+
(item) =>
|
|
5243
|
+
treeKeyEquals(item[rowField], prevRow[rowField])
|
|
5244
|
+
);
|
|
5225
5245
|
tableRows.splice(currentIndex, 1);
|
|
5226
5246
|
tableRows.splice(prevIndex, 0, row);
|
|
5227
5247
|
this.setValue(tableRows);
|
|
@@ -5251,26 +5271,26 @@ modules = {
|
|
|
5251
5271
|
let row = obj.row;
|
|
5252
5272
|
let $grid = this.getGridTable();
|
|
5253
5273
|
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
5254
|
-
let isTreeTable = this.widget.options.isTreeTable;
|
|
5255
|
-
if (isTreeTable) {
|
|
5256
|
-
let { rowField, parentField } = this.getTreeFields($grid);
|
|
5257
|
-
let paretValue = row[parentField];
|
|
5258
|
-
let siblingRows = tableRows.filter(
|
|
5259
|
-
(item) => treeKeyEquals(item[parentField], paretValue)
|
|
5260
|
-
);
|
|
5261
|
-
if (siblingRows.length > 1) {
|
|
5262
|
-
let currentIndex = tableRows.findIndex(
|
|
5263
|
-
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5264
|
-
);
|
|
5265
|
-
let index1 = siblingRows.findIndex(
|
|
5266
|
-
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5267
|
-
);
|
|
5274
|
+
let isTreeTable = this.widget.options.isTreeTable;
|
|
5275
|
+
if (isTreeTable) {
|
|
5276
|
+
let { rowField, parentField } = this.getTreeFields($grid);
|
|
5277
|
+
let paretValue = row[parentField];
|
|
5278
|
+
let siblingRows = tableRows.filter(
|
|
5279
|
+
(item) => treeKeyEquals(item[parentField], paretValue)
|
|
5280
|
+
);
|
|
5281
|
+
if (siblingRows.length > 1) {
|
|
5282
|
+
let currentIndex = tableRows.findIndex(
|
|
5283
|
+
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5284
|
+
);
|
|
5285
|
+
let index1 = siblingRows.findIndex(
|
|
5286
|
+
(item) => treeKeyEquals(item[rowField], row[rowField])
|
|
5287
|
+
);
|
|
5268
5288
|
if (index1 < siblingRows.length - 1) {
|
|
5269
|
-
let nextRow = siblingRows[index1 + 1];
|
|
5270
|
-
let nextIndex = tableRows.findIndex(
|
|
5271
|
-
(item) =>
|
|
5272
|
-
treeKeyEquals(item[rowField], nextRow[rowField])
|
|
5273
|
-
);
|
|
5289
|
+
let nextRow = siblingRows[index1 + 1];
|
|
5290
|
+
let nextIndex = tableRows.findIndex(
|
|
5291
|
+
(item) =>
|
|
5292
|
+
treeKeyEquals(item[rowField], nextRow[rowField])
|
|
5293
|
+
);
|
|
5274
5294
|
tableRows.splice(currentIndex, 1);
|
|
5275
5295
|
tableRows.splice(nextIndex, 0, row);
|
|
5276
5296
|
this.setValue(tableRows);
|
|
@@ -5293,19 +5313,19 @@ modules = {
|
|
|
5293
5313
|
},
|
|
5294
5314
|
|
|
5295
5315
|
/** @param {Object} obj VXE 行参数。打开当前层级的树节点排序弹窗。 */
|
|
5296
|
-
openSortRowDialog(obj) {
|
|
5297
|
-
let $grid = this.getGridTable();
|
|
5298
|
-
let { rowField, parentField } = this.getTreeFields($grid);
|
|
5316
|
+
openSortRowDialog(obj) {
|
|
5317
|
+
let $grid = this.getGridTable();
|
|
5318
|
+
let { rowField, parentField } = this.getTreeFields($grid);
|
|
5299
5319
|
let row = obj.row;
|
|
5300
5320
|
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
5301
5321
|
|
|
5302
|
-
let sortParentRow = tableRows.find(
|
|
5303
|
-
(item) => treeKeyEquals(item[rowField], row[parentField])
|
|
5304
|
-
);
|
|
5305
|
-
let sortRows = tableRows.filter(
|
|
5306
|
-
(item) =>
|
|
5307
|
-
treeKeyEquals(item[parentField], row[parentField])
|
|
5308
|
-
);
|
|
5322
|
+
let sortParentRow = tableRows.find(
|
|
5323
|
+
(item) => treeKeyEquals(item[rowField], row[parentField])
|
|
5324
|
+
);
|
|
5325
|
+
let sortRows = tableRows.filter(
|
|
5326
|
+
(item) =>
|
|
5327
|
+
treeKeyEquals(item[parentField], row[parentField])
|
|
5328
|
+
);
|
|
5309
5329
|
this.sortRows = sortRows;
|
|
5310
5330
|
this.sortParentRow = sortParentRow;
|
|
5311
5331
|
this.showTreeMoveDialog = true;
|
|
@@ -5333,20 +5353,20 @@ modules = {
|
|
|
5333
5353
|
this.getGridTable().reloadTreeExpand(this.sortParentRow);
|
|
5334
5354
|
},
|
|
5335
5355
|
});
|
|
5336
|
-
} else {
|
|
5337
|
-
let $grid = this.getGridTable();
|
|
5338
|
-
let { rowField } = this.getTreeFields($grid);
|
|
5339
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
5340
|
-
|
|
5341
|
-
let ids = rows.map((item) => item[rowField]);
|
|
5342
|
-
let hasRowKey = (value) =>
|
|
5343
|
-
ids.some((id) => treeKeyEquals(id, value));
|
|
5344
|
-
let index = tableRows.findIndex((item) =>
|
|
5345
|
-
hasRowKey(item[rowField])
|
|
5346
|
-
);
|
|
5347
|
-
let items = tableRows.filter(
|
|
5348
|
-
(item) => !hasRowKey(item[rowField])
|
|
5349
|
-
);
|
|
5356
|
+
} else {
|
|
5357
|
+
let $grid = this.getGridTable();
|
|
5358
|
+
let { rowField } = this.getTreeFields($grid);
|
|
5359
|
+
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
5360
|
+
|
|
5361
|
+
let ids = rows.map((item) => item[rowField]);
|
|
5362
|
+
let hasRowKey = (value) =>
|
|
5363
|
+
ids.some((id) => treeKeyEquals(id, value));
|
|
5364
|
+
let index = tableRows.findIndex((item) =>
|
|
5365
|
+
hasRowKey(item[rowField])
|
|
5366
|
+
);
|
|
5367
|
+
let items = tableRows.filter(
|
|
5368
|
+
(item) => !hasRowKey(item[rowField])
|
|
5369
|
+
);
|
|
5350
5370
|
rows.forEach((row, index1) => {
|
|
5351
5371
|
items.splice(index + index1, 0, row);
|
|
5352
5372
|
});
|