@ldquocc/dynamic-form 0.0.9 → 0.0.11
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/fesm2022/ldquocc-dynamic-form.mjs +4928 -0
- package/fesm2022/ldquocc-dynamic-form.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/dynamic-form.component.d.ts +67 -0
- package/lib/shared/base/base-select.component.d.ts +19 -0
- package/lib/shared/base/base-value-accessor.d.ts +69 -0
- package/{src/lib/shared/components/component.ts → lib/shared/components/component.d.ts} +14 -34
- package/lib/shared/components/dynamic-field/dynamic-field.component.d.ts +23 -0
- package/lib/shared/components/field-user-config/field-user-config.component.d.ts +10 -0
- package/lib/shared/components/fields/components/suffix/suffix.component.d.ts +12 -0
- package/lib/shared/components/fields/date/date-picker/date-picker.component.d.ts +17 -0
- package/lib/shared/components/fields/date/date-range/date-range.component.d.ts +17 -0
- package/lib/shared/components/fields/input/input-formatted/input-formatted.component.d.ts +20 -0
- package/lib/shared/components/fields/input/input-password/input-password.component.d.ts +12 -0
- package/lib/shared/components/fields/input/input-text/input-text.component.d.ts +14 -0
- package/lib/shared/components/fields/select/multi-select/multi-select.component.d.ts +21 -0
- package/lib/shared/components/fields/select/single-select/single-select.component.d.ts +22 -0
- package/lib/shared/components/fields/select/tree-select/tree-select.component.d.ts +28 -0
- package/lib/shared/components/fields/textarea/textarea.component.d.ts +14 -0
- package/lib/shared/components/fields/upload/avatar-upload/avatar-upload.component.d.ts +25 -0
- package/lib/shared/components/fields/upload/multi-file-upload/multi-file-upload.component.d.ts +76 -0
- package/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.d.ts +27 -0
- package/lib/shared/components/fields/upload/single-file-upload/single-file-upload.component.d.ts +29 -0
- package/lib/shared/config/dynamic-form.config.d.ts +9 -0
- package/lib/shared/consts/common/common.const.d.ts +5 -0
- package/lib/shared/consts/common/field-dependency.const.d.ts +1 -0
- package/lib/shared/consts/common/file.const.d.ts +148 -0
- package/{src/lib/shared/consts/common/index.ts → lib/shared/consts/common/index.d.ts} +4 -4
- package/lib/shared/consts/common/standalone-import.const.d.ts +7 -0
- package/lib/shared/consts/controls/control.const.d.ts +1 -0
- package/{src/lib/shared/consts/controls/index.ts → lib/shared/consts/controls/index.d.ts} +1 -1
- package/lib/shared/consts/fields/date-field.const.d.ts +7 -0
- package/lib/shared/consts/fields/field.const.d.ts +4 -0
- package/{src/lib/shared/consts/fields/index.ts → lib/shared/consts/fields/index.d.ts} +5 -5
- package/lib/shared/consts/fields/input-field.const.d.ts +4 -0
- package/lib/shared/consts/fields/input-formatted-field.const.d.ts +4 -0
- package/lib/shared/consts/fields/radio-field.const.d.ts +10 -0
- package/lib/shared/consts/fields/select-field.const.d.ts +6 -0
- package/lib/shared/consts/fields/upload-field.const.d.ts +1 -0
- package/lib/shared/consts/validators/pattern.const.d.ts +2 -0
- package/lib/shared/enums/common/field-dependency.enum.d.ts +9 -0
- package/lib/shared/enums/common/file-size-type.enum.d.ts +6 -0
- package/{src/lib/shared/enums/common/index.ts → lib/shared/enums/common/index.d.ts} +4 -4
- package/lib/shared/enums/common/output-value-type.enum.d.ts +19 -0
- package/lib/shared/enums/common/view-mode.enum.d.ts +4 -0
- package/lib/shared/enums/controls/control.enum.d.ts +11 -0
- package/{src/lib/shared/enums/controls/index.ts → lib/shared/enums/controls/index.d.ts} +1 -1
- package/lib/shared/enums/fields/date-field.enum.d.ts +4 -0
- package/lib/shared/enums/fields/field.enum.d.ts +20 -0
- package/{src/lib/shared/enums/fields/index.ts → lib/shared/enums/fields/index.d.ts} +6 -6
- package/lib/shared/enums/fields/input-field.enum.d.ts +6 -0
- package/lib/shared/enums/fields/input-formatted-field.enum.d.ts +6 -0
- package/lib/shared/enums/fields/select-field.enum.d.ts +4 -0
- package/lib/shared/enums/fields/upload-field.enum.d.ts +5 -0
- package/lib/shared/enums/form/dynamic-form.enum.d.ts +6 -0
- package/{src/lib/shared/enums/form/index.ts → lib/shared/enums/form/index.d.ts} +1 -1
- package/{src/lib/shared/enums/validators/index.ts → lib/shared/enums/validators/index.d.ts} +2 -2
- package/lib/shared/enums/validators/regex.enum.d.ts +38 -0
- package/lib/shared/enums/validators/validators.enum.d.ts +14 -0
- package/lib/shared/factories/auto-numeric-options.factory.d.ts +5 -0
- package/lib/shared/models/common/api-config.model.d.ts +4 -0
- package/lib/shared/models/common/api-response.model.d.ts +19 -0
- package/lib/shared/models/common/common.model.d.ts +29 -0
- package/lib/shared/models/common/field-dependency.model.d.ts +16 -0
- package/lib/shared/models/common/file-config.model.d.ts +11 -0
- package/{src/lib/shared/models/common/index.ts → lib/shared/models/common/index.d.ts} +7 -7
- package/lib/shared/models/common/obj-field.model.d.ts +59 -0
- package/lib/shared/models/common/object-storage.model.d.ts +15 -0
- package/{src/lib/shared/models/common/output-value-type.model.ts → lib/shared/models/common/output-value-type.model.d.ts} +4 -4
- package/lib/shared/models/common/table-models.d.ts +15 -0
- package/{src/lib/shared/models/common/view-mode.model.ts → lib/shared/models/common/view-mode.model.d.ts} +1 -1
- package/{src/lib/shared/models/controls/control.model.ts → lib/shared/models/controls/control.model.d.ts} +2 -3
- package/{src/lib/shared/models/controls/index.ts → lib/shared/models/controls/index.d.ts} +1 -1
- package/lib/shared/models/fields/date/base-date-field.model.d.ts +19 -0
- package/lib/shared/models/fields/date/date-picker-field.model.d.ts +12 -0
- package/lib/shared/models/fields/date/date-range-field.model.d.ts +12 -0
- package/{src/lib/shared/models/fields/date/index.ts → lib/shared/models/fields/date/index.d.ts} +3 -3
- package/lib/shared/models/fields/field-grid.model.d.ts +9 -0
- package/lib/shared/models/fields/field-group.model.d.ts +21 -0
- package/lib/shared/models/fields/field-user-config.model.d.ts +3 -0
- package/lib/shared/models/fields/field.model.d.ts +57 -0
- package/{src/lib/shared/models/fields/index.ts → lib/shared/models/fields/index.d.ts} +2 -2
- package/{src/lib/shared/models/fields/input/index.ts → lib/shared/models/fields/input/index.d.ts} +4 -4
- package/lib/shared/models/fields/input/input-field.model.d.ts +31 -0
- package/lib/shared/models/fields/input/input-formatted-field.model.d.ts +13 -0
- package/lib/shared/models/fields/input/input-password-field.model.d.ts +11 -0
- package/lib/shared/models/fields/input/input-text-field.model.d.ts +9 -0
- package/lib/shared/models/fields/radio/radio-base-field.model.d.ts +26 -0
- package/lib/shared/models/fields/select/multi-select-field.model.d.ts +11 -0
- package/lib/shared/models/fields/select/select-base-field.model.d.ts +40 -0
- package/lib/shared/models/fields/select/single-select-field.model.d.ts +9 -0
- package/lib/shared/models/fields/select/tree-select-field.model.d.ts +10 -0
- package/lib/shared/models/fields/textarea/textarea-field.model.d.ts +20 -0
- package/lib/shared/models/fields/upload/avatar-upload-field.model.d.ts +9 -0
- package/lib/shared/models/fields/upload/base-upload-field.model.d.ts +25 -0
- package/{src/lib/shared/models/fields/upload/index.ts → lib/shared/models/fields/upload/index.d.ts} +5 -5
- package/lib/shared/models/fields/upload/multi-file-upload-field.model.d.ts +10 -0
- package/lib/shared/models/fields/upload/multi-image-upload-field.model.d.ts +12 -0
- package/lib/shared/models/fields/upload/single-file-upload-field.model.d.ts +11 -0
- package/{src/lib/shared/models/form/dynamic-form.model.ts → lib/shared/models/form/dynamic-form.model.d.ts} +1 -1
- package/{src/lib/shared/models/form/index.ts → lib/shared/models/form/index.d.ts} +1 -1
- package/lib/shared/services/dynamic-form.service.d.ts +48 -0
- package/lib/shared/services/field.service.d.ts +41 -0
- package/lib/shared/services/file.service.d.ts +20 -0
- package/lib/shared/services/form-config.service.d.ts +10 -0
- package/lib/shared/services/form-data.service.d.ts +53 -0
- package/lib/shared/services/form-utils.d.ts +5 -0
- package/lib/shared/services/suffix.service.d.ts +12 -0
- package/lib/shared/services/validation.service.d.ts +10 -0
- package/lib/shared/utils/common/common.utils.d.ts +7 -0
- package/{src/lib/shared/utils/common/index.ts → lib/shared/utils/common/index.d.ts} +1 -1
- package/lib/shared/utils/date/date.utils.d.ts +6 -0
- package/{src/lib/shared/utils/date/index.ts → lib/shared/utils/date/index.d.ts} +1 -1
- package/lib/shared/utils/dynamic-form/dynamic-form.d.ts +11 -0
- package/lib/shared/utils/fields/fields.d.ts +20 -0
- package/{src/lib/shared/utils/fields/index.ts → lib/shared/utils/fields/index.d.ts} +1 -1
- package/lib/shared/utils/file/file.utils.d.ts +4 -0
- package/{src/lib/shared/utils/file/index.ts → lib/shared/utils/file/index.d.ts} +1 -1
- package/lib/shared/utils/validators/custom-validators.d.ts +11 -0
- package/lib/shared/utils/validators/default-error-message.d.ts +6 -0
- package/{src/lib/shared/utils/validators/index.ts → lib/shared/utils/validators/index.d.ts} +3 -3
- package/lib/shared/utils/validators/pattern.d.ts +4 -0
- package/package.json +31 -20
- package/{src/public-api.ts → public-api.d.ts} +29 -68
- package/ng-package.json +0 -15
- package/src/lib/dynamic-form.component.html +0 -121
- package/src/lib/dynamic-form.component.scss +0 -7
- package/src/lib/dynamic-form.component.spec.ts +0 -21
- package/src/lib/dynamic-form.component.ts +0 -237
- package/src/lib/dynamic-form.service.spec.ts +0 -16
- package/src/lib/dynamic-form.service.ts +0 -9
- package/src/lib/shared/base/base-select.component.ts +0 -183
- package/src/lib/shared/base/base-value-accessor.ts +0 -192
- package/src/lib/shared/components/d-form-testing/d-form-testing.component.html +0 -197
- package/src/lib/shared/components/d-form-testing/d-form-testing.component.less +0 -12
- package/src/lib/shared/components/d-form-testing/d-form-testing.component.spec.ts +0 -22
- package/src/lib/shared/components/d-form-testing/d-form-testing.component.ts +0 -197
- package/src/lib/shared/components/dynamic-field/dynamic-field.component.html +0 -218
- package/src/lib/shared/components/dynamic-field/dynamic-field.component.scss +0 -28
- package/src/lib/shared/components/dynamic-field/dynamic-field.component.spec.ts +0 -21
- package/src/lib/shared/components/dynamic-field/dynamic-field.component.ts +0 -67
- package/src/lib/shared/components/field-user-config/field-user-config.component.html +0 -38
- package/src/lib/shared/components/field-user-config/field-user-config.component.scss +0 -29
- package/src/lib/shared/components/field-user-config/field-user-config.component.ts +0 -33
- package/src/lib/shared/components/fields/components/suffix/suffix.component.html +0 -42
- package/src/lib/shared/components/fields/components/suffix/suffix.component.scss +0 -3
- package/src/lib/shared/components/fields/components/suffix/suffix.component.spec.ts +0 -22
- package/src/lib/shared/components/fields/components/suffix/suffix.component.ts +0 -32
- package/src/lib/shared/components/fields/date/date-picker/date-picker.component.html +0 -20
- package/src/lib/shared/components/fields/date/date-picker/date-picker.component.scss +0 -5
- package/src/lib/shared/components/fields/date/date-picker/date-picker.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/date/date-picker/date-picker.component.ts +0 -148
- package/src/lib/shared/components/fields/date/date-range/date-range.component.html +0 -33
- package/src/lib/shared/components/fields/date/date-range/date-range.component.scss +0 -22
- package/src/lib/shared/components/fields/date/date-range/date-range.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/date/date-range/date-range.component.ts +0 -133
- package/src/lib/shared/components/fields/input/input-formatted/input-formatted.component.html +0 -31
- package/src/lib/shared/components/fields/input/input-formatted/input-formatted.component.scss +0 -3
- package/src/lib/shared/components/fields/input/input-formatted/input-formatted.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/input/input-formatted/input-formatted.component.ts +0 -148
- package/src/lib/shared/components/fields/input/input-password/input-password.component.html +0 -18
- package/src/lib/shared/components/fields/input/input-password/input-password.component.scss +0 -0
- package/src/lib/shared/components/fields/input/input-password/input-password.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/input/input-password/input-password.component.ts +0 -56
- package/src/lib/shared/components/fields/input/input-text/input-text.component.html +0 -73
- package/src/lib/shared/components/fields/input/input-text/input-text.component.scss +0 -0
- package/src/lib/shared/components/fields/input/input-text/input-text.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/input/input-text/input-text.component.ts +0 -98
- package/src/lib/shared/components/fields/select/multi-select/multi-select.component.html +0 -73
- package/src/lib/shared/components/fields/select/multi-select/multi-select.component.scss +0 -21
- package/src/lib/shared/components/fields/select/multi-select/multi-select.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/select/multi-select/multi-select.component.ts +0 -212
- package/src/lib/shared/components/fields/select/single-select/single-select.component.html +0 -55
- package/src/lib/shared/components/fields/select/single-select/single-select.component.scss +0 -1
- package/src/lib/shared/components/fields/select/single-select/single-select.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/select/single-select/single-select.component.ts +0 -217
- package/src/lib/shared/components/fields/select/single-select/sl.component.old.txt +0 -337
- package/src/lib/shared/components/fields/select/single-select/sl.component.old2.txt +0 -340
- package/src/lib/shared/components/fields/select/tree-select/tree-select.component.html +0 -38
- package/src/lib/shared/components/fields/select/tree-select/tree-select.component.scss +0 -1
- package/src/lib/shared/components/fields/select/tree-select/tree-select.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/select/tree-select/tree-select.component.ts +0 -401
- package/src/lib/shared/components/fields/textarea/textarea.component.html +0 -29
- package/src/lib/shared/components/fields/textarea/textarea.component.scss +0 -17
- package/src/lib/shared/components/fields/textarea/textarea.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/textarea/textarea.component.ts +0 -76
- package/src/lib/shared/components/fields/upload/avatar-upload/avatar-upload.component.html +0 -30
- package/src/lib/shared/components/fields/upload/avatar-upload/avatar-upload.component.scss +0 -22
- package/src/lib/shared/components/fields/upload/avatar-upload/avatar-upload.component.spec.ts +0 -22
- package/src/lib/shared/components/fields/upload/avatar-upload/avatar-upload.component.ts +0 -217
- package/src/lib/shared/components/fields/upload/multi-file-upload/multi-file-upload.component.html +0 -101
- package/src/lib/shared/components/fields/upload/multi-file-upload/multi-file-upload.component.scss +0 -117
- package/src/lib/shared/components/fields/upload/multi-file-upload/multi-file-upload.component.spec.ts +0 -22
- package/src/lib/shared/components/fields/upload/multi-file-upload/multi-file-upload.component.ts +0 -480
- package/src/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.html +0 -82
- package/src/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.less +0 -80
- package/src/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.spec.ts +0 -22
- package/src/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.ts +0 -288
- package/src/lib/shared/components/fields/upload/single-file-upload/single-file-upload.component.html +0 -104
- package/src/lib/shared/components/fields/upload/single-file-upload/single-file-upload.component.scss +0 -37
- package/src/lib/shared/components/fields/upload/single-file-upload/single-file-upload.component.spec.ts +0 -21
- package/src/lib/shared/components/fields/upload/single-file-upload/single-file-upload.component.ts +0 -317
- package/src/lib/shared/config/dynamic-form.config.ts +0 -11
- package/src/lib/shared/consts/common/common.const.ts +0 -5
- package/src/lib/shared/consts/common/field-dependency.const.ts +0 -1
- package/src/lib/shared/consts/common/file.const.ts +0 -130
- package/src/lib/shared/consts/common/sample-test.const.ts +0 -1648
- package/src/lib/shared/consts/common/standalone-import.const.ts +0 -51
- package/src/lib/shared/consts/controls/control.const.ts +0 -11
- package/src/lib/shared/consts/fields/date-field.const.ts +0 -12
- package/src/lib/shared/consts/fields/field.const.ts +0 -23
- package/src/lib/shared/consts/fields/input-field.const.ts +0 -4
- package/src/lib/shared/consts/fields/input-formatted-field.const.ts +0 -35
- package/src/lib/shared/consts/fields/radio-field.const.ts +0 -31
- package/src/lib/shared/consts/fields/select-field.const.ts +0 -7
- package/src/lib/shared/consts/fields/upload-field.const.ts +0 -1
- package/src/lib/shared/consts/validators/index.ts +0 -0
- package/src/lib/shared/consts/validators/pattern.const.ts +0 -117
- package/src/lib/shared/enums/common/component-ui.enum.ts +0 -8
- package/src/lib/shared/enums/common/field-dependency.enum.ts +0 -10
- package/src/lib/shared/enums/common/file-size-type.enum.ts +0 -6
- package/src/lib/shared/enums/common/output-value-type.enum.ts +0 -22
- package/src/lib/shared/enums/common/view-mode.enum.ts +0 -4
- package/src/lib/shared/enums/controls/control.enum.ts +0 -12
- package/src/lib/shared/enums/fields/date-field.enum.ts +0 -4
- package/src/lib/shared/enums/fields/field.enum.ts +0 -21
- package/src/lib/shared/enums/fields/input-field.enum.ts +0 -6
- package/src/lib/shared/enums/fields/input-formatted-field.enum.ts +0 -6
- package/src/lib/shared/enums/fields/select-field.enum.ts +0 -4
- package/src/lib/shared/enums/fields/upload-field.enum.ts +0 -5
- package/src/lib/shared/enums/form/dynamic-form.enum.ts +0 -6
- package/src/lib/shared/enums/validators/regex.enum.ts +0 -47
- package/src/lib/shared/enums/validators/validators.enum.ts +0 -17
- package/src/lib/shared/factories/auto-numeric-options.factory.ts +0 -14
- package/src/lib/shared/models/common/api-config.model.ts +0 -7
- package/src/lib/shared/models/common/api-response.model.ts +0 -20
- package/src/lib/shared/models/common/common.model.ts +0 -39
- package/src/lib/shared/models/common/field-dependency.model.ts +0 -27
- package/src/lib/shared/models/common/file-config.model.ts +0 -22
- package/src/lib/shared/models/common/obj-field.model.ts +0 -68
- package/src/lib/shared/models/common/object-storage.model.ts +0 -15
- package/src/lib/shared/models/common/table-models.ts +0 -16
- package/src/lib/shared/models/fields/date/base-date-field.model.ts +0 -52
- package/src/lib/shared/models/fields/date/date-picker-field.model.ts +0 -43
- package/src/lib/shared/models/fields/date/date-range-field.model.ts +0 -52
- package/src/lib/shared/models/fields/field-grid.model.ts +0 -10
- package/src/lib/shared/models/fields/field-group.model.ts +0 -50
- package/src/lib/shared/models/fields/field-user-config.model.ts +0 -8
- package/src/lib/shared/models/fields/field.model.ts +0 -184
- package/src/lib/shared/models/fields/input/input-field.model.ts +0 -111
- package/src/lib/shared/models/fields/input/input-formatted-field.model.ts +0 -38
- package/src/lib/shared/models/fields/input/input-password-field.model.ts +0 -38
- package/src/lib/shared/models/fields/input/input-text-field.model.ts +0 -26
- package/src/lib/shared/models/fields/radio/index.ts +0 -0
- package/src/lib/shared/models/fields/radio/radio-base-field.model.ts +0 -84
- package/src/lib/shared/models/fields/select/index.ts +0 -0
- package/src/lib/shared/models/fields/select/multi-select-field.model.ts +0 -46
- package/src/lib/shared/models/fields/select/select-base-field.model.ts +0 -125
- package/src/lib/shared/models/fields/select/single-select-field.model.ts +0 -43
- package/src/lib/shared/models/fields/select/tree-select-field.model.ts +0 -44
- package/src/lib/shared/models/fields/textarea/index.ts +0 -0
- package/src/lib/shared/models/fields/textarea/textarea-field.model.ts +0 -97
- package/src/lib/shared/models/fields/upload/avatar-upload-field.model.ts +0 -33
- package/src/lib/shared/models/fields/upload/base-upload-field.model.ts +0 -105
- package/src/lib/shared/models/fields/upload/multi-file-upload-field.model.ts +0 -34
- package/src/lib/shared/models/fields/upload/multi-image-upload-field.model.ts +0 -42
- package/src/lib/shared/models/fields/upload/single-file-upload-field.model.ts +0 -33
- package/src/lib/shared/models/validations/index.ts +0 -1
- package/src/lib/shared/models/validations/validations.model.ts +0 -14
- package/src/lib/shared/services/dynamic-form.service.spec.ts +0 -16
- package/src/lib/shared/services/dynamic-form.service.ts +0 -251
- package/src/lib/shared/services/field.service.spec.ts +0 -16
- package/src/lib/shared/services/field.service.ts +0 -152
- package/src/lib/shared/services/file.service.spec.ts +0 -16
- package/src/lib/shared/services/file.service.ts +0 -53
- package/src/lib/shared/services/form-config.service.ts +0 -53
- package/src/lib/shared/services/form-data.service.spec.ts +0 -16
- package/src/lib/shared/services/form-data.service.ts +0 -114
- package/src/lib/shared/services/form-utils.ts +0 -52
- package/src/lib/shared/services/suffix.service.spec.ts +0 -16
- package/src/lib/shared/services/suffix.service.ts +0 -16
- package/src/lib/shared/services/validation.service.spec.ts +0 -16
- package/src/lib/shared/services/validation.service.ts +0 -38
- package/src/lib/shared/utils/common/common.utils.ts +0 -52
- package/src/lib/shared/utils/date/date.utils.ts +0 -129
- package/src/lib/shared/utils/dynamic-field/dynamic-field.ts +0 -0
- package/src/lib/shared/utils/dynamic-field/index.ts +0 -0
- package/src/lib/shared/utils/dynamic-form/dynamic-form.ts +0 -114
- package/src/lib/shared/utils/dynamic-form/index.ts +0 -0
- package/src/lib/shared/utils/fields/fields.ts +0 -78
- package/src/lib/shared/utils/file/file.utils.ts +0 -37
- package/src/lib/shared/utils/validators/custom-validators.ts +0 -158
- package/src/lib/shared/utils/validators/default-error-message.ts +0 -42
- package/src/lib/shared/utils/validators/pattern.ts +0 -26
- package/tsconfig.lib.json +0 -15
- package/tsconfig.lib.prod.json +0 -11
- package/tsconfig.spec.json +0 -15
- /package/{src/lib/shared/styles → styles}/_common-form.scss +0 -0
package/src/lib/shared/components/fields/upload/multi-file-upload/multi-file-upload.component.ts
DELETED
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
computed,
|
|
4
|
-
effect,
|
|
5
|
-
forwardRef,
|
|
6
|
-
inject,
|
|
7
|
-
signal,
|
|
8
|
-
untracked,
|
|
9
|
-
} from "@angular/core";
|
|
10
|
-
import { CORE_MODULES } from "../../../../consts/common";
|
|
11
|
-
import { BaseValueAccessor } from "../../../../base/base-value-accessor";
|
|
12
|
-
import {
|
|
13
|
-
NzUploadFile,
|
|
14
|
-
NzUploadModule,
|
|
15
|
-
NzUploadXHRArgs,
|
|
16
|
-
} from "ng-zorro-antd/upload";
|
|
17
|
-
import { MultiFileUploadField } from "../../../../models/fields/upload/multi-file-upload-field.model";
|
|
18
|
-
import { FieldTypeEnum } from "../../../../enums/fields";
|
|
19
|
-
import { isValidJSON } from "../../../../utils/common";
|
|
20
|
-
import { MyUploadFile } from "../../../../models/common/common.model";
|
|
21
|
-
import { ObjectStorage } from "../../../../models/common";
|
|
22
|
-
import { FileService } from "../../../../services/file.service";
|
|
23
|
-
import { Observable, of, Subscription } from "rxjs";
|
|
24
|
-
import { NG_VALUE_ACCESSOR } from "@angular/forms";
|
|
25
|
-
import { ControlTypeEnum } from "../../../../enums/controls";
|
|
26
|
-
import { formatFileSize, getExtensions } from "../../../../utils/file";
|
|
27
|
-
import { FileSizeTypeEnum } from "../../../../enums/common";
|
|
28
|
-
import { FormConfigService } from "../../../../services/form-config.service";
|
|
29
|
-
import { NzIconModule } from "ng-zorro-antd/icon";
|
|
30
|
-
import { NzButtonModule } from "ng-zorro-antd/button";
|
|
31
|
-
import { NzMessageService } from "ng-zorro-antd/message";
|
|
32
|
-
import { NzNotificationService } from "ng-zorro-antd/notification";
|
|
33
|
-
|
|
34
|
-
const ZORRO_MODULES = [NzUploadModule, NzIconModule, NzButtonModule];
|
|
35
|
-
|
|
36
|
-
@Component({
|
|
37
|
-
selector: "app-multi-file-upload",
|
|
38
|
-
standalone: true,
|
|
39
|
-
imports: [...CORE_MODULES, ...ZORRO_MODULES],
|
|
40
|
-
templateUrl: "./multi-file-upload.component.html",
|
|
41
|
-
styleUrl: "./multi-file-upload.component.scss",
|
|
42
|
-
providers: [
|
|
43
|
-
{
|
|
44
|
-
provide: NG_VALUE_ACCESSOR,
|
|
45
|
-
useExisting: forwardRef(() => MultiFileUploadComponent),
|
|
46
|
-
multi: true,
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
})
|
|
50
|
-
export class MultiFileUploadComponent extends BaseValueAccessor<
|
|
51
|
-
string | File | NzUploadFile
|
|
52
|
-
> {
|
|
53
|
-
// Cast lại đúng instance là MultiFileUploadFile.
|
|
54
|
-
readonly field = computed(() => {
|
|
55
|
-
const base = this.fieldInput();
|
|
56
|
-
if (
|
|
57
|
-
!(base instanceof MultiFileUploadField) ||
|
|
58
|
-
(base.type !== FieldTypeEnum.MultiFileUpload &&
|
|
59
|
-
base.controlType !== ControlTypeEnum.Upload)
|
|
60
|
-
) {
|
|
61
|
-
throw new Error("Expected MultiFileUploadField");
|
|
62
|
-
}
|
|
63
|
-
return base;
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Mảng lưu trữ objectStorage liên quan đến tập tin.
|
|
67
|
-
objStorageList = signal<ObjectStorage[]>([]);
|
|
68
|
-
|
|
69
|
-
// Mảng đại diện các images.
|
|
70
|
-
allFiles = signal<MyUploadFile[]>([]);
|
|
71
|
-
|
|
72
|
-
// Text hướng dẫn các loại extension được upload.
|
|
73
|
-
readonly fileExtensionGuide = computed(() => {
|
|
74
|
-
if (!this.isAddOrEdit()) return "";
|
|
75
|
-
const { acceptedMimeTypes } = this.field();
|
|
76
|
-
return `Hỗ trợ định dạng ${getExtensions(acceptedMimeTypes).join(", ")}`;
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// Đếm số file đã pass beforeUpload nhưng chưa upload xong (đang trong hàng chờ customRequest/uploadFile).
|
|
80
|
-
// Dùng để tính toán count chính xác khi user chọn nhiều file cùng lúc.
|
|
81
|
-
pendingCount = signal<number>(0);
|
|
82
|
-
|
|
83
|
-
// Buffer chứa các file đang chờ xử lý trong một batch (một lần chọn file từ dialog).
|
|
84
|
-
private _batchBuffer: Array<{
|
|
85
|
-
file: NzUploadFile;
|
|
86
|
-
resolve: (pass: boolean) => void;
|
|
87
|
-
}> = [];
|
|
88
|
-
|
|
89
|
-
// Timer dùng để phát hiện kết thúc một batch (setTimeout(0)).
|
|
90
|
-
private _batchTimer: ReturnType<typeof setTimeout> | null = null;
|
|
91
|
-
|
|
92
|
-
private fileService = inject(FileService);
|
|
93
|
-
private nzMessage = inject(NzMessageService);
|
|
94
|
-
private nzNotification = inject(NzNotificationService);
|
|
95
|
-
private formConfigService = inject(FormConfigService);
|
|
96
|
-
|
|
97
|
-
constructor() {
|
|
98
|
-
super();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
102
|
-
protected override writeValueToView(value: string): void {
|
|
103
|
-
this.handleInitAllData(value);
|
|
104
|
-
|
|
105
|
-
if (!this.isAddOrEdit()) return;
|
|
106
|
-
|
|
107
|
-
// Gán data vào đầu ra của form.
|
|
108
|
-
this.patchFormData(this.fieldKey(), value);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Xử lý init các data cần thiết: objStorageList, allFiles, fileList, lưu giữ first value.
|
|
112
|
-
// value sẽ là 1 string json mảng các objStorage.
|
|
113
|
-
private handleInitAllData(value: string): void {
|
|
114
|
-
// Reset khi đổi mode, hoặc model, hoặc fields.
|
|
115
|
-
this.objStorageList.set([]);
|
|
116
|
-
this.allFiles.set([]);
|
|
117
|
-
|
|
118
|
-
if (isValidJSON(value)) {
|
|
119
|
-
// Khởi tạo danh sách ObjectStorage từ data json.
|
|
120
|
-
const objStorageList = JSON.parse(value) as ObjectStorage[];
|
|
121
|
-
this.objStorageList.set(objStorageList);
|
|
122
|
-
|
|
123
|
-
// Khởi tạo danh sách MyUploadFile từ data json.
|
|
124
|
-
// File từ server luôn ở trạng thái success.
|
|
125
|
-
const myUploadFiles = objStorageList.map(
|
|
126
|
-
(objStorage) =>
|
|
127
|
-
({
|
|
128
|
-
objStorage,
|
|
129
|
-
isTemp: false,
|
|
130
|
-
previewUrl: this.formConfigService.getViewFileUrl(
|
|
131
|
-
objStorage.name ?? "",
|
|
132
|
-
false,
|
|
133
|
-
),
|
|
134
|
-
uploadStatus: "success",
|
|
135
|
-
}) as MyUploadFile,
|
|
136
|
-
);
|
|
137
|
-
this.allFiles.set(myUploadFiles);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Xử lý trước khi upload — trả về Observable<boolean> để hỗ trợ batch detection.
|
|
143
|
-
*
|
|
144
|
-
* Cơ chế batch detection:
|
|
145
|
-
* nz-upload gọi beforeUpload() từng file một (đồng bộ) trong cùng 1 JS tick khi user
|
|
146
|
-
* chọn nhiều file. Mỗi lần gọi, file được đẩy vào _batchBuffer. Sau khi tất cả các
|
|
147
|
-
* lần gọi đồng bộ kết thúc, setTimeout(0) kích hoạt _processBatch() để xử lý toàn bộ
|
|
148
|
-
* batch một lần, cho phép kiểm tra tổng số lượng chính xác trước khi upload.
|
|
149
|
-
*/
|
|
150
|
-
beforeUpload = (file: NzUploadFile): Observable<boolean> => {
|
|
151
|
-
return new Observable<boolean>((subscriber) => {
|
|
152
|
-
// Đẩy file vào buffer với hàm resolve tương ứng.
|
|
153
|
-
this._batchBuffer.push({
|
|
154
|
-
file,
|
|
155
|
-
resolve: (pass: boolean) => {
|
|
156
|
-
subscriber.next(pass);
|
|
157
|
-
subscriber.complete();
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Reset timer mỗi lần có file mới vào buffer.
|
|
162
|
-
// Khi tất cả beforeUpload synchronous calls kết thúc, timer sẽ fire và gọi _processBatch().
|
|
163
|
-
if (this._batchTimer !== null) clearTimeout(this._batchTimer);
|
|
164
|
-
this._batchTimer = setTimeout(() => this._processBatch(), 0);
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Xử lý toàn bộ batch file sau khi tất cả beforeUpload calls trong cùng 1 tick đã hoàn tất.
|
|
170
|
-
*
|
|
171
|
-
* Logic:
|
|
172
|
-
* 1. Nếu tổng (file hiện tại + pending + batch) vượt maxFileCount → reject TOÀN BỘ batch.
|
|
173
|
-
* 2. Validate từng file trong batch:
|
|
174
|
-
* - File thỏa (MIME + size) → pendingCount++, resolve(true) → cho phép upload.
|
|
175
|
-
* - File không thỏa → hiển thị NzMessage lỗi, resolve(false) → bỏ qua.
|
|
176
|
-
*/
|
|
177
|
-
private _processBatch(): void {
|
|
178
|
-
const batch = [...this._batchBuffer];
|
|
179
|
-
this._batchBuffer = [];
|
|
180
|
-
this._batchTimer = null;
|
|
181
|
-
|
|
182
|
-
const { maxFileCount, maxSizeInMB, acceptedMimeTypes } = this.field();
|
|
183
|
-
|
|
184
|
-
// Số file hiện tại: đã upload xong + đang trong hàng chờ upload.
|
|
185
|
-
const currentCount = this.allFiles().length + this.pendingCount();
|
|
186
|
-
|
|
187
|
-
// ── CHECK 1: Tổng batch vượt maxFileCount → reject TOÀN BỘ batch ──
|
|
188
|
-
if (currentCount + batch.length > maxFileCount) {
|
|
189
|
-
this.nzNotification.warning(
|
|
190
|
-
"Cảnh báo",
|
|
191
|
-
`Không thể tải lên: số lượng file tải lên vượt quá giới hạn cho phép. Tối đa ${maxFileCount} tập tin.`,
|
|
192
|
-
{ nzDuration: 4500 },
|
|
193
|
-
);
|
|
194
|
-
batch.forEach(({ resolve }) => resolve(false));
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// ── CHECK 2: Validate từng file — upload file thỏa, báo lỗi file không thỏa ──
|
|
199
|
-
for (const { file, resolve } of batch) {
|
|
200
|
-
const originFile = file as unknown as File;
|
|
201
|
-
const fileSizeInMB = formatFileSize(file.size!, FileSizeTypeEnum.MB);
|
|
202
|
-
const fileType = file.type ?? "";
|
|
203
|
-
|
|
204
|
-
const isSizeOk = fileSizeInMB <= maxSizeInMB;
|
|
205
|
-
const isMimeOk = acceptedMimeTypes.includes(fileType);
|
|
206
|
-
|
|
207
|
-
if (!isSizeOk || !isMimeOk) {
|
|
208
|
-
// Xây dựng thông báo lỗi chi tiết cho từng file không thỏa.
|
|
209
|
-
const reasons: string[] = [];
|
|
210
|
-
if (!isMimeOk) reasons.push(`định dạng không hợp lệ`);
|
|
211
|
-
if (!isSizeOk) reasons.push(`kích thước vượt ${maxSizeInMB}MB`);
|
|
212
|
-
|
|
213
|
-
this.nzMessage.error(
|
|
214
|
-
`"${file.name}" không được tải lên: ${reasons.join(", ")}.`,
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
// Propagate để CVA/validator hiển thị trạng thái lỗi trên control.
|
|
218
|
-
this.propagateValue(originFile);
|
|
219
|
-
resolve(false);
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// File hợp lệ: thêm optimistic entry vào allFiles với trạng thái loading ngay lập tức.
|
|
224
|
-
// Dùng file.uid (do nz-upload tự tạo, duy nhất cho mỗi NzUploadFile) làm key để track và update sau này.
|
|
225
|
-
const uid = file.uid;
|
|
226
|
-
this.allFiles.update((curr) => [
|
|
227
|
-
...curr,
|
|
228
|
-
{
|
|
229
|
-
uid,
|
|
230
|
-
objStorage: { id: uid, name: originFile.name }, // placeholder, sẽ được thay bằng data thật sau khi upload
|
|
231
|
-
isTemp: true,
|
|
232
|
-
previewUrl: "",
|
|
233
|
-
uploadStatus: "loading",
|
|
234
|
-
} as MyUploadFile,
|
|
235
|
-
]);
|
|
236
|
-
|
|
237
|
-
// Propagate để trigger validator, tăng pendingCount, cho phép upload.
|
|
238
|
-
this.propagateValue(originFile);
|
|
239
|
-
this.pendingCount.update((c) => c + 1);
|
|
240
|
-
resolve(true);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
customRequest = (item: NzUploadXHRArgs): Subscription => {
|
|
245
|
-
// const originFile = nzUploadFile?.originFileObj;
|
|
246
|
-
const uid = item.file.uid; // Stable key để map với optimistic entry trong allFiles.
|
|
247
|
-
const originFile = item.file as unknown as File;
|
|
248
|
-
|
|
249
|
-
// Nếu validation không thỏa, dừng tại đây và xóa optimistic entry khỏi list.
|
|
250
|
-
if (this.control?.invalid) {
|
|
251
|
-
this.pendingCount.update((c) => Math.max(0, c - 1));
|
|
252
|
-
this.allFiles.update((curr) => curr.filter((f) => f.uid !== uid));
|
|
253
|
-
return of(null).subscribe(); // fake subscription.
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Validation đã thỏa, tiến hành upload file.
|
|
257
|
-
return this.uploadFile(originFile, uid);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
private uploadFile(file: File, uid: string) {
|
|
261
|
-
const { apiFileConfig, uploadTemp } = this.field();
|
|
262
|
-
const newFileName = this.formConfigService.generateRandomFileName(
|
|
263
|
-
file.name,
|
|
264
|
-
"file",
|
|
265
|
-
);
|
|
266
|
-
const renamedFile = new File([file], newFileName, { type: file.type });
|
|
267
|
-
|
|
268
|
-
const mimeCfg = apiFileConfig.perMimeTypeConfig?.[file.type]; // Lấy mimeTypes file upload.
|
|
269
|
-
const uploadUrl = mimeCfg?.uploadUrl ?? apiFileConfig.uploadUrl; // Nếu có config upload riêng cho mimeTypes đang kiểm tra.
|
|
270
|
-
const formData = mimeCfg?.buildFormData // Nếu có hàm custon buildFormData.
|
|
271
|
-
? mimeCfg.buildFormData(file, {})
|
|
272
|
-
: (() => {
|
|
273
|
-
// Mặc định
|
|
274
|
-
const fd = new FormData();
|
|
275
|
-
fd.append("File", renamedFile);
|
|
276
|
-
// fd.append('isTemp', 'true');
|
|
277
|
-
return fd;
|
|
278
|
-
})();
|
|
279
|
-
|
|
280
|
-
if (uploadTemp) formData.append("isTemp", "true");
|
|
281
|
-
|
|
282
|
-
return this.fileService
|
|
283
|
-
.uploadFile(renamedFile, formData, { uploadUrl })
|
|
284
|
-
.pipe(this.takeUntilDestroy())
|
|
285
|
-
.subscribe({
|
|
286
|
-
next: (res) => {
|
|
287
|
-
// Giảm pending dù thành công hay thất bại.
|
|
288
|
-
this.pendingCount.update((c) => Math.max(0, c - 1));
|
|
289
|
-
|
|
290
|
-
const { code, data, message } = res;
|
|
291
|
-
if (code === 0) {
|
|
292
|
-
// Cập nhật objStorageList với data thật từ server.
|
|
293
|
-
this.objStorageList.update((curr) => [...curr, data]);
|
|
294
|
-
|
|
295
|
-
// Thay thế optimistic entry (uid) bằng data thật, chuyển sang trạng thái success.
|
|
296
|
-
this.allFiles.update((curr) =>
|
|
297
|
-
curr.map((f) =>
|
|
298
|
-
f.uid === uid
|
|
299
|
-
? ({
|
|
300
|
-
...f,
|
|
301
|
-
objStorage: data,
|
|
302
|
-
previewUrl: this.formConfigService.getViewFileUrl(
|
|
303
|
-
data.name ?? "",
|
|
304
|
-
true,
|
|
305
|
-
),
|
|
306
|
-
uploadStatus: "success",
|
|
307
|
-
} as MyUploadFile)
|
|
308
|
-
: f,
|
|
309
|
-
),
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
this.patchFormData(
|
|
313
|
-
this.fieldKey(),
|
|
314
|
-
JSON.stringify(this.objStorageList()),
|
|
315
|
-
);
|
|
316
|
-
// Đồng bộ control value → validators (required) nhận biết có file thành công.
|
|
317
|
-
this._syncControlValue();
|
|
318
|
-
} else {
|
|
319
|
-
// Cập nhật optimistic entry sang trạng thái error.
|
|
320
|
-
this.allFiles.update((curr) =>
|
|
321
|
-
curr.map((f) =>
|
|
322
|
-
f.uid === uid
|
|
323
|
-
? ({ ...f, uploadStatus: "error" } as MyUploadFile)
|
|
324
|
-
: f,
|
|
325
|
-
),
|
|
326
|
-
);
|
|
327
|
-
console.error(message);
|
|
328
|
-
// Đồng bộ control value → nếu tất cả file đều fail, objStorageList rỗng → required kích hoạt.
|
|
329
|
-
this._syncControlValue();
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
error: () => {
|
|
333
|
-
// Giảm pending khi upload thất bại.
|
|
334
|
-
this.pendingCount.update((c) => Math.max(0, c - 1));
|
|
335
|
-
// Cập nhật optimistic entry sang trạng thái error.
|
|
336
|
-
this.allFiles.update((curr) =>
|
|
337
|
-
curr.map((f) =>
|
|
338
|
-
f.uid === uid
|
|
339
|
-
? ({ ...f, uploadStatus: "error" } as MyUploadFile)
|
|
340
|
-
: f,
|
|
341
|
-
),
|
|
342
|
-
);
|
|
343
|
-
console.error("Lỗi trong quá trình tải tập đến máy chủ!!");
|
|
344
|
-
// Đồng bộ control value → nếu tất cả file đều fail → required kích hoạt.
|
|
345
|
-
this._syncControlValue();
|
|
346
|
-
},
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
handleDelete(file: MyUploadFile): void {
|
|
351
|
-
const { objStorage, uploadStatus } = file;
|
|
352
|
-
const { uploadTemp } = this.field();
|
|
353
|
-
|
|
354
|
-
// Loại bỏ và cập nhật danh sách ObjectStorage.
|
|
355
|
-
const newObjStorageList = this.objStorageList().filter(
|
|
356
|
-
(item) => item.id !== objStorage?.id,
|
|
357
|
-
);
|
|
358
|
-
this.objStorageList.set(newObjStorageList);
|
|
359
|
-
|
|
360
|
-
// Loại bỏ và cập nhật danh sách MyUploadFile.
|
|
361
|
-
const newAllFiles = this.allFiles().filter(
|
|
362
|
-
(item) => item.objStorage?.id !== objStorage?.id,
|
|
363
|
-
);
|
|
364
|
-
this.allFiles.set(newAllFiles);
|
|
365
|
-
|
|
366
|
-
// File ở trạng thái error: upload chưa thành công, không cần gọi API xoá trên server.
|
|
367
|
-
if (uploadStatus === "error") {
|
|
368
|
-
this.patchFormData(
|
|
369
|
-
this.fieldKey(),
|
|
370
|
-
JSON.stringify(this.objStorageList()),
|
|
371
|
-
);
|
|
372
|
-
// Đồng bộ control value → nếu xóa hết file error còn lại → required kích hoạt.
|
|
373
|
-
this._syncControlValue();
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (uploadTemp) {
|
|
378
|
-
this.deleteObjStorage(objStorage.id || "");
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// Cập nhật đầu ra cho form.
|
|
383
|
-
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
384
|
-
// Đồng bộ control value → nếu xóa hết file → required kích hoạt.
|
|
385
|
-
this._syncControlValue();
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
deleteObjStorage(id: string) {
|
|
389
|
-
return this.fileService
|
|
390
|
-
.deleteObjStorage(id, {
|
|
391
|
-
deleteUrl: this.field().apiFileConfig.deleteUrl,
|
|
392
|
-
})
|
|
393
|
-
.pipe(this.takeUntilDestroy())
|
|
394
|
-
.subscribe({
|
|
395
|
-
next: (res) => {
|
|
396
|
-
const { code, message } = res;
|
|
397
|
-
if (code === 0) {
|
|
398
|
-
const newObjStorageList = this.objStorageList().filter(
|
|
399
|
-
(item) => item.id !== id,
|
|
400
|
-
);
|
|
401
|
-
this.objStorageList.set(newObjStorageList);
|
|
402
|
-
|
|
403
|
-
this.patchFormData(
|
|
404
|
-
this.fieldKey(),
|
|
405
|
-
JSON.stringify(this.objStorageList()),
|
|
406
|
-
);
|
|
407
|
-
// Đồng bộ control value sau khi server xác nhận xóa.
|
|
408
|
-
this._syncControlValue();
|
|
409
|
-
} else {
|
|
410
|
-
console.error(message);
|
|
411
|
-
}
|
|
412
|
-
},
|
|
413
|
-
error: () => {
|
|
414
|
-
console.error("Lỗi trong quá trình xóa tập tin khỏi máy chủ!!");
|
|
415
|
-
// Fake vì hiện api xóa đang có vấn đề.
|
|
416
|
-
const newObjStorageList = this.objStorageList().filter(
|
|
417
|
-
(item) => item.id !== id,
|
|
418
|
-
);
|
|
419
|
-
this.objStorageList.set(newObjStorageList);
|
|
420
|
-
|
|
421
|
-
this.patchFormData(
|
|
422
|
-
this.fieldKey(),
|
|
423
|
-
JSON.stringify(this.objStorageList()),
|
|
424
|
-
);
|
|
425
|
-
// Đồng bộ control value (fake delete thành công).
|
|
426
|
-
this._syncControlValue();
|
|
427
|
-
// Fake vì hiện api xóa đang có vấn đề.
|
|
428
|
-
},
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Xử lý click vào file item:
|
|
434
|
-
* - Không làm gì nếu file đang loading hoặc ở trạng thái error.
|
|
435
|
-
* - Gọi fileClick để xem file nếu đã upload thành công.
|
|
436
|
-
*/
|
|
437
|
-
onFileItemClick(file: MyUploadFile): void {
|
|
438
|
-
if (file.uploadStatus === "loading" || file.uploadStatus === "error")
|
|
439
|
-
return;
|
|
440
|
-
this.fileService.onFileClick(file.objStorage);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
fileClick(objStorage: ObjectStorage): void {
|
|
444
|
-
this.fileService.onFileClick(objStorage);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Hủy toàn bộ batch đang chờ xử lý:
|
|
449
|
-
* - Clear timer batch detection.
|
|
450
|
-
* - Reject tất cả file trong buffer (resolve false).
|
|
451
|
-
* - Reset pendingCount về 0.
|
|
452
|
-
* Gọi khi form bị reset từ bên ngoài.
|
|
453
|
-
*/
|
|
454
|
-
private _clearBatch(): void {
|
|
455
|
-
if (this._batchTimer !== null) {
|
|
456
|
-
clearTimeout(this._batchTimer);
|
|
457
|
-
this._batchTimer = null;
|
|
458
|
-
}
|
|
459
|
-
this._batchBuffer.forEach(({ resolve }) => resolve(false));
|
|
460
|
-
this._batchBuffer = [];
|
|
461
|
-
this.pendingCount.set(0);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Đồng bộ control value với trạng thái thực tế của danh sách file đã upload thành công.
|
|
466
|
-
*
|
|
467
|
-
* Gọi sau mỗi thay đổi về danh sách file (upload xong, xóa file) để đảm bảo:
|
|
468
|
-
* - Không có file nào thành công → propagateValue('') → Validators.required kích hoạt.
|
|
469
|
-
* - Có ít nhất 1 file thành công → propagateValue(JSON string) → validators pass.
|
|
470
|
-
*
|
|
471
|
-
* Validators hiện tại tương thích:
|
|
472
|
-
* - acceptedMimeTypesValidator: bỏ qua nếu value falsy; parse JSON nếu là string.
|
|
473
|
-
* - maxFileSizeInMBValidator: bỏ qua nếu value.size undefined (JSON string).
|
|
474
|
-
*/
|
|
475
|
-
private _syncControlValue(): void {
|
|
476
|
-
const list = this.objStorageList();
|
|
477
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
478
|
-
this.propagateValue((list.length > 0 ? JSON.stringify(list) : "") as any);
|
|
479
|
-
}
|
|
480
|
-
}
|
package/src/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.html
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
@if (isAddOrEdit()) {
|
|
2
|
-
<div class="upload">
|
|
3
|
-
<nz-upload
|
|
4
|
-
[nzDisabled]="
|
|
5
|
-
allFiles().length >= field().maxFileCount ||
|
|
6
|
-
disabledSignal() ||
|
|
7
|
-
uploading()
|
|
8
|
-
"
|
|
9
|
-
[nzShowUploadList]="false"
|
|
10
|
-
[nzMultiple]="false"
|
|
11
|
-
[nzBeforeUpload]="beforeUpload"
|
|
12
|
-
[nzCustomRequest]="customRequest"
|
|
13
|
-
>
|
|
14
|
-
<button nz-button class="btn-upload" [nzLoading]="uploading()">
|
|
15
|
-
Tải lên
|
|
16
|
-
@if (!uploading()) {
|
|
17
|
-
<nz-icon nzType="upload" nzTheme="outline" />
|
|
18
|
-
}
|
|
19
|
-
</button>
|
|
20
|
-
|
|
21
|
-
<span class="ms-2 text-muted fs-12">
|
|
22
|
-
(Đã tải lên {{ allFiles().length }}/{{ field().maxFileCount }}
|
|
23
|
-
hình ảnh)
|
|
24
|
-
</span>
|
|
25
|
-
</nz-upload>
|
|
26
|
-
</div>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
<!-- Custom hiển thị danh sách hình ảnh -->
|
|
30
|
-
@if (allFiles().length > 0) {
|
|
31
|
-
<ng-container *ngTemplateOutlet="imageGroupTpl"></ng-container>
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
<!-- Template custom hiển thị danh sách hình ảnh -->
|
|
35
|
-
<ng-template #imageGroupTpl>
|
|
36
|
-
<nz-image-group>
|
|
37
|
-
<div class="image-list">
|
|
38
|
-
@for (file of allFiles(); track file.objStorage?.id; let i = $index) {
|
|
39
|
-
<div
|
|
40
|
-
class="image-card-container"
|
|
41
|
-
[ngStyle]="{
|
|
42
|
-
width: field().imageCardWidth,
|
|
43
|
-
height: field().imageCardHeight,
|
|
44
|
-
}"
|
|
45
|
-
>
|
|
46
|
-
<div class="image-item">
|
|
47
|
-
<div class="image-item-info">
|
|
48
|
-
<img
|
|
49
|
-
[id]="file.objStorage.id"
|
|
50
|
-
nz-image
|
|
51
|
-
nzSrc="{{ file.previewUrl }}"
|
|
52
|
-
alt="{{ file.objStorage.originalName }}"
|
|
53
|
-
/>
|
|
54
|
-
</div>
|
|
55
|
-
|
|
56
|
-
<div class="image-item-actions">
|
|
57
|
-
<button
|
|
58
|
-
nz-button
|
|
59
|
-
nzType="text"
|
|
60
|
-
nzSize="small"
|
|
61
|
-
(click)="handlePreview(file)"
|
|
62
|
-
>
|
|
63
|
-
<nz-icon nzType="eye" nzTheme="outline" />
|
|
64
|
-
</button>
|
|
65
|
-
|
|
66
|
-
@if (isAddOrEdit()) {
|
|
67
|
-
<button
|
|
68
|
-
nz-button
|
|
69
|
-
nzType="text"
|
|
70
|
-
nzSize="small"
|
|
71
|
-
(click)="handleDelete(file)"
|
|
72
|
-
>
|
|
73
|
-
<nz-icon nzType="delete" nzTheme="outline" />
|
|
74
|
-
</button>
|
|
75
|
-
}
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
</div>
|
|
79
|
-
}
|
|
80
|
-
</div>
|
|
81
|
-
</nz-image-group>
|
|
82
|
-
</ng-template>
|
package/src/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.less
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
.upload {
|
|
2
|
-
margin-bottom: 0.625rem;
|
|
3
|
-
nz-upload {
|
|
4
|
-
.btn-upload {
|
|
5
|
-
margin-right: 0.75rem;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.image-list {
|
|
11
|
-
display: flex;
|
|
12
|
-
gap: 8px;
|
|
13
|
-
flex-wrap: nowrap;
|
|
14
|
-
overflow-x: auto; /* bật scroll ngang */
|
|
15
|
-
//max-width: 20%;
|
|
16
|
-
|
|
17
|
-
.image-card-container {
|
|
18
|
-
display: inline-block;
|
|
19
|
-
margin: 0px 0.5rem 0.5rem 0;
|
|
20
|
-
// width: 108px;
|
|
21
|
-
// height: 108px;
|
|
22
|
-
flex: 0 0 auto; /* item không co giãn, giữ kích thước */
|
|
23
|
-
|
|
24
|
-
.image-item {
|
|
25
|
-
padding: 0.5rem;
|
|
26
|
-
border: 1px solid #cbd5e1;
|
|
27
|
-
height: 100%;
|
|
28
|
-
cursor: pointer;
|
|
29
|
-
position: relative;
|
|
30
|
-
|
|
31
|
-
.image-item-info {
|
|
32
|
-
position: relative;
|
|
33
|
-
height: 100%;
|
|
34
|
-
overflow: hidden;
|
|
35
|
-
|
|
36
|
-
img {
|
|
37
|
-
display: block;
|
|
38
|
-
width: 100%;
|
|
39
|
-
height: 100%;
|
|
40
|
-
object-fit: contain;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.image-item-info::before {
|
|
45
|
-
position: absolute;
|
|
46
|
-
z-index: 1;
|
|
47
|
-
width: 100%;
|
|
48
|
-
height: 100%;
|
|
49
|
-
background-color: rgba(0, 0, 0, 0.5);
|
|
50
|
-
opacity: 0;
|
|
51
|
-
transition: all 0.3s;
|
|
52
|
-
content: ' ';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.image-item-actions {
|
|
56
|
-
position: absolute;
|
|
57
|
-
top: 50%;
|
|
58
|
-
left: 50%;
|
|
59
|
-
z-index: 10;
|
|
60
|
-
white-space: nowrap;
|
|
61
|
-
transform: translate(-50%, -50%);
|
|
62
|
-
transition: all 0.5s;
|
|
63
|
-
opacity: 0;
|
|
64
|
-
> button {
|
|
65
|
-
nz-icon {
|
|
66
|
-
font-size: 1rem !important;
|
|
67
|
-
color: #fdfdfdd9;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.image-item:hover {
|
|
74
|
-
.image-item-info::before,
|
|
75
|
-
.image-item-actions {
|
|
76
|
-
opacity: 1;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
-
|
|
3
|
-
import { MultiImageUploadComponent } from './multi-image-upload.component';
|
|
4
|
-
|
|
5
|
-
describe('MultiImageUploadComponent', () => {
|
|
6
|
-
let component: MultiImageUploadComponent;
|
|
7
|
-
let fixture: ComponentFixture<MultiImageUploadComponent>;
|
|
8
|
-
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
await TestBed.configureTestingModule({
|
|
11
|
-
imports: [MultiImageUploadComponent],
|
|
12
|
-
}).compileComponents();
|
|
13
|
-
|
|
14
|
-
fixture = TestBed.createComponent(MultiImageUploadComponent);
|
|
15
|
-
component = fixture.componentInstance;
|
|
16
|
-
fixture.detectChanges();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should create', () => {
|
|
20
|
-
expect(component).toBeTruthy();
|
|
21
|
-
});
|
|
22
|
-
});
|