@yibozhang/pro-table 0.0.4 → 0.0.6
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/bundles/yibozhang-pro-table.umd.js +612 -194
- package/bundles/yibozhang-pro-table.umd.js.map +1 -1
- package/bundles/yibozhang-pro-table.umd.min.js +1 -1
- package/bundles/yibozhang-pro-table.umd.min.js.map +1 -1
- package/esm2015/lib/page-container/page-container.component.js +4 -2
- package/esm2015/lib/page-public/antd-form.js +168 -36
- package/esm2015/lib/page-public/array-form.js +230 -131
- package/esm2015/lib/pro-table.component.js +156 -25
- package/fesm2015/yibozhang-pro-table.js +554 -190
- package/fesm2015/yibozhang-pro-table.js.map +1 -1
- package/lib/page-container/page-container.component.d.ts +1 -0
- package/lib/page-container/page-container.component.d.ts.map +1 -1
- package/lib/page-public/antd-form.d.ts +15 -1
- package/lib/page-public/antd-form.d.ts.map +1 -1
- package/lib/page-public/array-form.d.ts +56 -144
- package/lib/page-public/array-form.d.ts.map +1 -1
- package/lib/pro-table.component.d.ts +5 -0
- package/lib/pro-table.component.d.ts.map +1 -1
- package/package.json +1 -1
- package/yibozhang-pro-table.metadata.json +1 -1
|
@@ -181,8 +181,10 @@ class ProTableComponent {
|
|
|
181
181
|
};
|
|
182
182
|
this._loading = false;
|
|
183
183
|
this._selectedTableRow = null;
|
|
184
|
-
//
|
|
184
|
+
// 选中的行数据(用于复选框选择)- 保留用于兼容性
|
|
185
185
|
this._selectedRows = [];
|
|
186
|
+
// 使用 Set 存储选中项的 ID,支持跨页选中
|
|
187
|
+
this._selectedRowIds = new Set();
|
|
186
188
|
// 全选状态
|
|
187
189
|
this._checkedAll = false;
|
|
188
190
|
// 半选状态(部分选中)
|
|
@@ -705,7 +707,12 @@ class ProTableComponent {
|
|
|
705
707
|
return this._selectedTableRow;
|
|
706
708
|
}
|
|
707
709
|
getCheckedRows() {
|
|
708
|
-
|
|
710
|
+
if (!this.showCheckbox) {
|
|
711
|
+
return [];
|
|
712
|
+
}
|
|
713
|
+
// 返回当前数据源中所有 checked 为 true 的项
|
|
714
|
+
// 注意:如果需要获取所有页的选中项,需要遍历所有数据源或使用 _selectedRowIds
|
|
715
|
+
return this.dataSource.filter((row) => row.checked === true);
|
|
709
716
|
}
|
|
710
717
|
// 获取指定名称的模板
|
|
711
718
|
getTemplate(name) {
|
|
@@ -752,13 +759,14 @@ class ProTableComponent {
|
|
|
752
759
|
return false;
|
|
753
760
|
return this.rowDisabled ? this.rowDisabled(data) : false;
|
|
754
761
|
}
|
|
755
|
-
//
|
|
762
|
+
// 检查行是否被复选框选中(数据驱动模式)
|
|
756
763
|
isRowChecked(data) {
|
|
757
764
|
if (!this.showCheckbox)
|
|
758
765
|
return false;
|
|
759
|
-
|
|
766
|
+
// 直接读取数据对象的 checked 属性
|
|
767
|
+
return data.checked === true;
|
|
760
768
|
}
|
|
761
|
-
//
|
|
769
|
+
// 切换行的选中状态(数据驱动模式,保留用于兼容)
|
|
762
770
|
toggleRowChecked(data, checked, event) {
|
|
763
771
|
if (event) {
|
|
764
772
|
event.stopPropagation(); // 阻止事件冒泡,避免触发行点击
|
|
@@ -767,9 +775,21 @@ class ProTableComponent {
|
|
|
767
775
|
if (this.isRowDisabled(data)) {
|
|
768
776
|
return;
|
|
769
777
|
}
|
|
770
|
-
|
|
778
|
+
// 直接设置数据对象的 checked 属性
|
|
779
|
+
data.checked = checked;
|
|
780
|
+
// 同步更新 _selectedRowIds(用于跨页选中)
|
|
781
|
+
const id = this.getRowId(data);
|
|
782
|
+
if (id !== undefined) {
|
|
783
|
+
if (checked) {
|
|
784
|
+
this._selectedRowIds.add(id);
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
this._selectedRowIds.delete(id);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
// 同步更新 _selectedRows(用于兼容性)
|
|
791
|
+
const index = this._selectedRows.findIndex((row) => this.isSameRow(row, data));
|
|
771
792
|
if (checked) {
|
|
772
|
-
// 选中
|
|
773
793
|
if (index === -1) {
|
|
774
794
|
this._selectedRows.push(data);
|
|
775
795
|
}
|
|
@@ -777,19 +797,18 @@ class ProTableComponent {
|
|
|
777
797
|
this._selectedTableRow = data;
|
|
778
798
|
}
|
|
779
799
|
else {
|
|
780
|
-
// 取消选中
|
|
781
800
|
if (index > -1) {
|
|
782
801
|
this._selectedRows.splice(index, 1);
|
|
783
802
|
}
|
|
784
803
|
// 若当前高亮行为该行,则取消高亮
|
|
785
804
|
if (this._selectedTableRow &&
|
|
786
|
-
|
|
805
|
+
this.isSameRow(this._selectedTableRow, data)) {
|
|
787
806
|
this._selectedTableRow = null;
|
|
788
807
|
}
|
|
789
808
|
}
|
|
790
809
|
this.updateCheckAllStatus();
|
|
791
810
|
}
|
|
792
|
-
//
|
|
811
|
+
// 更新全选状态(数据驱动模式)
|
|
793
812
|
updateCheckAllStatus() {
|
|
794
813
|
if (!this.showCheckbox || !Array.isArray(this.dataSource)) {
|
|
795
814
|
this._checkedAll = false;
|
|
@@ -798,39 +817,120 @@ class ProTableComponent {
|
|
|
798
817
|
}
|
|
799
818
|
// 只计算可用的行(未禁用的行)
|
|
800
819
|
const availableRows = this.dataSource.filter((row) => !this.isRowDisabled(row));
|
|
801
|
-
|
|
820
|
+
// 基于数据对象的 checked 属性计算
|
|
821
|
+
const checkedCount = availableRows.filter((row) => row.checked === true).length;
|
|
802
822
|
const totalCount = availableRows.length;
|
|
803
823
|
this._checkedAll =
|
|
804
824
|
totalCount > 0 && checkedCount > 0 && checkedCount === totalCount;
|
|
805
825
|
this._indeterminate = checkedCount > 0 && checkedCount < totalCount;
|
|
806
826
|
}
|
|
807
|
-
//
|
|
827
|
+
// 全选/取消全选(数据驱动模式)
|
|
808
828
|
toggleCheckAll(checked, event) {
|
|
809
829
|
if (event) {
|
|
810
830
|
event.stopPropagation();
|
|
811
831
|
}
|
|
832
|
+
// 只处理可用的行(未禁用的行)
|
|
833
|
+
const availableRows = this.dataSource.filter((row) => !this.isRowDisabled(row));
|
|
834
|
+
// 批量设置 checked 属性
|
|
835
|
+
availableRows.forEach((row) => {
|
|
836
|
+
row.checked = checked;
|
|
837
|
+
// 同步更新 _selectedRowIds(用于跨页选中)
|
|
838
|
+
const id = this.getRowId(row);
|
|
839
|
+
if (id !== undefined) {
|
|
840
|
+
if (checked) {
|
|
841
|
+
this._selectedRowIds.add(id);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
this._selectedRowIds.delete(id);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
// 同步更新 _selectedRows(用于兼容性)
|
|
812
849
|
if (checked) {
|
|
813
|
-
|
|
814
|
-
this._selectedRows = this.dataSource.filter((row) => !this.isRowDisabled(row));
|
|
850
|
+
this._selectedRows = [...availableRows];
|
|
815
851
|
// 同步设置高亮选中行为第一条可选数据
|
|
816
|
-
const availableRows = this._selectedRows;
|
|
817
852
|
this._selectedTableRow =
|
|
818
853
|
availableRows.length > 0 ? availableRows[0] : null;
|
|
819
854
|
}
|
|
820
855
|
else {
|
|
821
|
-
// 取消全选
|
|
822
856
|
this._selectedRows = [];
|
|
823
857
|
// 取消高亮
|
|
824
858
|
this._selectedTableRow = null;
|
|
825
859
|
}
|
|
826
860
|
this.updateCheckAllStatus();
|
|
827
861
|
}
|
|
828
|
-
//
|
|
862
|
+
// 获取选中的行数据(保留用于兼容性)
|
|
829
863
|
getSelectedRows() {
|
|
830
|
-
return this.
|
|
864
|
+
return this.getCheckedRows();
|
|
831
865
|
}
|
|
832
|
-
//
|
|
866
|
+
// 处理行 checkbox 变化事件(数据驱动模式)
|
|
867
|
+
handleRowCheckedChange(data, checked) {
|
|
868
|
+
if (this.isRowDisabled(data)) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
// 数据对象的 checked 属性已经通过双向绑定自动更新
|
|
872
|
+
// 这里只需要同步更新 _selectedRowIds 和 _selectedRows
|
|
873
|
+
// 同步更新 _selectedRowIds(用于跨页选中)
|
|
874
|
+
const id = this.getRowId(data);
|
|
875
|
+
if (id !== undefined) {
|
|
876
|
+
if (checked) {
|
|
877
|
+
this._selectedRowIds.add(id);
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
this._selectedRowIds.delete(id);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
// 同步更新 _selectedRows(用于兼容性)
|
|
884
|
+
const index = this._selectedRows.findIndex((row) => this.isSameRow(row, data));
|
|
885
|
+
if (checked) {
|
|
886
|
+
if (index === -1) {
|
|
887
|
+
this._selectedRows.push(data);
|
|
888
|
+
}
|
|
889
|
+
// 勾选复选框时同步设置高亮选中行
|
|
890
|
+
this._selectedTableRow = data;
|
|
891
|
+
}
|
|
892
|
+
else {
|
|
893
|
+
if (index > -1) {
|
|
894
|
+
this._selectedRows.splice(index, 1);
|
|
895
|
+
}
|
|
896
|
+
// 若当前高亮行为该行,则取消高亮
|
|
897
|
+
if (this._selectedTableRow &&
|
|
898
|
+
this.isSameRow(this._selectedTableRow, data)) {
|
|
899
|
+
this._selectedTableRow = null;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
// 更新全选状态
|
|
903
|
+
this.updateCheckAllStatus();
|
|
904
|
+
}
|
|
905
|
+
// 刷新全选状态(用于其他场景)
|
|
906
|
+
refreshCheckAllStatus() {
|
|
907
|
+
this.updateCheckAllStatus();
|
|
908
|
+
}
|
|
909
|
+
// 获取行的唯一标识(用于跨页选中)
|
|
910
|
+
getRowId(data) {
|
|
911
|
+
var _a, _b;
|
|
912
|
+
return (_b = (_a = data.id) !== null && _a !== void 0 ? _a : data.key) !== null && _b !== void 0 ? _b : undefined;
|
|
913
|
+
}
|
|
914
|
+
// 判断两行是否为同一行
|
|
915
|
+
isSameRow(row1, row2) {
|
|
916
|
+
const id1 = this.getRowId(row1);
|
|
917
|
+
const id2 = this.getRowId(row2);
|
|
918
|
+
if (id1 !== undefined && id2 !== undefined) {
|
|
919
|
+
return id1 === id2;
|
|
920
|
+
}
|
|
921
|
+
// fallback 到 JSON 比较
|
|
922
|
+
return JSON.stringify(row1) === JSON.stringify(row2);
|
|
923
|
+
}
|
|
924
|
+
// 清空选中的行(数据驱动模式)
|
|
833
925
|
clearSelectedRows() {
|
|
926
|
+
// 清空当前数据源中所有项的 checked 状态
|
|
927
|
+
if (Array.isArray(this.dataSource)) {
|
|
928
|
+
this.dataSource.forEach((row) => {
|
|
929
|
+
row.checked = false;
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
// 清空选中集合
|
|
933
|
+
this._selectedRowIds.clear();
|
|
834
934
|
this._selectedRows = [];
|
|
835
935
|
this._checkedAll = false;
|
|
836
936
|
this._indeterminate = false;
|
|
@@ -907,6 +1007,8 @@ class ProTableComponent {
|
|
|
907
1007
|
this._pageInfo.pageIndex > 1) {
|
|
908
1008
|
this._pageInfo.pageIndex = this._pageInfo.pageIndex - 1;
|
|
909
1009
|
}
|
|
1010
|
+
// 保存删除前的数据源(用于删除后查询时移除被删除项的选中状态)
|
|
1011
|
+
const previousDataSource = afterDelete && this.showCheckbox ? [...this.dataSource] : [];
|
|
910
1012
|
this._loading = true;
|
|
911
1013
|
if (this.request) {
|
|
912
1014
|
try {
|
|
@@ -916,7 +1018,38 @@ class ProTableComponent {
|
|
|
916
1018
|
} }, (this.sortMode === "server"
|
|
917
1019
|
? { sort: this.buildServerSortPayload() }
|
|
918
1020
|
: {})));
|
|
919
|
-
|
|
1021
|
+
// 自动注入 checked 字段,支持跨页选中
|
|
1022
|
+
if (this.showCheckbox) {
|
|
1023
|
+
this.dataSource = (result.data || []).map((item) => {
|
|
1024
|
+
const id = this.getRowId(item);
|
|
1025
|
+
// 如果数据已有 checked 属性,保留;否则根据 _selectedRowIds 判断
|
|
1026
|
+
const checked = item.checked !== undefined
|
|
1027
|
+
? item.checked
|
|
1028
|
+
: id !== undefined
|
|
1029
|
+
? this._selectedRowIds.has(id)
|
|
1030
|
+
: false;
|
|
1031
|
+
return Object.assign(Object.assign({}, item), { checked: checked });
|
|
1032
|
+
});
|
|
1033
|
+
// 删除后查询:移除被删除项的选中状态
|
|
1034
|
+
if (afterDelete && previousDataSource.length > 0) {
|
|
1035
|
+
const newDataIds = new Set(this.dataSource.map((item) => this.getRowId(item)));
|
|
1036
|
+
// 遍历之前的数据源,如果不在新数据源中,说明被删除了,需要清除其选中状态
|
|
1037
|
+
previousDataSource.forEach((oldItem) => {
|
|
1038
|
+
const oldId = this.getRowId(oldItem);
|
|
1039
|
+
if (oldId !== undefined && !newDataIds.has(oldId)) {
|
|
1040
|
+
// 被删除的项,从选中集合中移除
|
|
1041
|
+
this._selectedRowIds.delete(oldId);
|
|
1042
|
+
// 如果数据对象还在其他地方引用,清除其选中状态
|
|
1043
|
+
if (oldItem.checked !== undefined) {
|
|
1044
|
+
oldItem.checked = false;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
this.dataSource = result.data || [];
|
|
1052
|
+
}
|
|
920
1053
|
this.summaryData = result.summaryData || null;
|
|
921
1054
|
// 本地排序模式:拿到数据后在前端排序
|
|
922
1055
|
if (this.sortMode === "local") {
|
|
@@ -937,15 +1070,13 @@ class ProTableComponent {
|
|
|
937
1070
|
finally {
|
|
938
1071
|
this._loading = false;
|
|
939
1072
|
this._selectedTableRow = null;
|
|
940
|
-
// 清空选中行(可选,根据业务需求决定是否保留跨页选中)
|
|
941
|
-
// this.clearSelectedRows();
|
|
942
1073
|
}
|
|
943
1074
|
}
|
|
944
1075
|
else {
|
|
945
1076
|
console.warn("未提供 _request 回调函数");
|
|
946
1077
|
this._loading = false;
|
|
947
1078
|
}
|
|
948
|
-
|
|
1079
|
+
// 不再调用 clearSelectedRows(),保留跨页选中状态
|
|
949
1080
|
});
|
|
950
1081
|
}
|
|
951
1082
|
// 触发列排序变更
|
|
@@ -1052,7 +1183,7 @@ class ProTableComponent {
|
|
|
1052
1183
|
ProTableComponent.decorators = [
|
|
1053
1184
|
{ type: Component, args: [{
|
|
1054
1185
|
selector: "app-pro-table",
|
|
1055
|
-
template: "<app-page-container [title]=\"title\">\r\n <ng-template #header>\r\n <app-table-search-bar\r\n *ngIf=\"showSearchBar\"\r\n [labelWidth]=\"labelWidth\"\r\n [labelAlign]=\"labelAlign\"\r\n >\r\n <ng-template #leftContent>\r\n <nz-form-item\r\n *ngFor=\"let column of _searchFiledColumns\"\r\n [ngClass]=\"getFormItemClassName(column)\"\r\n >\r\n <nz-form-label *ngIf=\"!getFieldProps(column).hideLabel\" nzNoColon>\r\n <!-- \u68C0\u67E5\u662F\u5426\u6709\u81EA\u5B9A\u4E49label\u6A21\u677F -->\r\n <ng-container\r\n *ngIf=\"\r\n column.customLabelRender &&\r\n getLabelTemplate(column.customLabelRender);\r\n else defaultLabel\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"getLabelTemplate(column.customLabelRender)\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: column,\r\n column: column,\r\n fieldProps: getFieldProps(column)\r\n }\"\r\n >\r\n </ng-container>\r\n </ng-container>\r\n <ng-template #defaultLabel>\r\n {{ getFieldProps(column).label || column.title }}\r\n </ng-template>\r\n </nz-form-label>\r\n <nz-form-control *ngIf=\"column.valueType === 'input'\">\r\n <input\r\n nz-input\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [placeholder]=\"getFieldProps(column).placeHolder\"\r\n [disabled]=\"getFieldProps(column).disabled\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n />\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'inputPlate'\">\r\n <app-plate-input\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n ></app-plate-input>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'select'\">\r\n <nz-select\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzAllowClear]=\"getFieldProps(column).allowClear\"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [nzOptions]=\"getFieldProps(column).options\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n >\r\n </nz-select>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'selectMultiple'\">\r\n <nz-select\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzAllowClear]=\"getFieldProps(column).allowClear\"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [nzOptions]=\"getFieldProps(column).options\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n nzMode=\"multiple\"\r\n >\r\n </nz-select>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'date'\">\r\n <nz-date-picker\r\n [nzShowTime]=\"getFieldProps(column).showTime\"\r\n [nzFormat]=\"getFieldProps(column).format\"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [nzAllowClear]=\"getFieldProps(column).allowClear\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzMode]=\"getFieldProps(column).mode\"\r\n ></nz-date-picker>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'checkbox'\">\r\n <nz-checkbox-group\r\n [class]=\"\r\n getFieldProps(column).noStyle\r\n ? 'pro-table-checkboxgroup-nostyle'\r\n : ''\r\n \"\r\n [(ngModel)]=\"getFieldProps(column).options\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n (ngModelChange)=\"\r\n handleFieldCheckBoxChange(\r\n $event,\r\n getFieldProps(column).name || column.prop\r\n )\r\n \"\r\n ></nz-checkbox-group>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'autoComplete'\">\r\n <input\r\n nz-input\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column)?.name || column.prop]\r\n \"\r\n (input)=\"handleAutoCompleteInput($event, column)\"\r\n [nzAutocomplete]=\"auto\"\r\n [disabled]=\"getFieldProps(column)?.disabled\"\r\n [placeholder]=\"getFieldProps(column)?.placeHolder\"\r\n />\r\n <nz-autocomplete\r\n [nzBackfill]=\"getFieldProps(column).backFill\"\r\n [nzDefaultActiveFirstOption]=\"\r\n getFieldProps(column).defaultActiveFirstOption\r\n \"\r\n [nzWidth]=\"getFieldProps(column).width\"\r\n #auto\r\n >\r\n <nz-auto-option\r\n *ngFor=\"let option of getAutoCompleteDataSource(column)\"\r\n [nzValue]=\"\r\n getFieldProps(column).returnFullData ? option : option.value\r\n \"\r\n [nzLabel]=\"option.label\"\r\n [nzDisabled]=\"option.disabled\"\r\n >\r\n {{ option.label }}\r\n </nz-auto-option>\r\n </nz-autocomplete>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'custom'\">\r\n <app-dynamic-search-field\r\n [component]=\"getFieldProps(column).component\"\r\n [value]=\"_searchParams[getFieldProps(column).name || column.prop]\"\r\n [props]=\"getFieldProps(column)\"\r\n (valueChange)=\"\r\n setFieldValue(getFieldProps(column).name || column.prop, $event)\r\n \"\r\n ></app-dynamic-search-field>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'inputNumber'\">\r\n <nz-input-number\r\n [style.width]=\"'100%'\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n [nzFormatter]=\"getFieldProps(column).formatterPercent\"\r\n [nzParser]=\"getFieldProps(column).parserPercent\"\r\n ></nz-input-number>\r\n </nz-form-control>\r\n </nz-form-item>\r\n </ng-template>\r\n <ng-template #actionTextBtn>\r\n <nz-space [nzSize]=\"4\">\r\n <nz-space-item *ngIf=\"showSearchBtn\">\r\n <button nz-button nzType=\"primary\" (click)=\"handleSearch()\">\r\n {{ confirmBtnText }}\r\n </button>\r\n </nz-space-item>\r\n <nz-space-item *ngIf=\"showClearBtn\">\r\n <button nz-button (click)=\"handleResetForm()\">\r\n {{ clearBtnText }}\r\n </button>\r\n </nz-space-item>\r\n </nz-space>\r\n </ng-template>\r\n <ng-template #actionImgBtn>\r\n <nz-space>\r\n <ng-container *ngTemplateOutlet=\"imgActionBarTpl\"></ng-container>\r\n <nz-space-item class=\"setting-space-item\" *ngIf=\"showColumnSetting\">\r\n <app-colmuns-setting\r\n [columns]=\"columns\"\r\n [selectedColumns]=\"_serverColumns\"\r\n [tableName]=\"tableName\"\r\n (afterConfirm)=\"handleColumnsSettingConfirm()\"\r\n ></app-colmuns-setting>\r\n </nz-space-item>\r\n </nz-space>\r\n </ng-template>\r\n </app-table-search-bar>\r\n </ng-template>\r\n <ng-template #body>\r\n <div class=\"mb-12\">\r\n <ng-container *ngIf=\"showActionBar\">\r\n <ng-container *ngTemplateOutlet=\"actionBarTpl\"></ng-container>\r\n </ng-container>\r\n </div>\r\n <ng-container *ngIf=\"customTableRender\">\r\n <ng-container *ngTemplateOutlet=\"customTableRender\"></ng-container>\r\n </ng-container>\r\n <nz-table\r\n *ngIf=\"!customTableRender\"\r\n #basicTable\r\n nzSize=\"small\"\r\n nzShowSizeChanger\r\n [nzBordered]=\"bordered\"\r\n [nzOuterBordered]=\"outerBordered\"\r\n [nzData]=\"dataSource\"\r\n [nzPageIndex]=\"_pageInfo.pageIndex\"\r\n [nzPageSize]=\"_pageInfo.pageSize\"\r\n [nzTotal]=\"_pageInfo.total\"\r\n [nzPageSizeOptions]=\"_pageInfo.pageSizeOptions\"\r\n [nzShowPagination]=\"showPagination\"\r\n [nzShowTotal]=\"totalTemplate\"\r\n [nzLoading]=\"_loading\"\r\n [nzFrontPagination]=\"frontPagination\"\r\n [nzScroll]=\"scroll\"\r\n (nzPageIndexChange)=\"handlePageIndexChange($event)\"\r\n (nzPageSizeChange)=\"handlePageSizeChange($event)\"\r\n >\r\n <thead>\r\n <tr>\r\n <!-- \u590D\u9009\u6846\u5217\uFF08\u5F53 showCheckbox=true \u65F6\u663E\u793A\uFF09 -->\r\n <th\r\n *ngIf=\"showCheckbox\"\r\n [nzWidth]=\"'50px'\"\r\n [nzAlign]=\"'center'\"\r\n style=\"text-align: center\"\r\n >\r\n <label\r\n nz-checkbox\r\n [(ngModel)]=\"_checkedAll\"\r\n [nzIndeterminate]=\"_indeterminate\"\r\n (ngModelChange)=\"toggleCheckAll($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n ></label>\r\n </th>\r\n <th\r\n *ngFor=\"let column of _columns\"\r\n [nzWidth]=\"column.width\"\r\n [nzAlign]=\"column.align\"\r\n [nzLeft]=\"column.fixedLeft\"\r\n [nzRight]=\"column.fixedRight\"\r\n [nzShowSort]=\"!!column.sorter\"\r\n [nzSortOrder]=\"getSortOrder(column.prop)\"\r\n (nzSortOrderChange)=\"onSortChange(column.prop, $event)\"\r\n >\r\n {{ column.title }}\r\n </th>\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n <tr\r\n style=\"cursor: pointer\"\r\n *ngFor=\"let data; let i = index; of: basicTable.data\"\r\n [ngClass]=\"{\r\n 'ant-table-custom-row-selected': !!getTableRowChecked(data),\r\n 'ant-table-custom-row-even': i % 2 === 0,\r\n 'ant-table-custom-row-odd': i % 2 !== 0\r\n }\"\r\n (click)=\"handleTableRowClick(data)\"\r\n (dblclick)=\"handleTableRowDbClick(data)\"\r\n >\r\n <!-- \u590D\u9009\u6846\u5217\uFF08\u5F53 showCheckbox=true \u65F6\u663E\u793A\uFF09 -->\r\n <td\r\n *ngIf=\"showCheckbox\"\r\n [nzAlign]=\"'center'\"\r\n style=\"text-align: center\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n <label\r\n nz-checkbox\r\n [ngModel]=\"isRowChecked(data)\"\r\n [nzDisabled]=\"isRowDisabled(data)\"\r\n (ngModelChange)=\"toggleRowChecked(data, $event)\"\r\n ></label>\r\n </td>\r\n <td\r\n *ngFor=\"let column of _columns\"\r\n [nzLeft]=\"column.fixedLeft\"\r\n [nzRight]=\"column.fixedRight\"\r\n [nzAlign]=\"column.align\"\r\n class=\"pro-ellipsis\"\r\n [title]=\"data[column.prop]\"\r\n >\r\n <!-- \u68C0\u67E5\u662F\u5426\u6709\u81EA\u5B9A\u4E49\u6A21\u677F -->\r\n <ng-container\r\n *ngIf=\"\r\n column.customRender && getTemplate(column.customRender);\r\n let template\r\n \"\r\n >\r\n <ng-template\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: data,\r\n data: data,\r\n column: column,\r\n index: i,\r\n pageInfo: _pageInfo\r\n }\"\r\n >\r\n </ng-template>\r\n </ng-container>\r\n\r\n <!-- \u9ED8\u8BA4\u6E32\u67D3\u903B\u8F91 -->\r\n <ng-container\r\n *ngIf=\"!column.customRender || !getTemplate(column.customRender)\"\r\n >\r\n {{ data[column.prop] }}\r\n </ng-container>\r\n </td>\r\n </tr>\r\n <tr *ngIf=\"summaryData && _pageInfo.total > 0\">\r\n <!-- \u6C47\u603B\u884C\u7684\u590D\u9009\u6846\u5217\uFF08\u5F53 showCheckbox=true \u65F6\u663E\u793A\uFF0C\u4F46\u4E3A\u7A7A\uFF09 -->\r\n <td\r\n *ngIf=\"showCheckbox\"\r\n style=\"font-weight: bold; border-right: 1px solid #e8e8e8\"\r\n ></td>\r\n <td\r\n *ngFor=\"let column; let i = index; of: _columns\"\r\n [nzLeft]=\"column.fixedLeft\"\r\n [nzRight]=\"column.fixedRight\"\r\n style=\"font-weight: bold; border-right: 1px solid #e8e8e8\"\r\n [nzAlign]=\"column.align\"\r\n >\r\n <span *ngIf=\"i === 0\">\u603B\u8BA1</span>\r\n <ng-container *ngIf=\"i !== 0 && column.summary\">\r\n {{\r\n column.summary?.format\r\n ? column.summary?.format(\r\n summaryData[column.summary?.name || column.prop]\r\n )\r\n : summaryData[column.summary?.name || column.prop]\r\n }}\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <ng-template #totalTemplate let-total\r\n >\u5171 {{ _pageInfo.total }} \u6761\u8BB0\u5F55</ng-template\r\n >\r\n </nz-table>\r\n </ng-template>\r\n</app-page-container>\r\n",
|
|
1186
|
+
template: "<app-page-container\r\n [title]=\"title\"\r\n [showHeader]=\"showSearchBar\"\r\n ngClass=\"pro-table-container\"\r\n>\r\n <ng-template #header>\r\n <app-table-search-bar\r\n *ngIf=\"showSearchBar\"\r\n [labelWidth]=\"labelWidth\"\r\n [labelAlign]=\"labelAlign\"\r\n >\r\n <ng-template #leftContent>\r\n <nz-form-item\r\n *ngFor=\"let column of _searchFiledColumns\"\r\n [ngClass]=\"getFormItemClassName(column)\"\r\n >\r\n <nz-form-label *ngIf=\"!getFieldProps(column).hideLabel\" nzNoColon>\r\n <!-- \u68C0\u67E5\u662F\u5426\u6709\u81EA\u5B9A\u4E49label\u6A21\u677F -->\r\n <ng-container\r\n *ngIf=\"\r\n column.customLabelRender &&\r\n getLabelTemplate(column.customLabelRender);\r\n else defaultLabel\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"getLabelTemplate(column.customLabelRender)\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: column,\r\n column: column,\r\n fieldProps: getFieldProps(column)\r\n }\"\r\n >\r\n </ng-container>\r\n </ng-container>\r\n <ng-template #defaultLabel>\r\n {{ getFieldProps(column).label || column.title }}\r\n </ng-template>\r\n </nz-form-label>\r\n <nz-form-control *ngIf=\"column.valueType === 'input'\">\r\n <input\r\n nz-input\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [placeholder]=\"getFieldProps(column).placeHolder\"\r\n [disabled]=\"getFieldProps(column).disabled\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n />\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'inputPlate'\">\r\n <app-plate-input\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n ></app-plate-input>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'select'\">\r\n <nz-select\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzAllowClear]=\"getFieldProps(column).allowClear\"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [nzOptions]=\"getFieldProps(column).options\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n >\r\n </nz-select>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'selectMultiple'\">\r\n <nz-select\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzAllowClear]=\"getFieldProps(column).allowClear\"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [name]=\"getFieldProps(column).name || column.prop\"\r\n [nzOptions]=\"getFieldProps(column).options\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n nzMode=\"multiple\"\r\n >\r\n </nz-select>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'date'\">\r\n <nz-date-picker\r\n [nzShowTime]=\"getFieldProps(column).showTime\"\r\n [nzFormat]=\"getFieldProps(column).format\"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [nzAllowClear]=\"getFieldProps(column).allowClear\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzMode]=\"getFieldProps(column).mode\"\r\n ></nz-date-picker>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'checkbox'\">\r\n <nz-checkbox-group\r\n [class]=\"\r\n getFieldProps(column).noStyle\r\n ? 'pro-table-checkboxgroup-nostyle'\r\n : ''\r\n \"\r\n [(ngModel)]=\"getFieldProps(column).options\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n (ngModelChange)=\"\r\n handleFieldCheckBoxChange(\r\n $event,\r\n getFieldProps(column).name || column.prop\r\n )\r\n \"\r\n ></nz-checkbox-group>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'autoComplete'\">\r\n <input\r\n nz-input\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column)?.name || column.prop]\r\n \"\r\n (input)=\"handleAutoCompleteInput($event, column)\"\r\n [nzAutocomplete]=\"auto\"\r\n [disabled]=\"getFieldProps(column)?.disabled\"\r\n [placeholder]=\"getFieldProps(column)?.placeHolder\"\r\n />\r\n <nz-autocomplete\r\n [nzBackfill]=\"getFieldProps(column).backFill\"\r\n [nzDefaultActiveFirstOption]=\"\r\n getFieldProps(column).defaultActiveFirstOption\r\n \"\r\n [nzWidth]=\"getFieldProps(column).width\"\r\n #auto\r\n >\r\n <nz-auto-option\r\n *ngFor=\"let option of getAutoCompleteDataSource(column)\"\r\n [nzValue]=\"\r\n getFieldProps(column).returnFullData ? option : option.value\r\n \"\r\n [nzLabel]=\"option.label\"\r\n [nzDisabled]=\"option.disabled\"\r\n >\r\n {{ option.label }}\r\n </nz-auto-option>\r\n </nz-autocomplete>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'custom'\">\r\n <app-dynamic-search-field\r\n [component]=\"getFieldProps(column).component\"\r\n [value]=\"_searchParams[getFieldProps(column).name || column.prop]\"\r\n [props]=\"getFieldProps(column)\"\r\n (valueChange)=\"\r\n setFieldValue(getFieldProps(column).name || column.prop, $event)\r\n \"\r\n ></app-dynamic-search-field>\r\n </nz-form-control>\r\n <nz-form-control *ngIf=\"column.valueType === 'inputNumber'\">\r\n <nz-input-number\r\n [style.width]=\"'100%'\"\r\n [(ngModel)]=\"\r\n _searchParams[getFieldProps(column).name || column.prop]\r\n \"\r\n [nzPlaceHolder]=\"getFieldProps(column).placeHolder\"\r\n [nzDisabled]=\"getFieldProps(column).disabled\"\r\n [nzFormatter]=\"getFieldProps(column).formatterPercent\"\r\n [nzParser]=\"getFieldProps(column).parserPercent\"\r\n ></nz-input-number>\r\n </nz-form-control>\r\n </nz-form-item>\r\n </ng-template>\r\n <ng-template #actionTextBtn>\r\n <nz-space [nzSize]=\"4\">\r\n <nz-space-item *ngIf=\"showSearchBtn\">\r\n <button nz-button nzType=\"primary\" (click)=\"handleSearch()\">\r\n {{ confirmBtnText }}\r\n </button>\r\n </nz-space-item>\r\n <nz-space-item *ngIf=\"showClearBtn\">\r\n <button nz-button (click)=\"handleResetForm()\">\r\n {{ clearBtnText }}\r\n </button>\r\n </nz-space-item>\r\n </nz-space>\r\n </ng-template>\r\n <ng-template #actionImgBtn>\r\n <nz-space>\r\n <ng-container *ngTemplateOutlet=\"imgActionBarTpl\"></ng-container>\r\n <nz-space-item class=\"setting-space-item\" *ngIf=\"showColumnSetting\">\r\n <app-colmuns-setting\r\n [columns]=\"columns\"\r\n [selectedColumns]=\"_serverColumns\"\r\n [tableName]=\"tableName\"\r\n (afterConfirm)=\"handleColumnsSettingConfirm()\"\r\n ></app-colmuns-setting>\r\n </nz-space-item>\r\n </nz-space>\r\n </ng-template>\r\n </app-table-search-bar>\r\n </ng-template>\r\n\r\n <ng-template #body>\r\n <div class=\"mb-12\">\r\n <ng-container *ngIf=\"showActionBar\">\r\n <ng-container *ngTemplateOutlet=\"actionBarTpl\"></ng-container>\r\n </ng-container>\r\n </div>\r\n <ng-container *ngIf=\"customTableRender\">\r\n <ng-container *ngTemplateOutlet=\"customTableRender\"></ng-container>\r\n </ng-container>\r\n <nz-table\r\n *ngIf=\"!customTableRender\"\r\n #dynamicTable\r\n nzSize=\"small\"\r\n nzShowSizeChanger\r\n [nzBordered]=\"bordered\"\r\n [nzOuterBordered]=\"outerBordered\"\r\n [nzData]=\"dataSource\"\r\n [nzPageIndex]=\"_pageInfo.pageIndex\"\r\n [nzPageSize]=\"_pageInfo.pageSize\"\r\n [nzTotal]=\"_pageInfo.total\"\r\n [nzPageSizeOptions]=\"_pageInfo.pageSizeOptions\"\r\n [nzShowPagination]=\"showPagination\"\r\n [nzShowTotal]=\"totalTemplate\"\r\n [nzLoading]=\"_loading\"\r\n [nzFrontPagination]=\"frontPagination\"\r\n [nzScroll]=\"scroll\"\r\n (nzPageIndexChange)=\"handlePageIndexChange($event)\"\r\n (nzPageSizeChange)=\"handlePageSizeChange($event)\"\r\n >\r\n <thead>\r\n <tr>\r\n <!-- \u590D\u9009\u6846\u5217\uFF08\u5F53 showCheckbox=true \u65F6\u663E\u793A\uFF09 -->\r\n <th\r\n *ngIf=\"showCheckbox\"\r\n [nzWidth]=\"'50px'\"\r\n [nzAlign]=\"'center'\"\r\n style=\"text-align: center\"\r\n [(nzChecked)]=\"_checkedAll\"\r\n [nzIndeterminate]=\"_indeterminate\"\r\n (nzCheckedChange)=\"toggleCheckAll($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n ></th>\r\n <th\r\n *ngFor=\"let column of _columns\"\r\n [nzWidth]=\"column.width\"\r\n [nzAlign]=\"column.align\"\r\n [nzLeft]=\"column.fixedLeft\"\r\n [nzRight]=\"column.fixedRight\"\r\n [nzShowSort]=\"!!column.sorter\"\r\n [nzSortOrder]=\"getSortOrder(column.prop)\"\r\n (nzSortOrderChange)=\"onSortChange(column.prop, $event)\"\r\n >\r\n {{ column.title }}\r\n </th>\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n <tr\r\n style=\"cursor: pointer\"\r\n *ngFor=\"let data; let i = index; of: dynamicTable.data\"\r\n [ngClass]=\"{\r\n 'ant-table-custom-row-selected': !!getTableRowChecked(data),\r\n 'ant-table-custom-row-even': i % 2 === 0,\r\n 'ant-table-custom-row-odd': i % 2 !== 0\r\n }\"\r\n (click)=\"handleTableRowClick(data)\"\r\n (dblclick)=\"handleTableRowDbClick(data)\"\r\n >\r\n <!-- \u590D\u9009\u6846\u5217\uFF08\u5F53 showCheckbox=true \u65F6\u663E\u793A\uFF09 -->\r\n <td\r\n *ngIf=\"showCheckbox\"\r\n [nzAlign]=\"'center'\"\r\n style=\"text-align: center\"\r\n [(nzChecked)]=\"data.checked\"\r\n [nzDisabled]=\"isRowDisabled(data)\"\r\n (nzCheckedChange)=\"handleRowCheckedChange(data, $event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n ></td>\r\n <td\r\n *ngFor=\"let column of _columns\"\r\n [nzLeft]=\"column.fixedLeft\"\r\n [nzRight]=\"column.fixedRight\"\r\n [nzAlign]=\"column.align\"\r\n class=\"pro-ellipsis\"\r\n [title]=\"data[column.prop]\"\r\n >\r\n <!-- \u68C0\u67E5\u662F\u5426\u6709\u81EA\u5B9A\u4E49\u6A21\u677F -->\r\n <ng-container\r\n *ngIf=\"\r\n column.customRender && getTemplate(column.customRender);\r\n let template\r\n \"\r\n >\r\n <ng-template\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: data,\r\n data: data,\r\n column: column,\r\n index: i,\r\n pageInfo: _pageInfo\r\n }\"\r\n >\r\n </ng-template>\r\n </ng-container>\r\n\r\n <!-- \u9ED8\u8BA4\u6E32\u67D3\u903B\u8F91 -->\r\n <ng-container\r\n *ngIf=\"!column.customRender || !getTemplate(column.customRender)\"\r\n >\r\n {{ data[column.prop] }}\r\n </ng-container>\r\n </td>\r\n </tr>\r\n <tr *ngIf=\"summaryData && _pageInfo.total > 0\">\r\n <!-- \u6C47\u603B\u884C\u7684\u590D\u9009\u6846\u5217\uFF08\u5F53 showCheckbox=true \u65F6\u663E\u793A\uFF0C\u4F46\u4E3A\u7A7A\uFF09 -->\r\n <td\r\n *ngIf=\"showCheckbox\"\r\n style=\"font-weight: bold; border-right: 1px solid #e8e8e8\"\r\n ></td>\r\n <td\r\n *ngFor=\"let column; let i = index; of: _columns\"\r\n [nzLeft]=\"column.fixedLeft\"\r\n [nzRight]=\"column.fixedRight\"\r\n style=\"font-weight: bold; border-right: 1px solid #e8e8e8\"\r\n [nzAlign]=\"column.align\"\r\n >\r\n <span *ngIf=\"i === 0\">\u603B\u8BA1</span>\r\n <ng-container *ngIf=\"i !== 0 && column.summary\">\r\n {{\r\n column.summary?.format\r\n ? column.summary?.format(\r\n summaryData[column.summary?.name || column.prop]\r\n )\r\n : summaryData[column.summary?.name || column.prop]\r\n }}\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <ng-template #totalTemplate let-total\r\n >\u5171 {{ _pageInfo.total }} \u6761\u8BB0\u5F55</ng-template\r\n >\r\n </nz-table>\r\n </ng-template>\r\n</app-page-container>\r\n",
|
|
1056
1187
|
styles: [".pro-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}::ng-deep .setting-space-item{margin-right:0!important}::ng-deep .pro-table-checkboxgroup-nostyle{white-space:nowrap}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body table{border-collapse:separate;border-spacing:0}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-tbody>tr>td{border-right:1px solid #e8e8e8!important}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-thead>tr>th{border-bottom:1px solid #e8e8e8!important;border-right:1px solid #e8e8e8!important;white-space:nowrap}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-tbody>tr>td:first-child,::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-thead>tr>th:first-child{border-left:none!important}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-cell-fix-left,::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-cell-fix-right,::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-header .ant-table-thead>tr>th.ant-table-cell-fix-left,::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-header .ant-table-thead>tr>th.ant-table-cell-fix-right{border-bottom:1px solid #e8e8e8!important;border-right:1px solid #e8e8e8!important}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-header .ant-table-thead>tr>th{border-top:1px solid #e8e8e8!important}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-tbody>tr>td:last-child,::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-thead>tr>th:last-child{border-right:1px solid #e8e8e8!important}::ng-deep .ant-table-bordered .ant-table-container .ant-table-content .ant-table-body .ant-table-tbody>tr:last-child>td{border-bottom:1px solid #e8e8e8!important}::ng-deep .table-search-bar-left .ant-form-item{margin-bottom:8px}"]
|
|
1057
1188
|
},] }
|
|
1058
1189
|
];
|
|
@@ -1099,19 +1230,21 @@ ProTableComponent.propDecorators = {
|
|
|
1099
1230
|
class PageContainerComponent {
|
|
1100
1231
|
constructor() {
|
|
1101
1232
|
this.title = "";
|
|
1233
|
+
this.showHeader = true;
|
|
1102
1234
|
}
|
|
1103
1235
|
ngOnInit() { }
|
|
1104
1236
|
}
|
|
1105
1237
|
PageContainerComponent.decorators = [
|
|
1106
1238
|
{ type: Component, args: [{
|
|
1107
1239
|
selector: "app-page-container",
|
|
1108
|
-
template: "<nz-card\r\n [nzBorderless]=\"true\"\r\n [nzBodyStyle]=\"{ padding: '10px', width: '100%' }\"\r\n>\r\n <div class=\"page-container-title\" *ngIf=\"title\">{{ title }}</div>\r\n <div class=\"page-container-header\">\r\n <ng-container *ngTemplateOutlet=\"headerTpl\"></ng-container>\r\n </div>\r\n <div class=\"page-container-body\">\r\n <ng-container *ngTemplateOutlet=\"bodyTpl\"></ng-container>\r\n </div>\r\n</nz-card>\r\n",
|
|
1240
|
+
template: "<nz-card\r\n [nzBorderless]=\"true\"\r\n [nzBodyStyle]=\"{ padding: '10px', width: '100%' }\"\r\n>\r\n <div class=\"page-container-title\" *ngIf=\"title\">{{ title }}</div>\r\n <div class=\"page-container-header\" *ngIf=\"showHeader\">\r\n <ng-container *ngTemplateOutlet=\"headerTpl\"></ng-container>\r\n </div>\r\n <div class=\"page-container-body\">\r\n <ng-container *ngTemplateOutlet=\"bodyTpl\"></ng-container>\r\n </div>\r\n</nz-card>\r\n",
|
|
1109
1241
|
styles: [".page-container-title{border-left:3px solid #096dd9;color:#1d1d1d;font-size:16px;margin-bottom:16px;padding-left:10px}.page-container-body,.page-container-header{box-sizing:border-box;padding:7px}"]
|
|
1110
1242
|
},] }
|
|
1111
1243
|
];
|
|
1112
1244
|
PageContainerComponent.ctorParameters = () => [];
|
|
1113
1245
|
PageContainerComponent.propDecorators = {
|
|
1114
1246
|
title: [{ type: Input }],
|
|
1247
|
+
showHeader: [{ type: Input }],
|
|
1115
1248
|
headerTpl: [{ type: ContentChild, args: ["header",] }],
|
|
1116
1249
|
bodyTpl: [{ type: ContentChild, args: ["body",] }]
|
|
1117
1250
|
};
|
|
@@ -1718,6 +1851,7 @@ class AntdFormService {
|
|
|
1718
1851
|
this.formStore = {};
|
|
1719
1852
|
this.formModifyType = "create";
|
|
1720
1853
|
// ==================== 私有属性 ====================
|
|
1854
|
+
this.formRegisterStore = {};
|
|
1721
1855
|
this.labelWidth = "120px";
|
|
1722
1856
|
this.labelAlign = "right";
|
|
1723
1857
|
this.labelObservers = {};
|
|
@@ -1732,18 +1866,62 @@ class AntdFormService {
|
|
|
1732
1866
|
};
|
|
1733
1867
|
}
|
|
1734
1868
|
// ==================== 表单创建和初始化 ====================
|
|
1869
|
+
// 判断是否为嵌套 FormGroup 配置
|
|
1870
|
+
isFormGroupConfig(config) {
|
|
1871
|
+
return (typeof config === "object" &&
|
|
1872
|
+
config !== null &&
|
|
1873
|
+
"type" in config &&
|
|
1874
|
+
config.type === "group");
|
|
1875
|
+
}
|
|
1876
|
+
// 递归创建嵌套 FormGroup
|
|
1877
|
+
createNestedFormGroup(fields, disabled) {
|
|
1878
|
+
const groupConfig = {};
|
|
1879
|
+
Object.entries(fields).forEach(([key, fieldConfig]) => {
|
|
1880
|
+
var _a, _b, _c, _d, _e;
|
|
1881
|
+
if (this.isFormGroupConfig(fieldConfig)) {
|
|
1882
|
+
// 递归创建嵌套的 FormGroup
|
|
1883
|
+
groupConfig[key] = this.createNestedFormGroup(fieldConfig.fields, (_a = fieldConfig.disabled) !== null && _a !== void 0 ? _a : disabled);
|
|
1884
|
+
}
|
|
1885
|
+
else {
|
|
1886
|
+
// 创建普通 FormControl
|
|
1887
|
+
groupConfig[key] = [
|
|
1888
|
+
{
|
|
1889
|
+
value: fieldConfig.value,
|
|
1890
|
+
disabled: (_c = (_b = fieldConfig.disabled) !== null && _b !== void 0 ? _b : disabled) !== null && _c !== void 0 ? _c : false,
|
|
1891
|
+
},
|
|
1892
|
+
(_e = (_d = fieldConfig.validators) === null || _d === void 0 ? void 0 : _d.call(fieldConfig)) !== null && _e !== void 0 ? _e : [],
|
|
1893
|
+
];
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
return this.fb.group(groupConfig);
|
|
1897
|
+
}
|
|
1735
1898
|
// 初始化表单
|
|
1736
1899
|
createFormGroup(name, config, options) {
|
|
1737
1900
|
const groupConfig = {};
|
|
1738
1901
|
this.errorMessageStore[name] = {};
|
|
1739
1902
|
Object.entries(config).forEach(([key, fieldConfig]) => {
|
|
1740
1903
|
var _a, _b, _c;
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1904
|
+
if (this.isFormGroupConfig(fieldConfig)) {
|
|
1905
|
+
// 处理嵌套 FormGroup
|
|
1906
|
+
const nestedGroup = this.createNestedFormGroup(fieldConfig.fields, fieldConfig.disabled);
|
|
1907
|
+
groupConfig[key] = nestedGroup;
|
|
1908
|
+
// 存储嵌套 FormGroup 的错误消息(如果需要)
|
|
1909
|
+
if (fieldConfig.errorMessages) {
|
|
1910
|
+
this.errorMessageStore[name][key] = fieldConfig.errorMessages;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
else {
|
|
1914
|
+
// 处理普通字段
|
|
1915
|
+
groupConfig[key] = [
|
|
1916
|
+
{
|
|
1917
|
+
value: fieldConfig.value,
|
|
1918
|
+
disabled: (_a = fieldConfig.disabled) !== null && _a !== void 0 ? _a : false,
|
|
1919
|
+
},
|
|
1920
|
+
(_c = (_b = fieldConfig.validators) === null || _b === void 0 ? void 0 : _b.call(fieldConfig)) !== null && _c !== void 0 ? _c : [],
|
|
1921
|
+
];
|
|
1922
|
+
if (fieldConfig.errorMessages) {
|
|
1923
|
+
this.errorMessageStore[name][key] = fieldConfig.errorMessages;
|
|
1924
|
+
}
|
|
1747
1925
|
}
|
|
1748
1926
|
});
|
|
1749
1927
|
if (options === null || options === void 0 ? void 0 : options.labelWidth) {
|
|
@@ -1753,6 +1931,7 @@ class AntdFormService {
|
|
|
1753
1931
|
this.labelAlign = options.labelAlign;
|
|
1754
1932
|
}
|
|
1755
1933
|
this.formStore[name] = this.fb.group(groupConfig);
|
|
1934
|
+
this.formRegisterStore[name] = true;
|
|
1756
1935
|
this.setCSSVariablesToTarget(name);
|
|
1757
1936
|
return this.formStore[name];
|
|
1758
1937
|
}
|
|
@@ -1762,6 +1941,46 @@ class AntdFormService {
|
|
|
1762
1941
|
var _a;
|
|
1763
1942
|
(_a = this.formStore[name]) === null || _a === void 0 ? void 0 : _a.reset(value);
|
|
1764
1943
|
}
|
|
1944
|
+
// 检测表单是否完成注册
|
|
1945
|
+
isFormRegistered(name) {
|
|
1946
|
+
var _a;
|
|
1947
|
+
return (_a = this.formRegisterStore[name]) !== null && _a !== void 0 ? _a : false;
|
|
1948
|
+
}
|
|
1949
|
+
// 销毁对应的表单
|
|
1950
|
+
destory(names) {
|
|
1951
|
+
names.forEach((name) => {
|
|
1952
|
+
// 2. 清理错误消息存储
|
|
1953
|
+
if (this.errorMessageStore[name]) {
|
|
1954
|
+
delete this.errorMessageStore[name];
|
|
1955
|
+
}
|
|
1956
|
+
// 3. 清理表单注册标记
|
|
1957
|
+
if (this.formRegisterStore[name]) {
|
|
1958
|
+
delete this.formRegisterStore[name];
|
|
1959
|
+
}
|
|
1960
|
+
// 4. 清理表单组(Angular 会自动处理 FormGroup 的清理)
|
|
1961
|
+
if (this.formStore[name]) {
|
|
1962
|
+
delete this.formStore[name];
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
// 根据路径获取嵌套的 FormGroup
|
|
1967
|
+
getNestedFormGroup(formGroup, path) {
|
|
1968
|
+
if (!path || path.trim() === "") {
|
|
1969
|
+
return formGroup;
|
|
1970
|
+
}
|
|
1971
|
+
const pathParts = path.split(".").filter((p) => p.trim() !== "");
|
|
1972
|
+
let currentGroup = formGroup;
|
|
1973
|
+
for (const part of pathParts) {
|
|
1974
|
+
if (!currentGroup || !(currentGroup instanceof FormGroup)) {
|
|
1975
|
+
return null;
|
|
1976
|
+
}
|
|
1977
|
+
currentGroup = currentGroup.get(part);
|
|
1978
|
+
if (!currentGroup || !(currentGroup instanceof FormGroup)) {
|
|
1979
|
+
return null;
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
return currentGroup instanceof FormGroup ? currentGroup : null;
|
|
1983
|
+
}
|
|
1765
1984
|
// 批量添加字段配置
|
|
1766
1985
|
addFieldsConfig(formName, fieldsConfig, options) {
|
|
1767
1986
|
var _a;
|
|
@@ -1771,8 +1990,8 @@ class AntdFormService {
|
|
|
1771
1990
|
failed: [],
|
|
1772
1991
|
};
|
|
1773
1992
|
// 1. 验证表单是否存在
|
|
1774
|
-
const
|
|
1775
|
-
if (!
|
|
1993
|
+
const rootFormGroup = this.formStore[formName];
|
|
1994
|
+
if (!rootFormGroup) {
|
|
1776
1995
|
// 如果表单不存在,所有字段都失败
|
|
1777
1996
|
Object.keys(fieldsConfig).forEach((fieldName) => {
|
|
1778
1997
|
var _a;
|
|
@@ -1786,20 +2005,41 @@ class AntdFormService {
|
|
|
1786
2005
|
result.success = false;
|
|
1787
2006
|
return result;
|
|
1788
2007
|
}
|
|
1789
|
-
// 2.
|
|
2008
|
+
// 2. 获取目标 FormGroup(支持嵌套路径)
|
|
2009
|
+
const targetPath = options === null || options === void 0 ? void 0 : options.targetPath;
|
|
2010
|
+
const targetFormGroup = targetPath
|
|
2011
|
+
? this.getNestedFormGroup(rootFormGroup, targetPath)
|
|
2012
|
+
: rootFormGroup;
|
|
2013
|
+
if (!targetFormGroup) {
|
|
2014
|
+
// 如果目标 FormGroup 不存在,所有字段都失败
|
|
2015
|
+
Object.keys(fieldsConfig).forEach((fieldName) => {
|
|
2016
|
+
var _a;
|
|
2017
|
+
const error = targetPath
|
|
2018
|
+
? `Target FormGroup at path "${targetPath}" not found`
|
|
2019
|
+
: `FormGroup not found`;
|
|
2020
|
+
result.failed.push({
|
|
2021
|
+
fieldName,
|
|
2022
|
+
error,
|
|
2023
|
+
});
|
|
2024
|
+
(_a = options === null || options === void 0 ? void 0 : options.onFieldAdded) === null || _a === void 0 ? void 0 : _a.call(options, fieldName, false, error);
|
|
2025
|
+
});
|
|
2026
|
+
result.success = false;
|
|
2027
|
+
return result;
|
|
2028
|
+
}
|
|
2029
|
+
// 3. 初始化 errorMessageStore(如果不存在)
|
|
1790
2030
|
if (!this.errorMessageStore[formName]) {
|
|
1791
2031
|
this.errorMessageStore[formName] = {};
|
|
1792
2032
|
}
|
|
1793
|
-
//
|
|
2033
|
+
// 4. 批量构建控件配置
|
|
1794
2034
|
const controlsToAdd = {};
|
|
1795
2035
|
const errorMessagesToAdd = {};
|
|
1796
|
-
//
|
|
2036
|
+
// 5. 遍历所有字段配置,进行验证和构建
|
|
1797
2037
|
Object.entries(fieldsConfig).forEach(([fieldName, fieldConfig]) => {
|
|
1798
2038
|
var _a, _b, _c, _d, _e;
|
|
1799
2039
|
try {
|
|
1800
|
-
//
|
|
1801
|
-
if (
|
|
1802
|
-
const error = `Field "${fieldName}" already exists`;
|
|
2040
|
+
// 5.1 检查字段是否已存在
|
|
2041
|
+
if (targetFormGroup.get(fieldName)) {
|
|
2042
|
+
const error = `Field "${fieldName}" already exists${targetPath ? ` in "${targetPath}"` : ""}`;
|
|
1803
2043
|
result.failed.push({
|
|
1804
2044
|
fieldName,
|
|
1805
2045
|
error,
|
|
@@ -1807,20 +2047,38 @@ class AntdFormService {
|
|
|
1807
2047
|
(_a = options === null || options === void 0 ? void 0 : options.onFieldAdded) === null || _a === void 0 ? void 0 : _a.call(options, fieldName, false, error);
|
|
1808
2048
|
return;
|
|
1809
2049
|
}
|
|
1810
|
-
//
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
2050
|
+
// 5.2 创建控件
|
|
2051
|
+
let control;
|
|
2052
|
+
if (this.isFormGroupConfig(fieldConfig)) {
|
|
2053
|
+
// 创建嵌套 FormGroup
|
|
2054
|
+
control = this.createNestedFormGroup(fieldConfig.fields, fieldConfig.disabled);
|
|
2055
|
+
// 存储嵌套 FormGroup 的错误消息(如果需要)
|
|
2056
|
+
if (fieldConfig.errorMessages) {
|
|
2057
|
+
const errorMessageKey = targetPath
|
|
2058
|
+
? `${targetPath}.${fieldName}`
|
|
2059
|
+
: fieldName;
|
|
2060
|
+
errorMessagesToAdd[errorMessageKey] = fieldConfig.errorMessages;
|
|
2061
|
+
}
|
|
1818
2062
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
2063
|
+
else {
|
|
2064
|
+
// 创建普通 FormControl
|
|
2065
|
+
const controlOptions = {
|
|
2066
|
+
validators: (_c = (_b = fieldConfig.validators) === null || _b === void 0 ? void 0 : _b.call(fieldConfig)) !== null && _c !== void 0 ? _c : [],
|
|
2067
|
+
};
|
|
2068
|
+
control = this.fb.control(fieldConfig.value, controlOptions);
|
|
2069
|
+
// 设置 disabled 状态
|
|
2070
|
+
if (fieldConfig.disabled) {
|
|
2071
|
+
control.disable();
|
|
2072
|
+
}
|
|
2073
|
+
// 存储错误消息
|
|
2074
|
+
if (fieldConfig.errorMessages) {
|
|
2075
|
+
const errorMessageKey = targetPath
|
|
2076
|
+
? `${targetPath}.${fieldName}`
|
|
2077
|
+
: fieldName;
|
|
2078
|
+
errorMessagesToAdd[errorMessageKey] = fieldConfig.errorMessages;
|
|
2079
|
+
}
|
|
1823
2080
|
}
|
|
2081
|
+
controlsToAdd[fieldName] = control;
|
|
1824
2082
|
result.added.push(fieldName);
|
|
1825
2083
|
(_d = options === null || options === void 0 ? void 0 : options.onFieldAdded) === null || _d === void 0 ? void 0 : _d.call(options, fieldName, true);
|
|
1826
2084
|
}
|
|
@@ -1833,18 +2091,18 @@ class AntdFormService {
|
|
|
1833
2091
|
(_e = options === null || options === void 0 ? void 0 : options.onFieldAdded) === null || _e === void 0 ? void 0 : _e.call(options, fieldName, false, errorMessage);
|
|
1834
2092
|
}
|
|
1835
2093
|
});
|
|
1836
|
-
//
|
|
2094
|
+
// 6. 批量添加到目标 FormGroup
|
|
1837
2095
|
if (Object.keys(controlsToAdd).length > 0) {
|
|
1838
2096
|
Object.entries(controlsToAdd).forEach(([fieldName, control]) => {
|
|
1839
|
-
|
|
2097
|
+
targetFormGroup.addControl(fieldName, control);
|
|
1840
2098
|
});
|
|
1841
|
-
//
|
|
2099
|
+
// 7. 批量存储错误消息
|
|
1842
2100
|
Object.entries(errorMessagesToAdd).forEach(([key, messages]) => {
|
|
1843
2101
|
this.errorMessageStore[formName][key] = messages;
|
|
1844
2102
|
});
|
|
1845
|
-
//
|
|
2103
|
+
// 8. 更新表单验证状态
|
|
1846
2104
|
if (options === null || options === void 0 ? void 0 : options.updateValueAndValidity) {
|
|
1847
|
-
|
|
2105
|
+
targetFormGroup.updateValueAndValidity({
|
|
1848
2106
|
emitEvent: (_a = options === null || options === void 0 ? void 0 : options.emitEvent) !== null && _a !== void 0 ? _a : true,
|
|
1849
2107
|
});
|
|
1850
2108
|
}
|
|
@@ -2040,10 +2298,17 @@ class AntdFormService {
|
|
|
2040
2298
|
let appliedCount = 0;
|
|
2041
2299
|
dom.forEach((item) => {
|
|
2042
2300
|
const target = item;
|
|
2043
|
-
if (target.
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2301
|
+
if (target.closest(".pro-table-container")) {
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
const customWidth = target.getAttribute("custom-width");
|
|
2305
|
+
const customAlign = target.getAttribute("custom-align");
|
|
2306
|
+
const finalWidth = customWidth || this.labelWidth;
|
|
2307
|
+
const finalTextAlign = customAlign || this.labelAlign;
|
|
2308
|
+
if (target.style.width !== finalWidth ||
|
|
2309
|
+
target.style.textAlign !== finalTextAlign) {
|
|
2310
|
+
target.style.width = finalWidth;
|
|
2311
|
+
target.style.textAlign = finalTextAlign;
|
|
2047
2312
|
appliedCount++;
|
|
2048
2313
|
}
|
|
2049
2314
|
});
|
|
@@ -2113,59 +2378,75 @@ AntdFormService.ctorParameters = () => [
|
|
|
2113
2378
|
{ type: FormBuilder }
|
|
2114
2379
|
];
|
|
2115
2380
|
|
|
2116
|
-
/**
|
|
2117
|
-
* 数组型数据收集基础服务
|
|
2118
|
-
*
|
|
2119
|
-
* 功能:
|
|
2120
|
-
* 1. 支持通过 ngModel 绑定对应行的数据源
|
|
2121
|
-
* 2. 自动为数组数据添加 isEdit 和 uid 字段
|
|
2122
|
-
* 3. 支持每个字段的自定义校验方法,返回 'success' | 'warning' | 'error'
|
|
2123
|
-
* 4. 提供公共方法支持删除、新增、编辑等操作
|
|
2124
|
-
*/
|
|
2381
|
+
/** 数组型数据收集基础服务 */
|
|
2125
2382
|
class ArrayFormService {
|
|
2126
2383
|
constructor() {
|
|
2127
2384
|
this.formStore = {};
|
|
2128
2385
|
}
|
|
2129
|
-
/**
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2386
|
+
/** 深度克隆值 */
|
|
2387
|
+
cloneValue(value) {
|
|
2388
|
+
if (value === null || value === undefined) {
|
|
2389
|
+
return value;
|
|
2390
|
+
}
|
|
2391
|
+
if (Array.isArray(value)) {
|
|
2392
|
+
return value.map((item) => this.cloneValue(item));
|
|
2393
|
+
}
|
|
2394
|
+
if (typeof value === "object") {
|
|
2395
|
+
const cloned = {};
|
|
2396
|
+
for (const key of Object.keys(value)) {
|
|
2397
|
+
cloned[key] = this.cloneValue(value[key]);
|
|
2398
|
+
}
|
|
2399
|
+
return cloned;
|
|
2400
|
+
}
|
|
2401
|
+
return value;
|
|
2402
|
+
}
|
|
2403
|
+
/** 比较两个值是否相等 */
|
|
2404
|
+
isEqual(a, b) {
|
|
2405
|
+
if (a === b)
|
|
2406
|
+
return true;
|
|
2407
|
+
if (a === null || b === null)
|
|
2408
|
+
return a === b;
|
|
2409
|
+
if (a === undefined || b === undefined)
|
|
2410
|
+
return a === b;
|
|
2411
|
+
if (typeof a !== typeof b)
|
|
2412
|
+
return false;
|
|
2413
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2414
|
+
if (a.length !== b.length)
|
|
2415
|
+
return false;
|
|
2416
|
+
return a.every((item, index) => this.isEqual(item, b[index]));
|
|
2417
|
+
}
|
|
2418
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
2419
|
+
const keysA = Object.keys(a);
|
|
2420
|
+
const keysB = Object.keys(b);
|
|
2421
|
+
if (keysA.length !== keysB.length)
|
|
2422
|
+
return false;
|
|
2423
|
+
return keysA.every((key) => this.isEqual(a[key], b[key]));
|
|
2424
|
+
}
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2427
|
+
/** 创建行的初始值快照 */
|
|
2428
|
+
createRowSnapshot(row, fields) {
|
|
2429
|
+
const snapshot = {};
|
|
2430
|
+
fields.forEach((field) => {
|
|
2431
|
+
snapshot[field.name] = this.cloneValue(row[field.name]);
|
|
2432
|
+
});
|
|
2433
|
+
return snapshot;
|
|
2434
|
+
}
|
|
2435
|
+
/** 初始化数组数据,添加 uid 和 isEdit 字段 */
|
|
2137
2436
|
initializeData(data) {
|
|
2138
2437
|
return data.map((item) => this.enrichRow(item));
|
|
2139
2438
|
}
|
|
2140
|
-
/**
|
|
2141
|
-
* 为单行数据添加 uid 和 isEdit 字段
|
|
2142
|
-
*
|
|
2143
|
-
* @param row 原始行数据
|
|
2144
|
-
* @returns 增强后的行数据
|
|
2145
|
-
*/
|
|
2439
|
+
/** 为单行数据添加 uid 和 isEdit 字段 */
|
|
2146
2440
|
enrichRow(row) {
|
|
2147
|
-
return Object.assign(Object.assign({}, row), { uid: row.uid || v4(), isEdit: row.isEdit !== undefined ? row.isEdit : false });
|
|
2441
|
+
return Object.assign(Object.assign({}, row), { uid: row.uid || v4(), isEdit: row.isEdit !== undefined ? row.isEdit : false, disabled: row.disabled !== undefined ? row.disabled : false });
|
|
2148
2442
|
}
|
|
2149
|
-
/**
|
|
2150
|
-
* 新增一行数据
|
|
2151
|
-
*
|
|
2152
|
-
* @param data 数据数组引用
|
|
2153
|
-
* @param defaultValues 默认值
|
|
2154
|
-
* @returns 新增的行数据
|
|
2155
|
-
*/
|
|
2443
|
+
/** 新增一行数据 */
|
|
2156
2444
|
addRow(data, defaultValues) {
|
|
2157
|
-
const newRow = Object.assign(Object.assign({}, defaultValues), { uid: v4(), isEdit: true, isAdd: true });
|
|
2445
|
+
const newRow = Object.assign(Object.assign({}, defaultValues), { uid: v4(), isEdit: true, isAdd: true, disabled: false });
|
|
2158
2446
|
data.push(newRow);
|
|
2159
2447
|
return newRow;
|
|
2160
2448
|
}
|
|
2161
|
-
/**
|
|
2162
|
-
* 校验单个字段
|
|
2163
|
-
*
|
|
2164
|
-
* @param row 行数据
|
|
2165
|
-
* @param fieldName 字段名
|
|
2166
|
-
* @param config 表单配置
|
|
2167
|
-
* @returns 校验结果
|
|
2168
|
-
*/
|
|
2449
|
+
/** 校验单个字段 */
|
|
2169
2450
|
validateField(row, fieldName, config) {
|
|
2170
2451
|
const fieldConfig = config.fields.find((f) => f.name === fieldName);
|
|
2171
2452
|
if (!fieldConfig) {
|
|
@@ -2176,13 +2457,7 @@ class ArrayFormService {
|
|
|
2176
2457
|
}
|
|
2177
2458
|
return "";
|
|
2178
2459
|
}
|
|
2179
|
-
/**
|
|
2180
|
-
* 校验整行数据
|
|
2181
|
-
*
|
|
2182
|
-
* @param row 行数据
|
|
2183
|
-
* @param config 表单配置
|
|
2184
|
-
* @returns 校验结果对象,key为字段名,value为校验结果
|
|
2185
|
-
*/
|
|
2460
|
+
/** 校验整行数据 */
|
|
2186
2461
|
validateRow(row, config) {
|
|
2187
2462
|
const results = {};
|
|
2188
2463
|
config.fields.forEach((fieldConfig) => {
|
|
@@ -2190,13 +2465,7 @@ class ArrayFormService {
|
|
|
2190
2465
|
});
|
|
2191
2466
|
return results;
|
|
2192
2467
|
}
|
|
2193
|
-
/**
|
|
2194
|
-
* 校验整个数组
|
|
2195
|
-
*
|
|
2196
|
-
* @param data 数据数组
|
|
2197
|
-
* @param config 表单配置
|
|
2198
|
-
* @returns 校验结果对象,key为行的uid,value为该行的校验结果
|
|
2199
|
-
*/
|
|
2468
|
+
/** 校验整个数组 */
|
|
2200
2469
|
validateData(data, config) {
|
|
2201
2470
|
const results = {};
|
|
2202
2471
|
data.forEach((row) => {
|
|
@@ -2204,90 +2473,126 @@ class ArrayFormService {
|
|
|
2204
2473
|
});
|
|
2205
2474
|
return results;
|
|
2206
2475
|
}
|
|
2207
|
-
/**
|
|
2208
|
-
* 注册表单到存储
|
|
2209
|
-
* 如果表单已存在,则更新其配置
|
|
2210
|
-
*
|
|
2211
|
-
* @param formName 表单名称
|
|
2212
|
-
* @param data 数据数组
|
|
2213
|
-
* @param config 表单配置
|
|
2214
|
-
*/
|
|
2476
|
+
/** 注册表单到存储 */
|
|
2215
2477
|
registerForm(formName, data, config) {
|
|
2478
|
+
const initializedData = this.initializeData(data);
|
|
2479
|
+
// 记录初始值快照
|
|
2480
|
+
const initialSnapshot = {};
|
|
2481
|
+
initializedData.forEach((row) => {
|
|
2482
|
+
initialSnapshot[row.uid] = this.createRowSnapshot(row, config.fields);
|
|
2483
|
+
});
|
|
2216
2484
|
this.formStore[formName] = {
|
|
2217
|
-
data:
|
|
2485
|
+
data: initializedData,
|
|
2218
2486
|
config,
|
|
2219
2487
|
validationResults: {},
|
|
2488
|
+
initialSnapshot,
|
|
2489
|
+
editingSnapshot: {},
|
|
2490
|
+
allTouched: false,
|
|
2491
|
+
rowTouched: {},
|
|
2220
2492
|
};
|
|
2221
2493
|
// 如果配置了自动更新,立即更新一次
|
|
2222
2494
|
this.autoUpdateArrayReference(formName);
|
|
2223
2495
|
}
|
|
2224
|
-
/**
|
|
2225
|
-
* 从存储中获取表单
|
|
2226
|
-
*
|
|
2227
|
-
* @param formName 表单名称
|
|
2228
|
-
* @returns 表单存储项或undefined
|
|
2229
|
-
*/
|
|
2496
|
+
/** 从存储中获取表单 */
|
|
2230
2497
|
getForm(formName) {
|
|
2231
2498
|
return this.formStore[formName];
|
|
2232
2499
|
}
|
|
2233
|
-
/**
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2500
|
+
/** 从存储中获取表单数据 */
|
|
2501
|
+
getFormData(formName) {
|
|
2502
|
+
const form = this.formStore[formName];
|
|
2503
|
+
if (!form) {
|
|
2504
|
+
return undefined;
|
|
2505
|
+
}
|
|
2506
|
+
return form.data.map((item) => {
|
|
2507
|
+
delete item.isEdit;
|
|
2508
|
+
delete item.isAdd;
|
|
2509
|
+
delete item.uid;
|
|
2510
|
+
return item;
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
/** 向表单添加行 */
|
|
2240
2514
|
addRowToForm(formName, defaultValues) {
|
|
2241
2515
|
const form = this.formStore[formName];
|
|
2242
2516
|
if (!form) {
|
|
2243
2517
|
return undefined;
|
|
2244
2518
|
}
|
|
2245
2519
|
const newRow = this.addRow(form.data, defaultValues);
|
|
2520
|
+
// 为新行记录初始值快照
|
|
2521
|
+
form.initialSnapshot[newRow.uid] = this.createRowSnapshot(newRow, form.config.fields);
|
|
2246
2522
|
// 自动更新外部数组引用
|
|
2247
2523
|
this.autoUpdateArrayReference(formName);
|
|
2248
2524
|
return newRow;
|
|
2249
2525
|
}
|
|
2250
|
-
/**
|
|
2251
|
-
* 校验表单
|
|
2252
|
-
*
|
|
2253
|
-
* @param formName 表单名称
|
|
2254
|
-
* @returns 校验结果或undefined
|
|
2255
|
-
*/
|
|
2526
|
+
/** 校验表单,自动标记所有字段为已触碰 */
|
|
2256
2527
|
validateForm(formName) {
|
|
2257
2528
|
const form = this.formStore[formName];
|
|
2258
2529
|
if (!form) {
|
|
2259
|
-
return
|
|
2530
|
+
return true;
|
|
2260
2531
|
}
|
|
2532
|
+
// 标记所有字段为已触碰
|
|
2533
|
+
form.allTouched = true;
|
|
2261
2534
|
const results = this.validateData(form.data, form.config);
|
|
2262
2535
|
form.validationResults = results;
|
|
2263
|
-
|
|
2536
|
+
// 检查是否有任何错误
|
|
2537
|
+
for (const uid of Object.keys(results)) {
|
|
2538
|
+
for (const fieldName of Object.keys(results[uid])) {
|
|
2539
|
+
if (results[uid][fieldName]) {
|
|
2540
|
+
return false;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
return true;
|
|
2264
2545
|
}
|
|
2265
|
-
/**
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2546
|
+
/** 开启编辑模式,保存快照用于取消恢复 */
|
|
2547
|
+
enableEdit(formName, row) {
|
|
2548
|
+
const form = this.formStore[formName];
|
|
2549
|
+
if (form && row.uid) {
|
|
2550
|
+
// 保存编辑前的快照
|
|
2551
|
+
form.editingSnapshot[row.uid] = this.createRowSnapshot(row, form.config.fields);
|
|
2552
|
+
}
|
|
2271
2553
|
row.isEdit = true;
|
|
2272
2554
|
}
|
|
2273
|
-
/**
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2555
|
+
/** 取消编辑,恢复到编辑前的数据 */
|
|
2556
|
+
disableEdit(formName, row) {
|
|
2557
|
+
const form = this.formStore[formName];
|
|
2558
|
+
if (form && row.uid && form.editingSnapshot[row.uid]) {
|
|
2559
|
+
// 恢复编辑前的数据
|
|
2560
|
+
const snapshot = form.editingSnapshot[row.uid];
|
|
2561
|
+
form.config.fields.forEach((field) => {
|
|
2562
|
+
row[field.name] = this.cloneValue(snapshot[field.name]);
|
|
2563
|
+
});
|
|
2564
|
+
// 更新初始快照为恢复后的值,消除 touched 状态
|
|
2565
|
+
form.initialSnapshot[row.uid] = this.cloneValue(snapshot);
|
|
2566
|
+
// 清理编辑快照和 touched 状态
|
|
2567
|
+
delete form.editingSnapshot[row.uid];
|
|
2568
|
+
delete form.rowTouched[row.uid];
|
|
2569
|
+
// 清理该行的校验结果
|
|
2570
|
+
if (form.validationResults) {
|
|
2571
|
+
delete form.validationResults[row.uid];
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2279
2574
|
row.isEdit = false;
|
|
2280
2575
|
}
|
|
2281
|
-
/**
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2576
|
+
/** 确认编辑,保留修改后的数据 */
|
|
2577
|
+
confirmEdit(formName, row) {
|
|
2578
|
+
const form = this.formStore[formName];
|
|
2579
|
+
if (form && row.uid) {
|
|
2580
|
+
// 清理编辑快照(保留当前数据)
|
|
2581
|
+
if (form.editingSnapshot[row.uid]) {
|
|
2582
|
+
delete form.editingSnapshot[row.uid];
|
|
2583
|
+
}
|
|
2584
|
+
// 更新初始快照为当前值(用于后续 touched 检测)
|
|
2585
|
+
form.initialSnapshot[row.uid] = this.createRowSnapshot(row, form.config.fields);
|
|
2586
|
+
// 清除 touched 状态,基于新的 initialSnapshot 重新判断
|
|
2587
|
+
delete form.rowTouched[row.uid];
|
|
2588
|
+
}
|
|
2589
|
+
row.isEdit = false;
|
|
2590
|
+
row.isAdd = false;
|
|
2591
|
+
}
|
|
2592
|
+
/** 从表单中删除指定行 */
|
|
2288
2593
|
deleteRowFromForm(formName, row) {
|
|
2289
2594
|
const form = this.formStore[formName];
|
|
2290
|
-
if (!form) {
|
|
2595
|
+
if (!form || !row.uid) {
|
|
2291
2596
|
return false;
|
|
2292
2597
|
}
|
|
2293
2598
|
const index = form.data.findIndex((item) => item.uid === row.uid);
|
|
@@ -2295,31 +2600,44 @@ class ArrayFormService {
|
|
|
2295
2600
|
return false;
|
|
2296
2601
|
}
|
|
2297
2602
|
form.data.splice(index, 1);
|
|
2298
|
-
|
|
2603
|
+
// 清理该行的所有快照、touched 状态和校验结果
|
|
2604
|
+
delete form.initialSnapshot[row.uid];
|
|
2605
|
+
delete form.editingSnapshot[row.uid];
|
|
2606
|
+
delete form.rowTouched[row.uid];
|
|
2607
|
+
if (form.validationResults) {
|
|
2299
2608
|
delete form.validationResults[row.uid];
|
|
2300
2609
|
}
|
|
2301
2610
|
// 自动更新外部数组引用
|
|
2302
2611
|
this.autoUpdateArrayReference(formName);
|
|
2303
2612
|
return true;
|
|
2304
2613
|
}
|
|
2305
|
-
/**
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2614
|
+
/** 检测字段是否已被触碰 */
|
|
2615
|
+
isFieldTouched(form, row, fieldName) {
|
|
2616
|
+
var _a;
|
|
2617
|
+
// 整个表单已 touched(整个表单提交时)
|
|
2618
|
+
if (form.allTouched) {
|
|
2619
|
+
return true;
|
|
2620
|
+
}
|
|
2621
|
+
// 当前行已 touched(单行保存时)
|
|
2622
|
+
if (form.rowTouched[row.uid]) {
|
|
2623
|
+
return true;
|
|
2624
|
+
}
|
|
2625
|
+
// 检测当前值与初始值是否不同
|
|
2626
|
+
const initialValue = (_a = form.initialSnapshot[row.uid]) === null || _a === void 0 ? void 0 : _a[fieldName];
|
|
2627
|
+
const currentValue = row[fieldName];
|
|
2628
|
+
return !this.isEqual(initialValue, currentValue);
|
|
2629
|
+
}
|
|
2630
|
+
/** 校验指定行的指定字段,未修改时不显示校验状态 */
|
|
2314
2631
|
validateFieldInRow(formName, row, fieldName) {
|
|
2315
2632
|
const form = this.formStore[formName];
|
|
2316
2633
|
if (!form) {
|
|
2317
|
-
return "
|
|
2634
|
+
return "";
|
|
2318
2635
|
}
|
|
2319
2636
|
const fieldConfig = form.config.fields.find((f) => f.name === fieldName);
|
|
2320
2637
|
if (!fieldConfig) {
|
|
2321
|
-
return "
|
|
2638
|
+
return "";
|
|
2322
2639
|
}
|
|
2640
|
+
// 执行校验
|
|
2323
2641
|
let result = "";
|
|
2324
2642
|
if (fieldConfig.validator) {
|
|
2325
2643
|
result = fieldConfig.validator(row[fieldName], row, fieldName);
|
|
@@ -2332,20 +2650,35 @@ class ArrayFormService {
|
|
|
2332
2650
|
form.validationResults[row.uid] = {};
|
|
2333
2651
|
}
|
|
2334
2652
|
form.validationResults[row.uid][fieldName] = result;
|
|
2653
|
+
// 如果字段未被触碰,不显示校验状态
|
|
2654
|
+
if (!this.isFieldTouched(form, row, fieldName)) {
|
|
2655
|
+
return "";
|
|
2656
|
+
}
|
|
2335
2657
|
return result ? "error" : "success";
|
|
2336
2658
|
}
|
|
2337
|
-
/**
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2659
|
+
/** 获取指定行指定字段的校验错误信息 */
|
|
2660
|
+
getFieldErrorMessage(formName, row, fieldName) {
|
|
2661
|
+
var _a, _b;
|
|
2662
|
+
const form = this.formStore[formName];
|
|
2663
|
+
if (!form || !row.uid) {
|
|
2664
|
+
return "";
|
|
2665
|
+
}
|
|
2666
|
+
// 如果字段未被触碰,不显示错误信息
|
|
2667
|
+
if (!this.isFieldTouched(form, row, fieldName)) {
|
|
2668
|
+
return "";
|
|
2669
|
+
}
|
|
2670
|
+
return ((_b = (_a = form.validationResults) === null || _a === void 0 ? void 0 : _a[row.uid]) === null || _b === void 0 ? void 0 : _b[fieldName]) || "";
|
|
2671
|
+
}
|
|
2672
|
+
/** 校验指定行的所有字段 */
|
|
2344
2673
|
validateRowAllFields(formName, row) {
|
|
2345
2674
|
const form = this.formStore[formName];
|
|
2346
|
-
if (!form) {
|
|
2675
|
+
if (!form || !row.uid) {
|
|
2347
2676
|
return true;
|
|
2348
2677
|
}
|
|
2678
|
+
// 更新初始快照为当前值
|
|
2679
|
+
form.initialSnapshot[row.uid] = this.createRowSnapshot(row, form.config.fields);
|
|
2680
|
+
// 标记当前行为 touched(只影响当前行,不影响其他行)
|
|
2681
|
+
form.rowTouched[row.uid] = true;
|
|
2349
2682
|
let hasError = false;
|
|
2350
2683
|
form.config.fields.forEach((fieldConfig) => {
|
|
2351
2684
|
const result = this.validateFieldInRow(formName, row, fieldConfig.name);
|
|
@@ -2355,12 +2688,7 @@ class ArrayFormService {
|
|
|
2355
2688
|
});
|
|
2356
2689
|
return !hasError;
|
|
2357
2690
|
}
|
|
2358
|
-
/**
|
|
2359
|
-
* 自动更新外部数组引用(如果配置了)
|
|
2360
|
-
* 私有方法,在数据变化时自动调用
|
|
2361
|
-
*
|
|
2362
|
-
* @param formName 表单名称
|
|
2363
|
-
*/
|
|
2691
|
+
/** 自动更新外部数组引用 */
|
|
2364
2692
|
autoUpdateArrayReference(formName) {
|
|
2365
2693
|
const form = this.formStore[formName];
|
|
2366
2694
|
if (!form || !form.config.targetObject || !form.config.arrayPropertyName) {
|
|
@@ -2370,6 +2698,42 @@ class ArrayFormService {
|
|
|
2370
2698
|
// 更新目标对象的数组属性为新数组引用
|
|
2371
2699
|
form.config.targetObject[form.config.arrayPropertyName] = newArray;
|
|
2372
2700
|
}
|
|
2701
|
+
/** 是否有正在编辑的行 */
|
|
2702
|
+
hasEditingRow(formName) {
|
|
2703
|
+
const form = this.formStore[formName];
|
|
2704
|
+
if (!form) {
|
|
2705
|
+
return false;
|
|
2706
|
+
}
|
|
2707
|
+
return form.data.some((item) => item.isEdit);
|
|
2708
|
+
}
|
|
2709
|
+
// 销毁对应的表单
|
|
2710
|
+
destory(names) {
|
|
2711
|
+
names.forEach((name) => {
|
|
2712
|
+
if (this.formStore[name]) {
|
|
2713
|
+
// 清理表单数据
|
|
2714
|
+
delete this.formStore[name];
|
|
2715
|
+
}
|
|
2716
|
+
});
|
|
2717
|
+
}
|
|
2718
|
+
// 重置表单数组
|
|
2719
|
+
resetFormArray(name) {
|
|
2720
|
+
const form = this.formStore[name];
|
|
2721
|
+
if (!form) {
|
|
2722
|
+
return;
|
|
2723
|
+
}
|
|
2724
|
+
// 1. 清空数据数组
|
|
2725
|
+
form.data = [];
|
|
2726
|
+
// 2. 清理所有快照
|
|
2727
|
+
form.initialSnapshot = {};
|
|
2728
|
+
form.editingSnapshot = {};
|
|
2729
|
+
// 3. 清理校验结果
|
|
2730
|
+
form.validationResults = {};
|
|
2731
|
+
// 4. 重置 touched 状态
|
|
2732
|
+
form.allTouched = false;
|
|
2733
|
+
form.rowTouched = {};
|
|
2734
|
+
// 5. 如果配置了自动更新,更新外部数组引用
|
|
2735
|
+
this.autoUpdateArrayReference(name);
|
|
2736
|
+
}
|
|
2373
2737
|
}
|
|
2374
2738
|
ArrayFormService.ɵprov = ɵɵdefineInjectable({ factory: function ArrayFormService_Factory() { return new ArrayFormService(); }, token: ArrayFormService, providedIn: "root" });
|
|
2375
2739
|
ArrayFormService.decorators = [
|