@yibozhang/pro-table 0.0.4 → 0.0.5

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.
@@ -2742,60 +2742,90 @@
2742
2742
  { type: i1.FormBuilder }
2743
2743
  ]; };
2744
2744
 
2745
- /**
2746
- * 数组型数据收集基础服务
2747
- *
2748
- * 功能:
2749
- * 1. 支持通过 ngModel 绑定对应行的数据源
2750
- * 2. 自动为数组数据添加 isEdit 和 uid 字段
2751
- * 3. 支持每个字段的自定义校验方法,返回 'success' | 'warning' | 'error'
2752
- * 4. 提供公共方法支持删除、新增、编辑等操作
2753
- */
2745
+ /** 数组型数据收集基础服务 */
2754
2746
  var ArrayFormService = /** @class */ (function () {
2755
2747
  function ArrayFormService() {
2756
2748
  this.formStore = {};
2757
2749
  }
2758
- /**
2759
- * 初始化数组数据
2760
- * 为现有数据添加 uid 和 isEdit 字段
2761
- *
2762
- * @param data 原始数据数组
2763
- * @param config 表单配置
2764
- * @returns 初始化后的数据数组
2765
- */
2750
+ /** 深度克隆值 */
2751
+ ArrayFormService.prototype.cloneValue = function (value) {
2752
+ var e_1, _c;
2753
+ var _this = this;
2754
+ if (value === null || value === undefined) {
2755
+ return value;
2756
+ }
2757
+ if (Array.isArray(value)) {
2758
+ return value.map(function (item) { return _this.cloneValue(item); });
2759
+ }
2760
+ if (typeof value === "object") {
2761
+ var cloned = {};
2762
+ try {
2763
+ for (var _d = __values(Object.keys(value)), _e = _d.next(); !_e.done; _e = _d.next()) {
2764
+ var key = _e.value;
2765
+ cloned[key] = this.cloneValue(value[key]);
2766
+ }
2767
+ }
2768
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2769
+ finally {
2770
+ try {
2771
+ if (_e && !_e.done && (_c = _d.return)) _c.call(_d);
2772
+ }
2773
+ finally { if (e_1) throw e_1.error; }
2774
+ }
2775
+ return cloned;
2776
+ }
2777
+ return value;
2778
+ };
2779
+ /** 比较两个值是否相等 */
2780
+ ArrayFormService.prototype.isEqual = function (a, b) {
2781
+ var _this = this;
2782
+ if (a === b)
2783
+ return true;
2784
+ if (a === null || b === null)
2785
+ return a === b;
2786
+ if (a === undefined || b === undefined)
2787
+ return a === b;
2788
+ if (typeof a !== typeof b)
2789
+ return false;
2790
+ if (Array.isArray(a) && Array.isArray(b)) {
2791
+ if (a.length !== b.length)
2792
+ return false;
2793
+ return a.every(function (item, index) { return _this.isEqual(item, b[index]); });
2794
+ }
2795
+ if (typeof a === "object" && typeof b === "object") {
2796
+ var keysA = Object.keys(a);
2797
+ var keysB = Object.keys(b);
2798
+ if (keysA.length !== keysB.length)
2799
+ return false;
2800
+ return keysA.every(function (key) { return _this.isEqual(a[key], b[key]); });
2801
+ }
2802
+ return false;
2803
+ };
2804
+ /** 创建行的初始值快照 */
2805
+ ArrayFormService.prototype.createRowSnapshot = function (row, fields) {
2806
+ var _this = this;
2807
+ var snapshot = {};
2808
+ fields.forEach(function (field) {
2809
+ snapshot[field.name] = _this.cloneValue(row[field.name]);
2810
+ });
2811
+ return snapshot;
2812
+ };
2813
+ /** 初始化数组数据,添加 uid 和 isEdit 字段 */
2766
2814
  ArrayFormService.prototype.initializeData = function (data) {
2767
2815
  var _this = this;
2768
2816
  return data.map(function (item) { return _this.enrichRow(item); });
2769
2817
  };
2770
- /**
2771
- * 为单行数据添加 uid 和 isEdit 字段
2772
- *
2773
- * @param row 原始行数据
2774
- * @returns 增强后的行数据
2775
- */
2818
+ /** 为单行数据添加 uid 和 isEdit 字段 */
2776
2819
  ArrayFormService.prototype.enrichRow = function (row) {
2777
- return Object.assign(Object.assign({}, row), { uid: row.uid || uuid.v4(), isEdit: row.isEdit !== undefined ? row.isEdit : false });
2820
+ return Object.assign(Object.assign({}, row), { uid: row.uid || uuid.v4(), isEdit: row.isEdit !== undefined ? row.isEdit : false, disabled: row.disabled !== undefined ? row.disabled : false });
2778
2821
  };
2779
- /**
2780
- * 新增一行数据
2781
- *
2782
- * @param data 数据数组引用
2783
- * @param defaultValues 默认值
2784
- * @returns 新增的行数据
2785
- */
2822
+ /** 新增一行数据 */
2786
2823
  ArrayFormService.prototype.addRow = function (data, defaultValues) {
2787
- var newRow = Object.assign(Object.assign({}, defaultValues), { uid: uuid.v4(), isEdit: true, isAdd: true });
2824
+ var newRow = Object.assign(Object.assign({}, defaultValues), { uid: uuid.v4(), isEdit: true, isAdd: true, disabled: false });
2788
2825
  data.push(newRow);
2789
2826
  return newRow;
2790
2827
  };
2791
- /**
2792
- * 校验单个字段
2793
- *
2794
- * @param row 行数据
2795
- * @param fieldName 字段名
2796
- * @param config 表单配置
2797
- * @returns 校验结果
2798
- */
2828
+ /** 校验单个字段 */
2799
2829
  ArrayFormService.prototype.validateField = function (row, fieldName, config) {
2800
2830
  var fieldConfig = config.fields.find(function (f) { return f.name === fieldName; });
2801
2831
  if (!fieldConfig) {
@@ -2806,13 +2836,7 @@
2806
2836
  }
2807
2837
  return "";
2808
2838
  };
2809
- /**
2810
- * 校验整行数据
2811
- *
2812
- * @param row 行数据
2813
- * @param config 表单配置
2814
- * @returns 校验结果对象,key为字段名,value为校验结果
2815
- */
2839
+ /** 校验整行数据 */
2816
2840
  ArrayFormService.prototype.validateRow = function (row, config) {
2817
2841
  var _this = this;
2818
2842
  var results = {};
@@ -2821,13 +2845,7 @@
2821
2845
  });
2822
2846
  return results;
2823
2847
  };
2824
- /**
2825
- * 校验整个数组
2826
- *
2827
- * @param data 数据数组
2828
- * @param config 表单配置
2829
- * @returns 校验结果对象,key为行的uid,value为该行的校验结果
2830
- */
2848
+ /** 校验整个数组 */
2831
2849
  ArrayFormService.prototype.validateData = function (data, config) {
2832
2850
  var _this = this;
2833
2851
  var results = {};
@@ -2836,90 +2854,149 @@
2836
2854
  });
2837
2855
  return results;
2838
2856
  };
2839
- /**
2840
- * 注册表单到存储
2841
- * 如果表单已存在,则更新其配置
2842
- *
2843
- * @param formName 表单名称
2844
- * @param data 数据数组
2845
- * @param config 表单配置
2846
- */
2857
+ /** 注册表单到存储 */
2847
2858
  ArrayFormService.prototype.registerForm = function (formName, data, config) {
2859
+ var _this = this;
2860
+ var initializedData = this.initializeData(data);
2861
+ // 记录初始值快照
2862
+ var initialSnapshot = {};
2863
+ initializedData.forEach(function (row) {
2864
+ initialSnapshot[row.uid] = _this.createRowSnapshot(row, config.fields);
2865
+ });
2848
2866
  this.formStore[formName] = {
2849
- data: this.initializeData(data),
2867
+ data: initializedData,
2850
2868
  config: config,
2851
2869
  validationResults: {},
2870
+ initialSnapshot: initialSnapshot,
2871
+ editingSnapshot: {},
2872
+ allTouched: false,
2873
+ rowTouched: {},
2852
2874
  };
2853
2875
  // 如果配置了自动更新,立即更新一次
2854
2876
  this.autoUpdateArrayReference(formName);
2855
2877
  };
2856
- /**
2857
- * 从存储中获取表单
2858
- *
2859
- * @param formName 表单名称
2860
- * @returns 表单存储项或undefined
2861
- */
2878
+ /** 从存储中获取表单 */
2862
2879
  ArrayFormService.prototype.getForm = function (formName) {
2863
2880
  return this.formStore[formName];
2864
2881
  };
2865
- /**
2866
- * 向表单添加行
2867
- *
2868
- * @param formName 表单名称
2869
- * @param defaultValues 默认值
2870
- * @returns 新增的行数据或undefined
2871
- */
2882
+ /** 从存储中获取表单数据 */
2883
+ ArrayFormService.prototype.getFormData = function (formName) {
2884
+ var form = this.formStore[formName];
2885
+ if (!form) {
2886
+ return undefined;
2887
+ }
2888
+ return form.data.map(function (item) {
2889
+ delete item.isEdit;
2890
+ delete item.isAdd;
2891
+ delete item.uid;
2892
+ return item;
2893
+ });
2894
+ };
2895
+ /** 向表单添加行 */
2872
2896
  ArrayFormService.prototype.addRowToForm = function (formName, defaultValues) {
2873
2897
  var form = this.formStore[formName];
2874
2898
  if (!form) {
2875
2899
  return undefined;
2876
2900
  }
2877
2901
  var newRow = this.addRow(form.data, defaultValues);
2902
+ // 为新行记录初始值快照
2903
+ form.initialSnapshot[newRow.uid] = this.createRowSnapshot(newRow, form.config.fields);
2878
2904
  // 自动更新外部数组引用
2879
2905
  this.autoUpdateArrayReference(formName);
2880
2906
  return newRow;
2881
2907
  };
2882
- /**
2883
- * 校验表单
2884
- *
2885
- * @param formName 表单名称
2886
- * @returns 校验结果或undefined
2887
- */
2908
+ /** 校验表单,自动标记所有字段为已触碰 */
2888
2909
  ArrayFormService.prototype.validateForm = function (formName) {
2910
+ var e_2, _c, e_3, _d;
2889
2911
  var form = this.formStore[formName];
2890
2912
  if (!form) {
2891
- return undefined;
2913
+ return true;
2892
2914
  }
2915
+ // 标记所有字段为已触碰
2916
+ form.allTouched = true;
2893
2917
  var results = this.validateData(form.data, form.config);
2894
2918
  form.validationResults = results;
2895
- return results;
2919
+ try {
2920
+ // 检查是否有任何错误
2921
+ for (var _e = __values(Object.keys(results)), _f = _e.next(); !_f.done; _f = _e.next()) {
2922
+ var uid = _f.value;
2923
+ try {
2924
+ for (var _g = (e_3 = void 0, __values(Object.keys(results[uid]))), _h = _g.next(); !_h.done; _h = _g.next()) {
2925
+ var fieldName = _h.value;
2926
+ if (results[uid][fieldName]) {
2927
+ return false;
2928
+ }
2929
+ }
2930
+ }
2931
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
2932
+ finally {
2933
+ try {
2934
+ if (_h && !_h.done && (_d = _g.return)) _d.call(_g);
2935
+ }
2936
+ finally { if (e_3) throw e_3.error; }
2937
+ }
2938
+ }
2939
+ }
2940
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
2941
+ finally {
2942
+ try {
2943
+ if (_f && !_f.done && (_c = _e.return)) _c.call(_e);
2944
+ }
2945
+ finally { if (e_2) throw e_2.error; }
2946
+ }
2947
+ return true;
2896
2948
  };
2897
- /**
2898
- * 开启指定行的编辑模式
2899
- *
2900
- * @param row 行数据
2901
- */
2902
- ArrayFormService.prototype.enableEdit = function (row) {
2949
+ /** 开启编辑模式,保存快照用于取消恢复 */
2950
+ ArrayFormService.prototype.enableEdit = function (formName, row) {
2951
+ var form = this.formStore[formName];
2952
+ if (form && row.uid) {
2953
+ // 保存编辑前的快照
2954
+ form.editingSnapshot[row.uid] = this.createRowSnapshot(row, form.config.fields);
2955
+ }
2903
2956
  row.isEdit = true;
2904
2957
  };
2905
- /**
2906
- * 关闭指定行的编辑模式
2907
- *
2908
- * @param row 行数据
2909
- */
2910
- ArrayFormService.prototype.disableEdit = function (row) {
2958
+ /** 取消编辑,恢复到编辑前的数据 */
2959
+ ArrayFormService.prototype.disableEdit = function (formName, row) {
2960
+ var _this = this;
2961
+ var form = this.formStore[formName];
2962
+ if (form && row.uid && form.editingSnapshot[row.uid]) {
2963
+ // 恢复编辑前的数据
2964
+ var snapshot_1 = form.editingSnapshot[row.uid];
2965
+ form.config.fields.forEach(function (field) {
2966
+ row[field.name] = _this.cloneValue(snapshot_1[field.name]);
2967
+ });
2968
+ // 更新初始快照为恢复后的值,消除 touched 状态
2969
+ form.initialSnapshot[row.uid] = this.cloneValue(snapshot_1);
2970
+ // 清理编辑快照和 touched 状态
2971
+ delete form.editingSnapshot[row.uid];
2972
+ delete form.rowTouched[row.uid];
2973
+ // 清理该行的校验结果
2974
+ if (form.validationResults) {
2975
+ delete form.validationResults[row.uid];
2976
+ }
2977
+ }
2911
2978
  row.isEdit = false;
2912
2979
  };
2913
- /**
2914
- * 从表单中删除指定行
2915
- *
2916
- * @param formName 表单名称
2917
- * @param row 行的uid
2918
- * @returns 是否删除成功
2919
- */
2980
+ /** 确认编辑,保留修改后的数据 */
2981
+ ArrayFormService.prototype.confirmEdit = function (formName, row) {
2982
+ var form = this.formStore[formName];
2983
+ if (form && row.uid) {
2984
+ // 清理编辑快照(保留当前数据)
2985
+ if (form.editingSnapshot[row.uid]) {
2986
+ delete form.editingSnapshot[row.uid];
2987
+ }
2988
+ // 更新初始快照为当前值(用于后续 touched 检测)
2989
+ form.initialSnapshot[row.uid] = this.createRowSnapshot(row, form.config.fields);
2990
+ // 清除 touched 状态,基于新的 initialSnapshot 重新判断
2991
+ delete form.rowTouched[row.uid];
2992
+ }
2993
+ row.isEdit = false;
2994
+ row.isAdd = false;
2995
+ };
2996
+ /** 从表单中删除指定行 */
2920
2997
  ArrayFormService.prototype.deleteRowFromForm = function (formName, row) {
2921
2998
  var form = this.formStore[formName];
2922
- if (!form) {
2999
+ if (!form || !row.uid) {
2923
3000
  return false;
2924
3001
  }
2925
3002
  var index = form.data.findIndex(function (item) { return item.uid === row.uid; });
@@ -2927,31 +3004,44 @@
2927
3004
  return false;
2928
3005
  }
2929
3006
  form.data.splice(index, 1);
2930
- if (form.validationResults && form.validationResults[row.uid]) {
3007
+ // 清理该行的所有快照、touched 状态和校验结果
3008
+ delete form.initialSnapshot[row.uid];
3009
+ delete form.editingSnapshot[row.uid];
3010
+ delete form.rowTouched[row.uid];
3011
+ if (form.validationResults) {
2931
3012
  delete form.validationResults[row.uid];
2932
3013
  }
2933
3014
  // 自动更新外部数组引用
2934
3015
  this.autoUpdateArrayReference(formName);
2935
3016
  return true;
2936
3017
  };
2937
- /**
2938
- * 校验指定行的指定字段并返回校验结果
2939
- * 实时执行校验,用于模板中的实时校验显示
2940
- *
2941
- * @param formName 表单名称
2942
- * @param row 行数据
2943
- * @param fieldName 字段名
2944
- * @returns 校验结果
2945
- */
3018
+ /** 检测字段是否已被触碰 */
3019
+ ArrayFormService.prototype.isFieldTouched = function (form, row, fieldName) {
3020
+ var _a;
3021
+ // 整个表单已 touched(整个表单提交时)
3022
+ if (form.allTouched) {
3023
+ return true;
3024
+ }
3025
+ // 当前行已 touched(单行保存时)
3026
+ if (form.rowTouched[row.uid]) {
3027
+ return true;
3028
+ }
3029
+ // 检测当前值与初始值是否不同
3030
+ var initialValue = (_a = form.initialSnapshot[row.uid]) === null || _a === void 0 ? void 0 : _a[fieldName];
3031
+ var currentValue = row[fieldName];
3032
+ return !this.isEqual(initialValue, currentValue);
3033
+ };
3034
+ /** 校验指定行的指定字段,未修改时不显示校验状态 */
2946
3035
  ArrayFormService.prototype.validateFieldInRow = function (formName, row, fieldName) {
2947
3036
  var form = this.formStore[formName];
2948
3037
  if (!form) {
2949
- return "success";
3038
+ return "";
2950
3039
  }
2951
3040
  var fieldConfig = form.config.fields.find(function (f) { return f.name === fieldName; });
2952
3041
  if (!fieldConfig) {
2953
- return "success";
3042
+ return "";
2954
3043
  }
3044
+ // 执行校验
2955
3045
  var result = "";
2956
3046
  if (fieldConfig.validator) {
2957
3047
  result = fieldConfig.validator(row[fieldName], row, fieldName);
@@ -2964,21 +3054,36 @@
2964
3054
  form.validationResults[row.uid] = {};
2965
3055
  }
2966
3056
  form.validationResults[row.uid][fieldName] = result;
3057
+ // 如果字段未被触碰,不显示校验状态
3058
+ if (!this.isFieldTouched(form, row, fieldName)) {
3059
+ return "";
3060
+ }
2967
3061
  return result ? "error" : "success";
2968
3062
  };
2969
- /**
2970
- * 校验指定行的所有字段
2971
- *
2972
- * @param formName 表单名称
2973
- * @param row 行数据
2974
- * @returns 是否所有字段都通过校验
2975
- */
3063
+ /** 获取指定行指定字段的校验错误信息 */
3064
+ ArrayFormService.prototype.getFieldErrorMessage = function (formName, row, fieldName) {
3065
+ var _a, _b;
3066
+ var form = this.formStore[formName];
3067
+ if (!form || !row.uid) {
3068
+ return "";
3069
+ }
3070
+ // 如果字段未被触碰,不显示错误信息
3071
+ if (!this.isFieldTouched(form, row, fieldName)) {
3072
+ return "";
3073
+ }
3074
+ return ((_b = (_a = form.validationResults) === null || _a === void 0 ? void 0 : _a[row.uid]) === null || _b === void 0 ? void 0 : _b[fieldName]) || "";
3075
+ };
3076
+ /** 校验指定行的所有字段 */
2976
3077
  ArrayFormService.prototype.validateRowAllFields = function (formName, row) {
2977
3078
  var _this = this;
2978
3079
  var form = this.formStore[formName];
2979
- if (!form) {
3080
+ if (!form || !row.uid) {
2980
3081
  return true;
2981
3082
  }
3083
+ // 更新初始快照为当前值
3084
+ form.initialSnapshot[row.uid] = this.createRowSnapshot(row, form.config.fields);
3085
+ // 标记当前行为 touched(只影响当前行,不影响其他行)
3086
+ form.rowTouched[row.uid] = true;
2982
3087
  var hasError = false;
2983
3088
  form.config.fields.forEach(function (fieldConfig) {
2984
3089
  var result = _this.validateFieldInRow(formName, row, fieldConfig.name);
@@ -2988,12 +3093,7 @@
2988
3093
  });
2989
3094
  return !hasError;
2990
3095
  };
2991
- /**
2992
- * 自动更新外部数组引用(如果配置了)
2993
- * 私有方法,在数据变化时自动调用
2994
- *
2995
- * @param formName 表单名称
2996
- */
3096
+ /** 自动更新外部数组引用 */
2997
3097
  ArrayFormService.prototype.autoUpdateArrayReference = function (formName) {
2998
3098
  var form = this.formStore[formName];
2999
3099
  if (!form || !form.config.targetObject || !form.config.arrayPropertyName) {
@@ -3003,6 +3103,14 @@
3003
3103
  // 更新目标对象的数组属性为新数组引用
3004
3104
  form.config.targetObject[form.config.arrayPropertyName] = newArray;
3005
3105
  };
3106
+ /** 是否有正在编辑的行 */
3107
+ ArrayFormService.prototype.hasEditingRow = function (formName) {
3108
+ var form = this.formStore[formName];
3109
+ if (!form) {
3110
+ return false;
3111
+ }
3112
+ return form.data.some(function (item) { return item.isEdit; });
3113
+ };
3006
3114
  return ArrayFormService;
3007
3115
  }());
3008
3116
  ArrayFormService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ArrayFormService_Factory() { return new ArrayFormService(); }, token: ArrayFormService, providedIn: "root" });