cloud-web-corejs 1.0.54-dev.781 → 1.0.54-dev.783
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/VabUpload/index.vue +242 -242
- package/src/components/VabUpload/mixins.js +1971 -1971
- package/src/components/VabUpload/privateProfileDialog.vue +2 -2
- package/src/components/hiprint/view/design/index.vue +7 -2
- package/src/components/obsUpload/index.vue +234 -234
- package/src/components/obsUpload/mixins.js +1542 -1542
- package/src/components/vb-tabs/x-tabs.vue +7 -3
- package/src/components/xform/docs//346/240/221/350/241/250rowField/346/224/266/346/225/233-/350/220/275/345/234/260/346/226/207/346/241/243.md +1427 -0
- package/src/components/xform/form-designer/form-widget/dialog/formDialog.vue +2 -2
- package/src/components/xform/form-designer/form-widget/dialog/formDrawer.vue +2 -2
- package/src/components/xform/form-designer/form-widget/dialog/searchFormDialog.vue +2 -2
- package/src/components/xform/form-designer/form-widget/field-widget/copy_button-widget.vue +11 -2
- package/src/components/xform/form-designer/form-widget/field-widget/vabUpload-widget.vue +369 -369
- package/src/components/xform/form-designer/setting-panel/property-editor/fileTypesSelect.vue +69 -23
- package/src/components/xform/form-render/container-item/data-table-item.vue +1 -1
- package/src/components/xform/form-render/container-item/data-table-mixin.js +1469 -428
- package/src/components/xform/form-render/indexMixin.js +379 -263
- package/src/components/xform/mixins/defaultHandle.js +234 -28
- package/src/components/xform/mixins/scriptHttp.js +4 -4
- package/src/components/xform/utils/treeTableUtil.js +1265 -0
- package/src/components/xform/utils/util.js +29 -14
- package/src/microRouter/index.js +3 -0
- package/src/mixins/tableTree/index.js +77 -14
- package/src/store/config/index.js +28 -28
- package/src/utils/menuAdapter.js +277 -277
- package/src/utils/resolveViewComponent.js +203 -203
- package/src/utils/vab.js +6 -3
- package/src/views/bd/setting/formVersion/ftHistoryDialog.vue +9 -2
- package/src/views/user/common_attribute/list.vue +1 -1
- package/src/views/user/form/vform/render.vue +17 -2
- package/src/views/user/form/view/list.vue +11 -10
- package/src/views/user/wf/wfReport/index.vue +625 -625
|
@@ -33,15 +33,30 @@ 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 {
|
|
36
|
+
import {
|
|
37
|
+
buildDynamicSchemaRequestData,
|
|
38
|
+
getDynamicSchemaOption,
|
|
39
|
+
isActionColumnFormat,
|
|
40
|
+
isNonDataExportColumn,
|
|
41
|
+
normalizeDynamicColumns as normalizeDynamicColumnList,
|
|
42
|
+
resolveDynamicSchemaResponse,
|
|
43
|
+
} from "../../utils/dynamicSchemaUtil";
|
|
44
|
+
import {
|
|
45
|
+
resolveTreeFields,
|
|
46
|
+
resolveTreeIdentityConfig,
|
|
47
|
+
resolveTreeCopyConfig,
|
|
48
|
+
resolveTreeSubmitConfig,
|
|
49
|
+
canonicalizeTreeInput,
|
|
50
|
+
isRootParent,
|
|
51
|
+
normalizeTreeKey,
|
|
52
|
+
treeKeyEquals,
|
|
53
|
+
makeTreeTempKey,
|
|
54
|
+
markTemporaryTreeKey,
|
|
55
|
+
isTemporaryTreeKey,
|
|
56
|
+
syncTreeKeyReferences,
|
|
57
|
+
sanitizeTreeRow,
|
|
58
|
+
} from "../../utils/treeTableUtil";
|
|
59
|
+
import { tableTreeMixins } from "../../../../mixins/tableTree/index.js";
|
|
45
60
|
|
|
46
61
|
let modules = {};
|
|
47
62
|
const baseRefUtil = {
|
|
@@ -148,9 +163,17 @@ modules = {
|
|
|
148
163
|
dynamicTableColumns: [],
|
|
149
164
|
dynamicColumnsPreloaded: false,
|
|
150
165
|
dynamicColumnsInitResolved: false,
|
|
151
|
-
dynamicColumnsInitSkipped: false,
|
|
152
|
-
|
|
153
|
-
|
|
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,
|
|
154
177
|
};
|
|
155
178
|
},
|
|
156
179
|
watch: {
|
|
@@ -608,16 +631,22 @@ modules = {
|
|
|
608
631
|
this.initRowIdData(true);
|
|
609
632
|
this.initFieldSchemaData();
|
|
610
633
|
},
|
|
611
|
-
/** @param {Array} val 外部传入数据。@returns {Array} 表单与 VXE 共用的标准化行。 */
|
|
612
|
-
initValue(val) {
|
|
613
|
-
// this.clearRowWidgets()
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
this.
|
|
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;
|
|
621
650
|
this.initRowIdData(true);
|
|
622
651
|
this.initFieldSchemaData(true);
|
|
623
652
|
return rows;
|
|
@@ -627,33 +656,38 @@ modules = {
|
|
|
627
656
|
* @param {Array} rows 原始行数据。
|
|
628
657
|
* @returns {Array|undefined} 根节点优先、子节点紧随父节点的扁平数组。
|
|
629
658
|
*/
|
|
630
|
-
handleTreeData(rows) {
|
|
631
|
-
let isTreeTable = this.widget.options.isTreeTable;
|
|
632
|
-
if (isTreeTable) {
|
|
633
|
-
let $grid = this.getGridTable();
|
|
634
|
-
|
|
635
|
-
let parentField = $grid
|
|
636
|
-
if (parentField) {
|
|
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) {
|
|
637
666
|
// 构建树结构并排序
|
|
638
667
|
let sortedRows = [];
|
|
639
668
|
let nodeMap = new Map();
|
|
640
669
|
|
|
641
|
-
// 第一步:构建节点映射
|
|
642
|
-
rows.forEach((row) => {
|
|
643
|
-
if (row
|
|
644
|
-
nodeMap.set(row
|
|
645
|
-
}
|
|
646
|
-
});
|
|
670
|
+
// 第一步:构建节点映射
|
|
671
|
+
rows.forEach((row) => {
|
|
672
|
+
if (row[rowField] !== undefined && row[rowField] !== null) {
|
|
673
|
+
nodeMap.set(row[rowField], row);
|
|
674
|
+
}
|
|
675
|
+
});
|
|
647
676
|
|
|
648
677
|
// 第二步:按层次排序,先根节点,然后子节点
|
|
649
678
|
rows.forEach((row) => {
|
|
650
|
-
let parentValue = row[parentField];
|
|
651
|
-
//
|
|
652
|
-
if (
|
|
653
|
-
sortedRows.push(row);
|
|
654
|
-
// 递归添加子节点
|
|
655
|
-
this.addChildNodes(
|
|
656
|
-
|
|
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
|
+
}
|
|
657
691
|
});
|
|
658
692
|
|
|
659
693
|
// 如果没有找到根节点,返回原始数组
|
|
@@ -678,21 +712,12 @@ modules = {
|
|
|
678
712
|
return rows;
|
|
679
713
|
},
|
|
680
714
|
/** @param {*} parentId 父节点 id。@param {Map} nodeMap 节点映射。@param {String} parentField 父字段。@param {Array} sortedRows 输出数组。 */
|
|
681
|
-
addChildNodes(parentId, nodeMap, parentField, sortedRows) {
|
|
682
|
-
// 遍历所有节点,找出当前父节点的子节点
|
|
683
|
-
for (let [id, node] of nodeMap.entries()) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
// 转换为相同类型进行比较
|
|
689
|
-
if (typeof nodeParentValue !== typeof targetParentId) {
|
|
690
|
-
nodeParentValue = String(nodeParentValue);
|
|
691
|
-
targetParentId = String(targetParentId);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
if (nodeParentValue === targetParentId) {
|
|
695
|
-
sortedRows.push(node);
|
|
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);
|
|
696
721
|
// 递归添加子节点的子节点
|
|
697
722
|
this.addChildNodes(id, nodeMap, parentField, sortedRows);
|
|
698
723
|
}
|
|
@@ -704,7 +729,7 @@ modules = {
|
|
|
704
729
|
* @param {Boolean} defaultValueEnabled 是否应用字段默认值。
|
|
705
730
|
* @returns {Array} 标准化后的新数组。
|
|
706
731
|
*/
|
|
707
|
-
normalizeTableRows(rows, defaultValueEnabled = false) {
|
|
732
|
+
normalizeTableRows(rows, defaultValueEnabled = false) {
|
|
708
733
|
if (!Array.isArray(rows) || !rows.length) {
|
|
709
734
|
return rows || [];
|
|
710
735
|
}
|
|
@@ -720,17 +745,44 @@ modules = {
|
|
|
720
745
|
nextRow._X_ROW_KEY = "row_" + generateId();
|
|
721
746
|
}
|
|
722
747
|
return nextRow;
|
|
723
|
-
});
|
|
724
|
-
},
|
|
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
|
+
},
|
|
725
771
|
/**
|
|
726
772
|
* 全量替换表格数据并重建行级 schema。
|
|
727
|
-
* 注意:该操作会触发 vxe-grid
|
|
773
|
+
* 注意:该操作会触发 vxe-grid 重载;编辑表仅在服务端正式身份回填后使用。
|
|
728
774
|
* @param {Array} val 新的完整数据集。
|
|
729
775
|
*/
|
|
730
|
-
setValue(val) {
|
|
731
|
-
// console.log("rows:",val);
|
|
732
|
-
this.clearRowWidgets();
|
|
733
|
-
|
|
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);
|
|
734
786
|
this.formModel[this.fieldKeyName] = rows;
|
|
735
787
|
let $grid = this.getGridTable();
|
|
736
788
|
this.fieldModel = rows;
|
|
@@ -2084,15 +2136,15 @@ modules = {
|
|
|
2084
2136
|
this.widget.options.editDefaultRow
|
|
2085
2137
|
);
|
|
2086
2138
|
}
|
|
2087
|
-
treeNodeParam = (row) => {
|
|
2088
|
-
return {
|
|
2089
|
-
[this.widget.options.parentField]: row.id,
|
|
2090
|
-
};
|
|
2091
|
-
};
|
|
2092
2139
|
treeConfig = {
|
|
2093
2140
|
lazy: false,
|
|
2094
|
-
|
|
2095
|
-
|
|
2141
|
+
// 树表主键列显式声明为唯一事实源:vxe transform 建树(toArrayTree)
|
|
2142
|
+
// 以 rowField 为 key,父子关联代码一律经 getTreeFields 取列名,
|
|
2143
|
+
// 不允许在别处写死 id,否则配置变化时两条链分叉、层级错乱。
|
|
2144
|
+
rowField: "id",
|
|
2145
|
+
children: "f_children",
|
|
2146
|
+
mapChildren: "_X_ROW_CHILD",
|
|
2147
|
+
hasChild: "f_has_child", // 设置是否有子节点标识
|
|
2096
2148
|
parentField: "f_parent",
|
|
2097
2149
|
transform: true,
|
|
2098
2150
|
expandAll: true,
|
|
@@ -2101,18 +2153,18 @@ modules = {
|
|
|
2101
2153
|
// 恢复展开状态(克隆保留该键),查询重载会重新生成键,互不干扰。
|
|
2102
2154
|
reserve: true,
|
|
2103
2155
|
loadMethod: ({ $table, row }) => {
|
|
2104
|
-
// 模拟后台接口
|
|
2105
|
-
let $grid = that.getGridTable();
|
|
2106
|
-
let parentField = $grid
|
|
2156
|
+
// 模拟后台接口
|
|
2157
|
+
let $grid = that.getGridTable();
|
|
2158
|
+
let { rowField, parentField } = that.getTreeFields($grid);
|
|
2107
2159
|
return new Promise((resolve, reject) => {
|
|
2108
2160
|
let treeParam = tableConfig?.treeNodeParam;
|
|
2109
2161
|
let reqPram = {};
|
|
2110
2162
|
if (treeParam) {
|
|
2111
2163
|
reqPram = treeParam(row) || {};
|
|
2112
|
-
}
|
|
2113
|
-
Object.assign(reqPram, {
|
|
2114
|
-
[parentField]: row
|
|
2115
|
-
});
|
|
2164
|
+
}
|
|
2165
|
+
Object.assign(reqPram, {
|
|
2166
|
+
[parentField]: row[rowField],
|
|
2167
|
+
});
|
|
2116
2168
|
let accessParam = that.getAccessParam() || {};
|
|
2117
2169
|
let defaultOption = that.getHttpConfigForUser();
|
|
2118
2170
|
that.formHttp({
|
|
@@ -2126,62 +2178,126 @@ modules = {
|
|
|
2126
2178
|
...otherParam,
|
|
2127
2179
|
...accessParam,
|
|
2128
2180
|
},
|
|
2129
|
-
},
|
|
2130
|
-
callback: (res) => {
|
|
2131
|
-
if (res.type === "success") {
|
|
2132
|
-
let
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
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
|
+
}
|
|
2180
2287
|
},
|
|
2181
2288
|
});
|
|
2182
2289
|
});
|
|
2183
2290
|
},
|
|
2184
2291
|
};
|
|
2292
|
+
// 懒加载子节点的请求参数:父键/主键列名取自 treeConfig。
|
|
2293
|
+
// (此前误读 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
|
+
};
|
|
2185
2301
|
}
|
|
2186
2302
|
let editOpts = {};
|
|
2187
2303
|
if (this.widget.options.isEditTable) {
|
|
@@ -2334,7 +2450,30 @@ modules = {
|
|
|
2334
2450
|
rowConfig.height = this.widget.options.tableRowHeight;
|
|
2335
2451
|
}
|
|
2336
2452
|
|
|
2337
|
-
|
|
2453
|
+
// 宿主经 dataTableOption.config 覆写时,treeConfig 必须深合并而不是整体
|
|
2454
|
+
// 替换:宿主通常只想改单个键(如 expandAll),整体替换会把 rowField/
|
|
2455
|
+
// parentField/children 一并丢掉,使树主键链与建树逻辑分叉。
|
|
2456
|
+
// 不直接改 dataTableConfig——它是宿主经 $attrs 传入的对象。
|
|
2457
|
+
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 = {
|
|
2338
2477
|
// vue: this,
|
|
2339
2478
|
tableRef: tableRef,
|
|
2340
2479
|
tableName: this.getGridTableName(),
|
|
@@ -2345,11 +2484,18 @@ modules = {
|
|
|
2345
2484
|
isQueryAllPage,
|
|
2346
2485
|
exportItemConfig,
|
|
2347
2486
|
vform: true,
|
|
2348
|
-
...(this.getDynamicColumnSourceType() !== "none"
|
|
2349
|
-
? { visibleSync: false }
|
|
2350
|
-
: {}),
|
|
2351
|
-
...(dataTableConfig.otherConfig || {}),
|
|
2352
|
-
|
|
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: {
|
|
2353
2499
|
height: height,
|
|
2354
2500
|
showFooter,
|
|
2355
2501
|
pagerConfig,
|
|
@@ -2357,7 +2503,7 @@ modules = {
|
|
|
2357
2503
|
rowConfig,
|
|
2358
2504
|
headerCellStyle,
|
|
2359
2505
|
...editOpts,
|
|
2360
|
-
...
|
|
2506
|
+
...hostTableConfig,
|
|
2361
2507
|
|
|
2362
2508
|
/*rowConfig:{
|
|
2363
2509
|
height: 40
|
|
@@ -2503,19 +2649,26 @@ modules = {
|
|
|
2503
2649
|
if (res.type === "success") {
|
|
2504
2650
|
if (that.widget.options.isTreeTable) {
|
|
2505
2651
|
if (rows.length > 0) {
|
|
2506
|
-
let fullAllDataRowMap =
|
|
2507
|
-
$grid.$refs.xTable.fullAllDataRowMap;
|
|
2508
|
-
let
|
|
2652
|
+
let fullAllDataRowMap =
|
|
2653
|
+
$grid.$refs.xTable.fullAllDataRowMap;
|
|
2654
|
+
let treeFields = that.getTreeFields($grid);
|
|
2655
|
+
let rowField = treeFields.rowField;
|
|
2656
|
+
let parentField = treeFields.parentField;
|
|
2509
2657
|
let expandAll = $grid.treeConfig.expandAll || false;
|
|
2510
|
-
let isLazy = $grid.treeConfig.lazy;
|
|
2511
|
-
let expandIds = rows
|
|
2512
|
-
.filter(
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
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
|
+
: [];
|
|
2519
2672
|
if (expandAll && expandRows.length) {
|
|
2520
2673
|
that.$nextTick(() => {
|
|
2521
2674
|
setTimeout(function () {
|
|
@@ -2538,11 +2691,16 @@ modules = {
|
|
|
2538
2691
|
});
|
|
2539
2692
|
}
|
|
2540
2693
|
|
|
2541
|
-
let row = rows.find((item) =>
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
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
|
+
) {
|
|
2546
2704
|
let hasChild = $grid.treeConfig.hasChild;
|
|
2547
2705
|
if (row[hasChild]) {
|
|
2548
2706
|
that.$nextTick(() => {
|
|
@@ -2590,17 +2748,63 @@ modules = {
|
|
|
2590
2748
|
},
|
|
2591
2749
|
},
|
|
2592
2750
|
};
|
|
2593
|
-
tableOption.callback = (rows) => {
|
|
2594
|
-
// this.fieldModel = rows;
|
|
2595
|
-
this.formModel[this.fieldKeyName] = rows;
|
|
2596
|
-
};
|
|
2597
|
-
}
|
|
2598
|
-
|
|
2599
|
-
if (isTreeTable) {
|
|
2600
|
-
tableOption.filterType = false;
|
|
2601
|
-
}
|
|
2602
|
-
tableOption = extendDeeply(tableOption, tableConfig);
|
|
2603
|
-
|
|
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) {
|
|
2604
2808
|
let tableConfig =
|
|
2605
2809
|
this.handleCustomEvent(this.widget.options.tableConfig) || {};
|
|
2606
2810
|
tableOption = extendDeeply(tableOption, tableConfig);
|
|
@@ -2658,10 +2862,15 @@ modules = {
|
|
|
2658
2862
|
if (mergeRowEnabled && unikey) {
|
|
2659
2863
|
tableOption.config.spanMethod = this.mergeRowMethod;
|
|
2660
2864
|
}
|
|
2661
|
-
this.$vxeTableUtil.initVxeTable(tableOption).then((opts) => {
|
|
2662
|
-
this.vxeOption = opts;
|
|
2663
|
-
this.applyCompareRowClassName();
|
|
2664
|
-
|
|
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
|
|
2665
2874
|
this.flushPendingSchemaInit();
|
|
2666
2875
|
this.tryAutoLoadDynamicColumns().finally(() => {
|
|
2667
2876
|
if (!isQueryTable) {
|
|
@@ -3341,6 +3550,411 @@ modules = {
|
|
|
3341
3550
|
let $grid = this.$refs[this.getTableRef()];
|
|
3342
3551
|
return $grid;
|
|
3343
3552
|
},
|
|
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
|
+
},
|
|
3344
3958
|
/** @param {Object} e 容器组件 schema。@returns {String} 动态组件名称。 */
|
|
3345
3959
|
getContainerWidgetName: function (e) {
|
|
3346
3960
|
return "grid" === e.type ? "grid-item" : e.type + "-item";
|
|
@@ -3415,84 +4029,431 @@ modules = {
|
|
|
3415
4029
|
|
|
3416
4030
|
//editTable begin
|
|
3417
4031
|
/**
|
|
3418
|
-
*
|
|
4032
|
+
* 保存当前编辑行。持久化行原位合并;新身份以回查结果重建树关系。
|
|
3419
4033
|
* @param {Object} obj VXE 插槽参数,必须包含 row 和 $table。
|
|
3420
4034
|
*/
|
|
3421
|
-
async saveEditRow(obj) {
|
|
3422
|
-
let formRef = this.getFormRef();
|
|
3423
|
-
let formConfig = this.formConfig;
|
|
3424
|
-
let entity = formConfig.entity;
|
|
3425
|
-
if (!entity) return;
|
|
3426
|
-
let
|
|
3427
|
-
let
|
|
3428
|
-
let
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
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) {
|
|
3496
4457
|
let reportTemplate = this.getFormRef()?.reportTemplate;
|
|
3497
4458
|
let formCode = reportTemplate.formCode;
|
|
3498
4459
|
let formConfig = this.formConfig;
|
|
@@ -3500,7 +4461,7 @@ modules = {
|
|
|
3500
4461
|
let entity = formConfig.entity;
|
|
3501
4462
|
let scriptCode = formConfig.formScriptCode || "getOne";
|
|
3502
4463
|
let defaultOption = this.getHttpConfigForUser();
|
|
3503
|
-
this.formHttp({
|
|
4464
|
+
return this.formHttp({
|
|
3504
4465
|
scriptCode: scriptCode,
|
|
3505
4466
|
data: {
|
|
3506
4467
|
formCode: formCode,
|
|
@@ -3511,10 +4472,12 @@ modules = {
|
|
|
3511
4472
|
},
|
|
3512
4473
|
},
|
|
3513
4474
|
...defaultOption,
|
|
3514
|
-
success: (res) => {
|
|
3515
|
-
callback && callback(res);
|
|
3516
|
-
},
|
|
3517
|
-
|
|
4475
|
+
success: (res) => {
|
|
4476
|
+
callback && callback(res);
|
|
4477
|
+
},
|
|
4478
|
+
fail,
|
|
4479
|
+
error,
|
|
4480
|
+
});
|
|
3518
4481
|
},
|
|
3519
4482
|
/** @param {Object} rowData 新行数据。@param {Object} obj 父行参数。@param {Boolean} toTop 是否插到顶部。 */
|
|
3520
4483
|
addChildTreeRow(rowData, obj, toTop) {
|
|
@@ -3541,11 +4504,12 @@ modules = {
|
|
|
3541
4504
|
let isEditTable = this.widget.options.isEditTable || false;
|
|
3542
4505
|
let parent = obj?.row;
|
|
3543
4506
|
let $grid = this.getGridTable();
|
|
3544
|
-
if (isEditTable && this.hasEditingRow($grid, 1)) {
|
|
3545
|
-
return false;
|
|
3546
|
-
}
|
|
3547
|
-
let
|
|
3548
|
-
let
|
|
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 = {};
|
|
3549
4513
|
let originOption = $grid.params.originOption;
|
|
3550
4514
|
let editDefaultRow;
|
|
3551
4515
|
if (originOption.editDefaultRow) {
|
|
@@ -3556,21 +4520,27 @@ modules = {
|
|
|
3556
4520
|
}
|
|
3557
4521
|
}
|
|
3558
4522
|
|
|
3559
|
-
|
|
3560
|
-
newRow.
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
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] || [];
|
|
3574
4544
|
if (!parent) {
|
|
3575
4545
|
if (toEnd === true) {
|
|
3576
4546
|
tableRows.push(newRow);
|
|
@@ -3586,9 +4556,9 @@ modules = {
|
|
|
3586
4556
|
}
|
|
3587
4557
|
this.setValue(tableRows);
|
|
3588
4558
|
this.$nextTick(() => {
|
|
3589
|
-
this.handleWbs();
|
|
3590
|
-
if (isEditTable) {
|
|
3591
|
-
this.setActiveRowById($grid, newRow
|
|
4559
|
+
this.handleWbs();
|
|
4560
|
+
if (isEditTable) {
|
|
4561
|
+
this.setActiveRowById($grid, newRow[rowField]);
|
|
3592
4562
|
}
|
|
3593
4563
|
});
|
|
3594
4564
|
|
|
@@ -3610,9 +4580,9 @@ modules = {
|
|
|
3610
4580
|
this.$nextTick(() => {
|
|
3611
4581
|
this.handleWbs();
|
|
3612
4582
|
// setValue 已浅克隆所有行,obj.row 是失效引用,须按 _X_ROW_KEY 找回新行
|
|
3613
|
-
this.setTreeExpandByRowKey($grid, obj.row._X_ROW_KEY);
|
|
3614
|
-
if (isEditTable) {
|
|
3615
|
-
this.setActiveRowById($grid, newRow
|
|
4583
|
+
this.setTreeExpandByRowKey($grid, obj.row._X_ROW_KEY);
|
|
4584
|
+
if (isEditTable) {
|
|
4585
|
+
this.setActiveRowById($grid, newRow[rowField]);
|
|
3616
4586
|
}
|
|
3617
4587
|
});
|
|
3618
4588
|
});
|
|
@@ -3646,11 +4616,16 @@ modules = {
|
|
|
3646
4616
|
addTreeRows(rowsData, obj, field, sanitize) {
|
|
3647
4617
|
if (!Array.isArray(rowsData) || !rowsData.length) {
|
|
3648
4618
|
return;
|
|
3649
|
-
}
|
|
3650
|
-
let $grid = this.getGridTable();
|
|
3651
|
-
let parent = obj?.row;
|
|
3652
|
-
let
|
|
3653
|
-
let
|
|
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] || [];
|
|
3654
4629
|
let items = rowsData;
|
|
3655
4630
|
if (field) {
|
|
3656
4631
|
let keys = tableRows.map((item) => item[field] + "");
|
|
@@ -3667,28 +4642,29 @@ modules = {
|
|
|
3667
4642
|
} else {
|
|
3668
4643
|
editDefaultRow = originOption.editDefaultRow || {};
|
|
3669
4644
|
}
|
|
3670
|
-
}
|
|
3671
|
-
let newData = this.createNewTableData(false);
|
|
3672
|
-
let
|
|
3673
|
-
let
|
|
3674
|
-
items.forEach((rowData
|
|
3675
|
-
// 复制来的数据先剔除系统字段,避免旧审计/外键随 assign 泄入
|
|
3676
|
-
let source = rowData;
|
|
3677
|
-
if (sanitize) {
|
|
3678
|
-
source = this.stripRowSystemFields(rowData, extraStrip);
|
|
3679
|
-
}
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
}
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
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);
|
|
3692
4668
|
this.$nextTick(() => {
|
|
3693
4669
|
this.handleWbs();
|
|
3694
4670
|
if (parent) {
|
|
@@ -3705,25 +4681,36 @@ modules = {
|
|
|
3705
4681
|
* @returns {Set} 后代行的 _X_ROW_KEY 集合。
|
|
3706
4682
|
*/
|
|
3707
4683
|
collectDescendantKeys(row, tableRows) {
|
|
3708
|
-
let $grid = this.getGridTable();
|
|
3709
|
-
let isTreeTable = this.widget.options.isTreeTable || false;
|
|
3710
|
-
let
|
|
3711
|
-
let
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
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
|
+
};
|
|
3721
4709
|
loopDo(row);
|
|
3722
4710
|
// 树表使用扁平数据(transform),子节点通过 parentField 关联,
|
|
3723
|
-
// 需按 parentField 递归收集所有后代,避免删除父节点后子节点残留
|
|
3724
|
-
if (isTreeTable && $grid.treeConfig) {
|
|
3725
|
-
let parentField =
|
|
3726
|
-
let rowField = $grid.treeConfig.rowField || "id";
|
|
4711
|
+
// 需按 parentField 递归收集所有后代,避免删除父节点后子节点残留
|
|
4712
|
+
if (isTreeTable && $grid.treeConfig) {
|
|
4713
|
+
let { rowField, parentField } = treeFields;
|
|
3727
4714
|
let pending = [row];
|
|
3728
4715
|
while (pending.length) {
|
|
3729
4716
|
let cur = pending.shift();
|
|
@@ -3735,13 +4722,9 @@ modules = {
|
|
|
3735
4722
|
// 数据成环时防止把起始节点收进后代集合
|
|
3736
4723
|
if (item._X_ROW_KEY === row._X_ROW_KEY) {
|
|
3737
4724
|
return;
|
|
3738
|
-
}
|
|
3739
|
-
let parentValue = item[parentField];
|
|
3740
|
-
|
|
3741
|
-
if (!matched && parentValue != null && curId != null) {
|
|
3742
|
-
matched = String(parentValue) === String(curId);
|
|
3743
|
-
}
|
|
3744
|
-
if (matched) {
|
|
4725
|
+
}
|
|
4726
|
+
let parentValue = item[parentField];
|
|
4727
|
+
if (treeKeyEquals(parentValue, curId)) {
|
|
3745
4728
|
keys.add(item._X_ROW_KEY);
|
|
3746
4729
|
pending.push(item);
|
|
3747
4730
|
}
|
|
@@ -3756,8 +4739,19 @@ modules = {
|
|
|
3756
4739
|
* @param {Array} tableRows 当前扁平数据。
|
|
3757
4740
|
* @param {Set} delKeys 待删除行的 _X_ROW_KEY 集合。
|
|
3758
4741
|
*/
|
|
3759
|
-
removeTreeRowsByKeys(tableRows, delKeys) {
|
|
3760
|
-
|
|
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));
|
|
3761
4755
|
this.setValue(newRows);
|
|
3762
4756
|
this.$nextTick(() => {
|
|
3763
4757
|
this.handleWbs();
|
|
@@ -3911,23 +4905,43 @@ modules = {
|
|
|
3911
4905
|
}
|
|
3912
4906
|
}
|
|
3913
4907
|
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
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] || [];
|
|
3931
4945
|
// 编辑表统一使用 vxe 内部插入,避免 setValue 重载整表并丢失编辑状态。
|
|
3932
4946
|
if (isEditTable) {
|
|
3933
4947
|
let insertTarget = toEnd === true ? -1 : null;
|
|
@@ -3939,12 +4953,15 @@ modules = {
|
|
|
3939
4953
|
// 目标行找不到时追加到末尾,避免 slice(0) 误配到首个同级行
|
|
3940
4954
|
insertTarget = -1;
|
|
3941
4955
|
} else if (isTreeTable) {
|
|
3942
|
-
let parentField = $grid.treeConfig.parentField;
|
|
3943
4956
|
let nextSibling = tableRows
|
|
3944
|
-
.slice(currentIndex + 1)
|
|
3945
|
-
.find(
|
|
3946
|
-
(item) =>
|
|
3947
|
-
|
|
4957
|
+
.slice(currentIndex + 1)
|
|
4958
|
+
.find(
|
|
4959
|
+
(item) =>
|
|
4960
|
+
treeKeyEquals(
|
|
4961
|
+
item[parentField],
|
|
4962
|
+
obj.row[parentField]
|
|
4963
|
+
)
|
|
4964
|
+
);
|
|
3948
4965
|
insertTarget = nextSibling || -1;
|
|
3949
4966
|
} else {
|
|
3950
4967
|
insertTarget = tableRows[currentIndex + 1] || -1;
|
|
@@ -4030,9 +5047,10 @@ modules = {
|
|
|
4030
5047
|
if (!$grid || rowId == null) {
|
|
4031
5048
|
return;
|
|
4032
5049
|
}
|
|
4033
|
-
let
|
|
4034
|
-
|
|
4035
|
-
|
|
5050
|
+
let { rowField } = this.getTreeFields($grid);
|
|
5051
|
+
let sourceRow = (this.getValue() || []).find(
|
|
5052
|
+
(item) => item && treeKeyEquals(item[rowField], rowId)
|
|
5053
|
+
);
|
|
4036
5054
|
if (!sourceRow) {
|
|
4037
5055
|
return;
|
|
4038
5056
|
}
|
|
@@ -4088,11 +5106,18 @@ modules = {
|
|
|
4088
5106
|
* @param {Object} obj VXE 行参数。
|
|
4089
5107
|
*/
|
|
4090
5108
|
async removeEditRow(obj) {
|
|
4091
|
-
let row = obj.row;
|
|
4092
|
-
let $grid = this.getGridTable();
|
|
4093
|
-
await $grid.remove(row);
|
|
4094
|
-
|
|
4095
|
-
|
|
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 重载整表。
|
|
4096
5121
|
let tableRows = this.getValue() || [];
|
|
4097
5122
|
this.formModel[this.fieldKeyName] = tableRows.filter(
|
|
4098
5123
|
(item) => item._X_ROW_KEY !== row._X_ROW_KEY
|
|
@@ -4122,9 +5147,9 @@ modules = {
|
|
|
4122
5147
|
* @returns {Promise} VXE 数据刷新结果。
|
|
4123
5148
|
*/
|
|
4124
5149
|
updateWbs() {
|
|
4125
|
-
let that = this;
|
|
4126
|
-
let $grid = that.getGridTable();
|
|
4127
|
-
let childrenField = $grid
|
|
5150
|
+
let that = this;
|
|
5151
|
+
let $grid = that.getGridTable();
|
|
5152
|
+
let { childrenField, mapChildrenField } = this.getTreeFields($grid);
|
|
4128
5153
|
let fullData = $grid.getTableData().fullData;
|
|
4129
5154
|
let isEditTable = this.widget.options.isEditTable || false;
|
|
4130
5155
|
let isTreeTable = this.widget.options.isTreeTable || false;
|
|
@@ -4136,16 +5161,26 @@ modules = {
|
|
|
4136
5161
|
fullData = $grid.$refs.xTable.tableFullTreeData;
|
|
4137
5162
|
}
|
|
4138
5163
|
let tableRows = this.formModel[that.fieldKeyName] || [];
|
|
4139
|
-
let map = {};
|
|
4140
|
-
let loopDo = (item, wbs) => {
|
|
4141
|
-
item.f_wbs = wbs;
|
|
4142
|
-
map[item._X_ROW_KEY] = wbs;
|
|
4143
|
-
|
|
4144
|
-
item[
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
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
|
+
};
|
|
4149
5184
|
fullData.forEach((item, index) => {
|
|
4150
5185
|
let wbs = index + 1 + "";
|
|
4151
5186
|
loopDo(item, wbs);
|
|
@@ -4167,26 +5202,26 @@ modules = {
|
|
|
4167
5202
|
let row = obj.row;
|
|
4168
5203
|
let $grid = this.getGridTable();
|
|
4169
5204
|
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4170
|
-
let isTreeTable = this.widget.options.isTreeTable;
|
|
4171
|
-
if (isTreeTable) {
|
|
4172
|
-
let parentField = $grid
|
|
4173
|
-
let
|
|
4174
|
-
let
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
)
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
);
|
|
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
|
+
);
|
|
4185
5219
|
if (index1 > 0) {
|
|
4186
|
-
let prevRow = siblingRows[index1 - 1];
|
|
4187
|
-
let prevIndex = tableRows.findIndex(
|
|
4188
|
-
(item) =>
|
|
4189
|
-
|
|
5220
|
+
let prevRow = siblingRows[index1 - 1];
|
|
5221
|
+
let prevIndex = tableRows.findIndex(
|
|
5222
|
+
(item) =>
|
|
5223
|
+
treeKeyEquals(item[rowField], prevRow[rowField])
|
|
5224
|
+
);
|
|
4190
5225
|
tableRows.splice(currentIndex, 1);
|
|
4191
5226
|
tableRows.splice(prevIndex, 0, row);
|
|
4192
5227
|
this.setValue(tableRows);
|
|
@@ -4216,26 +5251,26 @@ modules = {
|
|
|
4216
5251
|
let row = obj.row;
|
|
4217
5252
|
let $grid = this.getGridTable();
|
|
4218
5253
|
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4219
|
-
let isTreeTable = this.widget.options.isTreeTable;
|
|
4220
|
-
if (isTreeTable) {
|
|
4221
|
-
let parentField = $grid
|
|
4222
|
-
let
|
|
4223
|
-
let
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
)
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
);
|
|
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
|
+
);
|
|
4234
5268
|
if (index1 < siblingRows.length - 1) {
|
|
4235
|
-
let nextRow = siblingRows[index1 + 1];
|
|
4236
|
-
let nextIndex = tableRows.findIndex(
|
|
4237
|
-
(item) =>
|
|
4238
|
-
|
|
5269
|
+
let nextRow = siblingRows[index1 + 1];
|
|
5270
|
+
let nextIndex = tableRows.findIndex(
|
|
5271
|
+
(item) =>
|
|
5272
|
+
treeKeyEquals(item[rowField], nextRow[rowField])
|
|
5273
|
+
);
|
|
4239
5274
|
tableRows.splice(currentIndex, 1);
|
|
4240
5275
|
tableRows.splice(nextIndex, 0, row);
|
|
4241
5276
|
this.setValue(tableRows);
|
|
@@ -4258,19 +5293,19 @@ modules = {
|
|
|
4258
5293
|
},
|
|
4259
5294
|
|
|
4260
5295
|
/** @param {Object} obj VXE 行参数。打开当前层级的树节点排序弹窗。 */
|
|
4261
|
-
openSortRowDialog(obj) {
|
|
4262
|
-
let $grid = this.getGridTable();
|
|
4263
|
-
let parentField = $grid
|
|
4264
|
-
let rowField = $grid.treeConfig.rowField || "id";
|
|
5296
|
+
openSortRowDialog(obj) {
|
|
5297
|
+
let $grid = this.getGridTable();
|
|
5298
|
+
let { rowField, parentField } = this.getTreeFields($grid);
|
|
4265
5299
|
let row = obj.row;
|
|
4266
5300
|
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4267
5301
|
|
|
4268
|
-
let sortParentRow = tableRows.find(
|
|
4269
|
-
(item) => item[rowField]
|
|
4270
|
-
);
|
|
4271
|
-
let sortRows = tableRows.filter(
|
|
4272
|
-
(item) =>
|
|
4273
|
-
|
|
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
|
+
);
|
|
4274
5309
|
this.sortRows = sortRows;
|
|
4275
5310
|
this.sortParentRow = sortParentRow;
|
|
4276
5311
|
this.showTreeMoveDialog = true;
|
|
@@ -4298,14 +5333,20 @@ modules = {
|
|
|
4298
5333
|
this.getGridTable().reloadTreeExpand(this.sortParentRow);
|
|
4299
5334
|
},
|
|
4300
5335
|
});
|
|
4301
|
-
} else {
|
|
4302
|
-
let $grid = this.getGridTable();
|
|
4303
|
-
let rowField = $grid
|
|
4304
|
-
let tableRows = this.formModel[this.fieldKeyName] || [];
|
|
4305
|
-
|
|
4306
|
-
let ids = rows.map((item) => item[rowField]);
|
|
4307
|
-
let
|
|
4308
|
-
|
|
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
|
+
);
|
|
4309
5350
|
rows.forEach((row, index1) => {
|
|
4310
5351
|
items.splice(index + index1, 0, row);
|
|
4311
5352
|
});
|