@brggroup/share-lib 0.0.1

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.
Files changed (106) hide show
  1. package/README.md +63 -0
  2. package/brggroup-share-lib.d.ts.map +1 -0
  3. package/fesm2022/brggroup-share-lib.mjs +2951 -0
  4. package/fesm2022/brggroup-share-lib.mjs.map +1 -0
  5. package/index.d.ts +6 -0
  6. package/lib/a-translate-key.d.ts +43 -0
  7. package/lib/a-translate-key.d.ts.map +1 -0
  8. package/lib/app-global.d.ts +21 -0
  9. package/lib/app-global.d.ts.map +1 -0
  10. package/lib/app-storeage.d.ts +8 -0
  11. package/lib/app-storeage.d.ts.map +1 -0
  12. package/lib/auth/auth.guard.d.ts +11 -0
  13. package/lib/auth/auth.guard.d.ts.map +1 -0
  14. package/lib/auth/auth.interceptor.d.ts +3 -0
  15. package/lib/auth/auth.interceptor.d.ts.map +1 -0
  16. package/lib/auth/auth.service.d.ts +30 -0
  17. package/lib/auth/auth.service.d.ts.map +1 -0
  18. package/lib/auth/token.storage.d.ts +22 -0
  19. package/lib/auth/token.storage.d.ts.map +1 -0
  20. package/lib/auth/unsaved-changes.guard.d.ts +11 -0
  21. package/lib/auth/unsaved-changes.guard.d.ts.map +1 -0
  22. package/lib/components/base.component.d.ts +36 -0
  23. package/lib/components/base.component.d.ts.map +1 -0
  24. package/lib/components/base.guard-change.d.ts +13 -0
  25. package/lib/components/base.guard-change.d.ts.map +1 -0
  26. package/lib/components/base.overlay.component.d.ts +13 -0
  27. package/lib/components/base.overlay.component.d.ts.map +1 -0
  28. package/lib/components/box.d.ts +9 -0
  29. package/lib/components/box.d.ts.map +1 -0
  30. package/lib/components/breadcrumb/breadcrumb.d.ts +18 -0
  31. package/lib/components/breadcrumb/breadcrumb.d.ts.map +1 -0
  32. package/lib/components/dashboard-widget/animated/animated-digit.component.d.ts +16 -0
  33. package/lib/components/dashboard-widget/animated/animated-digit.component.d.ts.map +1 -0
  34. package/lib/components/dashboard-widget/bar-graph/bar-graph.component.d.ts +15 -0
  35. package/lib/components/dashboard-widget/bar-graph/bar-graph.component.d.ts.map +1 -0
  36. package/lib/components/dashboard-widget/dashcard/dashcard.component.d.ts +10 -0
  37. package/lib/components/dashboard-widget/dashcard/dashcard.component.d.ts.map +1 -0
  38. package/lib/components/dashboard-widget/doughnut-graph/doughnut-graph.component.d.ts +16 -0
  39. package/lib/components/dashboard-widget/doughnut-graph/doughnut-graph.component.d.ts.map +1 -0
  40. package/lib/components/dashboard-widget/line-graph/line-graph.component.d.ts +15 -0
  41. package/lib/components/dashboard-widget/line-graph/line-graph.component.d.ts.map +1 -0
  42. package/lib/components/extend-checkbox/extend-checkbox.d.ts +23 -0
  43. package/lib/components/extend-checkbox/extend-checkbox.d.ts.map +1 -0
  44. package/lib/components/extend-date-picker/extend-date-picker.d.ts +40 -0
  45. package/lib/components/extend-date-picker/extend-date-picker.d.ts.map +1 -0
  46. package/lib/components/extend-input/extend-input.d.ts +45 -0
  47. package/lib/components/extend-input/extend-input.d.ts.map +1 -0
  48. package/lib/components/extend-input-number/extend-input-number.d.ts +40 -0
  49. package/lib/components/extend-input-number/extend-input-number.d.ts.map +1 -0
  50. package/lib/components/extend-select/extend-select.d.ts +44 -0
  51. package/lib/components/extend-select/extend-select.d.ts.map +1 -0
  52. package/lib/components/extend-textarea/extend-textarea.d.ts +32 -0
  53. package/lib/components/extend-textarea/extend-textarea.d.ts.map +1 -0
  54. package/lib/components/height.d.ts +7 -0
  55. package/lib/components/height.d.ts.map +1 -0
  56. package/lib/components/no-permission/no-permission.d.ts +12 -0
  57. package/lib/components/no-permission/no-permission.d.ts.map +1 -0
  58. package/lib/components/pdf-viewer/pdf-viewer.d.ts +11 -0
  59. package/lib/components/pdf-viewer/pdf-viewer.d.ts.map +1 -0
  60. package/lib/components/spinner/spinner.d.ts +14 -0
  61. package/lib/components/spinner/spinner.d.ts.map +1 -0
  62. package/lib/components/width.d.ts +7 -0
  63. package/lib/components/width.d.ts.map +1 -0
  64. package/lib/directive/auto-focus.directive.d.ts +12 -0
  65. package/lib/directive/auto-focus.directive.d.ts.map +1 -0
  66. package/lib/directive/date-input-parser.directive.d.ts +21 -0
  67. package/lib/directive/date-input-parser.directive.d.ts.map +1 -0
  68. package/lib/directive/null-if-empty.directive.d.ts +12 -0
  69. package/lib/directive/null-if-empty.directive.d.ts.map +1 -0
  70. package/lib/directive/number-only.directive.d.ts +19 -0
  71. package/lib/directive/number-only.directive.d.ts.map +1 -0
  72. package/lib/directive/uppercase-each-word.directive.d.ts +21 -0
  73. package/lib/directive/uppercase-each-word.directive.d.ts.map +1 -0
  74. package/lib/directive/uppercase-first-letter.directive.d.ts +19 -0
  75. package/lib/directive/uppercase-first-letter.directive.d.ts.map +1 -0
  76. package/lib/directive/uppercase.directive.d.ts +19 -0
  77. package/lib/directive/uppercase.directive.d.ts.map +1 -0
  78. package/lib/helper/date.helper.d.ts +43 -0
  79. package/lib/helper/date.helper.d.ts.map +1 -0
  80. package/lib/helper/download.helper.d.ts +6 -0
  81. package/lib/helper/download.helper.d.ts.map +1 -0
  82. package/lib/helper/xlsx.helper.d.ts +4 -0
  83. package/lib/helper/xlsx.helper.d.ts.map +1 -0
  84. package/lib/model.d.ts +52 -0
  85. package/lib/model.d.ts.map +1 -0
  86. package/lib/pipe/limit-words.pipe.d.ts +8 -0
  87. package/lib/pipe/limit-words.pipe.d.ts.map +1 -0
  88. package/lib/services/api-service/common.service.d.ts +14 -0
  89. package/lib/services/api-service/common.service.d.ts.map +1 -0
  90. package/lib/services/api-service/http.service.d.ts +12 -0
  91. package/lib/services/api-service/http.service.d.ts.map +1 -0
  92. package/lib/services/custom-modal.service.d.ts +15 -0
  93. package/lib/services/custom-modal.service.d.ts.map +1 -0
  94. package/lib/services/loading.service.d.ts +16 -0
  95. package/lib/services/loading.service.d.ts.map +1 -0
  96. package/lib/services/noti.service.d.ts +16 -0
  97. package/lib/services/noti.service.d.ts.map +1 -0
  98. package/lib/services/router-monitor.service.d.ts +13 -0
  99. package/lib/services/router-monitor.service.d.ts.map +1 -0
  100. package/lib/services/theme.service.d.ts +8 -0
  101. package/lib/services/theme.service.d.ts.map +1 -0
  102. package/lib/services/vsc.service.d.ts +22 -0
  103. package/lib/services/vsc.service.d.ts.map +1 -0
  104. package/package.json +23 -0
  105. package/public-api.d.ts +48 -0
  106. package/public-api.d.ts.map +1 -0
@@ -0,0 +1,2951 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, Injectable, Component, HostListener, ViewContainerRef, Input, ViewChild, EventEmitter, Output, Directive, Optional, Self, HostBinding, forwardRef, Pipe } from '@angular/core';
3
+ import * as i1$3 from '@angular/router';
4
+ import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
5
+ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
6
+ import * as i3 from '@ngx-translate/core';
7
+ import { TranslateService, TranslateModule } from '@ngx-translate/core';
8
+ import { firstValueFrom, BehaviorSubject, of, catchError, EMPTY, throwError, finalize, filter, fromEvent } from 'rxjs';
9
+ import { NzNotificationService } from 'ng-zorro-antd/notification';
10
+ import * as i1 from 'ng-zorro-antd/modal';
11
+ import { NzModalService } from 'ng-zorro-antd/modal';
12
+ import { jwtDecode } from 'jwt-decode';
13
+ import { switchMap, delay, distinctUntilChanged, filter as filter$1, takeUntil } from 'rxjs/operators';
14
+ import * as i2$2 from '@angular/forms';
15
+ import { FormGroup, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
16
+ import * as i1$2 from '@angular/common';
17
+ import { Location, CommonModule } from '@angular/common';
18
+ import { Overlay } from '@angular/cdk/overlay';
19
+ import { TemplatePortal } from '@angular/cdk/portal';
20
+ import * as i1$1 from 'ng-zorro-antd/breadcrumb';
21
+ import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
22
+ import * as i2 from 'ng-zorro-antd/icon';
23
+ import { NzIconModule } from 'ng-zorro-antd/icon';
24
+ import { Chart, registerables } from 'chart.js';
25
+ import * as i4 from 'ng-zorro-antd/grid';
26
+ import { NzGridModule } from 'ng-zorro-antd/grid';
27
+ import * as i2$1 from 'ng-zorro-antd/checkbox';
28
+ import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
29
+ import * as i5 from 'ng-zorro-antd/form';
30
+ import { NzFormModule } from 'ng-zorro-antd/form';
31
+ import * as i5$1 from 'ng-zorro-antd/date-picker';
32
+ import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
33
+ import * as i6 from 'ng-zorro-antd/input-number';
34
+ import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
35
+ import * as i6$1 from 'ng-zorro-antd/input';
36
+ import { NzInputModule } from 'ng-zorro-antd/input';
37
+ import * as i6$2 from 'ng-zorro-antd/select';
38
+ import { NzSelectModule } from 'ng-zorro-antd/select';
39
+ import * as i1$4 from 'ngx-extended-pdf-viewer';
40
+ import { NgxExtendedPdfViewerModule } from 'ngx-extended-pdf-viewer';
41
+ import { trigger, transition, animate, style } from '@angular/animations';
42
+ import * as i2$3 from 'ng-zorro-antd/spin';
43
+ import { NzSpinModule } from 'ng-zorro-antd/spin';
44
+ import * as XLSX from 'xlsx';
45
+
46
+ var TranslateKey;
47
+ (function (TranslateKey) {
48
+ TranslateKey["ACTION"] = "ACTION";
49
+ TranslateKey["ADD"] = "ADD";
50
+ TranslateKey["AGREE"] = "AGREE";
51
+ TranslateKey["BACK"] = "BACK";
52
+ TranslateKey["CANCEL"] = "CANCEL";
53
+ TranslateKey["CLOSE"] = "CLOSE";
54
+ TranslateKey["CONFIRM"] = "CONFIRM";
55
+ TranslateKey["CONFIRM_DELETE"] = "CONFIRM_DELETE";
56
+ TranslateKey["COMPLETE"] = "COMPLETE";
57
+ TranslateKey["DELETE"] = "DELETE";
58
+ TranslateKey["DELETE_SUCCESS"] = "DELETE_SUCCESS";
59
+ TranslateKey["EDIT"] = "EDIT";
60
+ TranslateKey["ERROR"] = "ERROR";
61
+ TranslateKey["EXPORT"] = "EXPORT";
62
+ TranslateKey["HIDDEN"] = "HIDDEN";
63
+ TranslateKey["IMPORT"] = "IMPORT";
64
+ TranslateKey["INFO"] = "INFO";
65
+ TranslateKey["LOGIN"] = "LOGIN";
66
+ TranslateKey["LOGOUT"] = "LOGOUT";
67
+ TranslateKey["NO_CONNECT_TO_SERVER"] = "NO_CONNECT_TO_SERVER";
68
+ TranslateKey["OK"] = "OK";
69
+ TranslateKey["PASSWORD"] = "PASSWORD";
70
+ TranslateKey["REQUIRED"] = "REQUIRED";
71
+ TranslateKey["REQUIRED_FIELD"] = "REQUIRED_FIELD";
72
+ TranslateKey["REFEESH"] = "REFEESH";
73
+ TranslateKey["RESET"] = "RESET";
74
+ TranslateKey["RESET_PASSWORD"] = "RESET_PASSWORD";
75
+ TranslateKey["SAVE"] = "SAVE";
76
+ TranslateKey["SEARCH"] = "SEARCH";
77
+ TranslateKey["SHOW"] = "SHOW";
78
+ TranslateKey["SUCCESS"] = "SUCCESS";
79
+ TranslateKey["SAVE_SUCCESS"] = "SAVE_SUCCESS";
80
+ TranslateKey["SETTING"] = "SETTING";
81
+ TranslateKey["PROFILE"] = "PROFILE";
82
+ TranslateKey["USERNAME"] = "USERNAME";
83
+ TranslateKey["UPDATE"] = "UPDATE";
84
+ TranslateKey["WARNING"] = "WARNING";
85
+ TranslateKey["YES"] = "YES";
86
+ TranslateKey["DOWNLOAD_TEMPLATE"] = "DOWNLOAD_TEMPLATE";
87
+ TranslateKey["WARNING_CHECK_DATA"] = "WARNING_CHECK_DATA";
88
+ })(TranslateKey || (TranslateKey = {}));
89
+
90
+ class AppGlobals {
91
+ static apiEndpoint;
92
+ static versionCheck;
93
+ static MENU_TYPE = 'toolbar-menu';
94
+ static pageSizeOptions = [10, 20, 50, 100];
95
+ static filterSet = {};
96
+ static selectedIdSet = {};
97
+ static clearFillter() {
98
+ this.filterSet = {};
99
+ }
100
+ static getFilter(key) {
101
+ return this.filterSet[key];
102
+ }
103
+ static setFilter(key, filter) {
104
+ this.filterSet[key] = filter;
105
+ }
106
+ static getSelectedId(key) {
107
+ return this.selectedIdSet[key];
108
+ }
109
+ static setSelectedId(key, value) {
110
+ this.selectedIdSet[key] = value;
111
+ }
112
+ static setLang(lang) {
113
+ localStorage.setItem('LANGUAGE', lang);
114
+ }
115
+ static getLang() {
116
+ if (!localStorage.getItem('LANGUAGE')) {
117
+ localStorage.setItem('LANGUAGE', 'vn');
118
+ }
119
+ return localStorage.getItem('LANGUAGE') || '';
120
+ }
121
+ static getOrgId() {
122
+ return localStorage.getItem('orgid');
123
+ }
124
+ static getOrgCode() {
125
+ return localStorage.getItem('orgcode');
126
+ }
127
+ static getOrgName() {
128
+ return localStorage.getItem('orgname');
129
+ }
130
+ static getUserName() {
131
+ return localStorage.getItem('username');
132
+ }
133
+ static getUserFullName() {
134
+ return localStorage.getItem('fullname');
135
+ }
136
+ }
137
+
138
+ class AppStorage {
139
+ static get tokenStorage() {
140
+ return localStorage;
141
+ // return sessionStorage;
142
+ }
143
+ static get localStoreage() {
144
+ return localStorage;
145
+ }
146
+ static get sessionStoreage() {
147
+ return sessionStorage;
148
+ }
149
+ static getLang() {
150
+ return AppStorage.localStoreage.getItem('LANGUAGE') || 'vn';
151
+ }
152
+ static setLang(lang) {
153
+ AppStorage.localStoreage.setItem('LANGUAGE', lang || 'vn');
154
+ }
155
+ }
156
+
157
+ class HTTPService {
158
+ httpClient = inject(HttpClient);
159
+ get(url, noLoadingMark) {
160
+ const options = {
161
+ headers: new HttpHeaders({
162
+ 'Content-Type': 'application/json; charset=utf-8',
163
+ 'no-loading-mark': noLoadingMark ? '1' : '0',
164
+ }),
165
+ };
166
+ return firstValueFrom(this.httpClient.get(url, options));
167
+ }
168
+ getParams(url, params, noLoadingMark) {
169
+ const options = {
170
+ headers: new HttpHeaders({
171
+ 'Content-Type': 'application/json; charset=utf-8',
172
+ 'no-loading-mark': noLoadingMark ? '1' : '0',
173
+ }),
174
+ params: params,
175
+ };
176
+ return firstValueFrom(this.httpClient.get(url, options));
177
+ }
178
+ post(url, noLoadingMark) {
179
+ const options = {
180
+ headers: new HttpHeaders({
181
+ 'Content-Type': 'application/json; charset=utf-8',
182
+ 'no-loading-mark': noLoadingMark ? '1' : '0',
183
+ }),
184
+ };
185
+ return firstValueFrom(this.httpClient.post(url, null, options));
186
+ }
187
+ postParams(url, params, noLoadingMark) {
188
+ const options = {
189
+ headers: new HttpHeaders({
190
+ 'Content-Type': 'application/json; charset=utf-8',
191
+ 'no-loading-mark': noLoadingMark ? '1' : '0',
192
+ }),
193
+ params: params,
194
+ };
195
+ return firstValueFrom(this.httpClient.post(url, null, options));
196
+ }
197
+ postData(url, body, noLoadingMark) {
198
+ const options = {
199
+ headers: new HttpHeaders({
200
+ 'Content-Type': 'application/json; charset=utf-8',
201
+ 'no-loading-mark': noLoadingMark ? '1' : '0',
202
+ }),
203
+ };
204
+ return firstValueFrom(this.httpClient.post(url, body, options));
205
+ }
206
+ postDataWithParams(url, body, params, noLoadingMark) {
207
+ const options = {
208
+ headers: new HttpHeaders({
209
+ 'Content-Type': 'application/json; charset=utf-8',
210
+ 'no-loading-mark': noLoadingMark ? '1' : '0',
211
+ }),
212
+ params: params,
213
+ };
214
+ return firstValueFrom(this.httpClient.post(url, body, options));
215
+ }
216
+ }
217
+
218
+ function escapeHtml(str) {
219
+ return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
220
+ }
221
+ class NotiService {
222
+ modal = inject(NzModalService);
223
+ notification = inject(NzNotificationService);
224
+ translate = inject(TranslateService);
225
+ async success(title, content = '', showPopup = false) {
226
+ if (showPopup) {
227
+ return new Promise((resolve) => {
228
+ const modalRef = this.modal.success({
229
+ nzTitle: title ?? this.translate.instant(TranslateKey.SUCCESS),
230
+ nzContent: content,
231
+ nzOnOk: () => resolve(),
232
+ });
233
+ });
234
+ }
235
+ else {
236
+ const notiRef = this.notification.success(title ?? this.translate.instant(TranslateKey.SUCCESS), content);
237
+ if (notiRef?.onClose) {
238
+ await firstValueFrom(notiRef.onClose);
239
+ }
240
+ }
241
+ }
242
+ async warning(title, content = '', showPopup = false) {
243
+ if (showPopup) {
244
+ return new Promise((resolve) => {
245
+ const modalRef = this.modal.warning({
246
+ nzTitle: title,
247
+ nzContent: content,
248
+ nzOnOk: () => resolve(),
249
+ });
250
+ });
251
+ }
252
+ else {
253
+ const notiRef = this.notification.warning(title, content);
254
+ if (notiRef?.onClose) {
255
+ await firstValueFrom(notiRef.onClose);
256
+ }
257
+ }
258
+ }
259
+ async error(title, content = '', showPopup = false) {
260
+ if (showPopup) {
261
+ return new Promise((resolve) => {
262
+ const modalRef = this.modal.error({
263
+ nzTitle: title,
264
+ nzContent: content,
265
+ nzOnOk: () => resolve(),
266
+ });
267
+ });
268
+ }
269
+ else {
270
+ const notiRef = this.notification.error(title, content);
271
+ if (notiRef?.onClose) {
272
+ await firstValueFrom(notiRef.onClose);
273
+ }
274
+ }
275
+ }
276
+ handleError(err) {
277
+ if (err?.status == 0) {
278
+ // this.notification.error('', this.translate.instant('NO_CONNECT_TO_SERVER'), { nzDuration: 0 });
279
+ this.modal.error({
280
+ nzTitle: 'Lỗi phát sinh',
281
+ nzContent: this.translate.instant('NO_CONNECT_TO_SERVER'),
282
+ nzWidth: '40vw',
283
+ nzOkText: 'Đóng',
284
+ });
285
+ return;
286
+ }
287
+ let _data = null;
288
+ if (err?.error instanceof ArrayBuffer) {
289
+ const message = new TextDecoder('utf-8').decode(new Uint8Array(err.error));
290
+ try {
291
+ _data = JSON.parse(message);
292
+ }
293
+ catch (error) { }
294
+ }
295
+ else if (err?.error instanceof Blob) {
296
+ const reader = new FileReader();
297
+ reader.onload = () => {
298
+ try {
299
+ const text = reader.result;
300
+ _data = JSON.parse(text);
301
+ this.handleError(_data);
302
+ }
303
+ catch (e) {
304
+ // this.notification.error('', this.translate.instant('UNKNOWN_ERROR'), { nzDuration: 0 });
305
+ this.modal.error({
306
+ nzTitle: 'Lỗi phát sinh',
307
+ nzContent: this.translate.instant('UNKNOWN_ERROR'),
308
+ nzWidth: '40vw',
309
+ nzOkText: 'Đóng',
310
+ });
311
+ }
312
+ };
313
+ reader.onerror = () => {
314
+ // this.notification.error('', this.translate.instant('UNKNOWN_ERROR'), { nzDuration: 0 });
315
+ this.modal.error({
316
+ nzTitle: 'Lỗi phát sinh',
317
+ nzContent: this.translate.instant('UNKNOWN_ERROR'),
318
+ nzWidth: '40vw',
319
+ nzOkText: 'Đóng',
320
+ });
321
+ };
322
+ reader.readAsText(err.error);
323
+ return;
324
+ }
325
+ else if (err?.error && typeof err.error === 'object') {
326
+ _data = err.error;
327
+ }
328
+ else {
329
+ _data = err;
330
+ }
331
+ let errorMsg = err?.message || 'An unexpected error occurred.';
332
+ if (err?.name == 'EmptyError' && err?.message == 'no elements in sequence') {
333
+ return;
334
+ }
335
+ if (_data?.ErrorMessage) {
336
+ let hasMsgTag = false;
337
+ let isMatchFirstMsg = false;
338
+ let isMatch = _data.ErrorMessage?.match(/System.Data.SqlClient.SqlException \(0x80131904\): <msg>(.*?)<\/msg>/);
339
+ isMatchFirstMsg = isMatch ? true : false;
340
+ if (isMatchFirstMsg) {
341
+ const matches = [..._data.ErrorMessage?.matchAll(/<msg>(.*?)<\/msg>/g)];
342
+ const messages = matches.map((m) => m[1]);
343
+ if (messages.length > 0) {
344
+ errorMsg = messages.join('\n');
345
+ hasMsgTag = true;
346
+ }
347
+ else {
348
+ errorMsg = _data.ErrorMessage;
349
+ }
350
+ }
351
+ else {
352
+ errorMsg = _data.ErrorMessage;
353
+ }
354
+ }
355
+ const modalRef = this.modal.error({
356
+ nzTitle: 'Lỗi phát sinh',
357
+ nzContent: errorMsg,
358
+ nzWidth: '40vw',
359
+ nzClosable: false,
360
+ nzOkText: 'Đóng',
361
+ nzCancelText: 'Chi tiết',
362
+ nzOnCancel: () => {
363
+ modalRef.destroy();
364
+ this.modal.error({
365
+ nzTitle: 'Chi tiết lỗi',
366
+ nzContent: escapeHtml(JSON.stringify(_data, null, 2)),
367
+ nzWidth: '60vw',
368
+ nzDraggable: true,
369
+ nzCentered: true,
370
+ nzOkText: 'Đóng',
371
+ });
372
+ },
373
+ });
374
+ }
375
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NotiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
376
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NotiService, providedIn: 'root' });
377
+ }
378
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NotiService, decorators: [{
379
+ type: Injectable,
380
+ args: [{
381
+ providedIn: 'root',
382
+ }]
383
+ }] });
384
+
385
+ var ENUM_ResponseType;
386
+ (function (ENUM_ResponseType) {
387
+ ENUM_ResponseType["ARRAYBUFFER"] = "arraybuffer";
388
+ ENUM_ResponseType["BLOB"] = "blob";
389
+ })(ENUM_ResponseType || (ENUM_ResponseType = {}));
390
+ class CommonService extends HTTPService {
391
+ ESP(obj) {
392
+ const params = new HttpParams().append('SPN', obj.SPN);
393
+ return this.postDataWithParams(AppGlobals.apiEndpoint + '/api/Common/ESP', obj, params);
394
+ }
395
+ ExportExcel(data) {
396
+ return firstValueFrom(this.httpClient.post(AppGlobals.apiEndpoint + '/api/Common/ExportExcel', data, {
397
+ responseType: ENUM_ResponseType.BLOB,
398
+ observe: 'response',
399
+ }));
400
+ }
401
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: CommonService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
402
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: CommonService, providedIn: 'root' });
403
+ }
404
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: CommonService, decorators: [{
405
+ type: Injectable,
406
+ args: [{ providedIn: 'root' }]
407
+ }] });
408
+
409
+ class TokenStorage {
410
+ static JWT_TOKEN = 'JWT_TOKEN';
411
+ static USER_NAME = 'username';
412
+ static FULL_NAME = 'fullname';
413
+ static USER_MENU = 'usermenu';
414
+ static ORG_ID = 'orgid';
415
+ static ORG_CODE = 'orgcode';
416
+ static ORG_NAME = 'orgname';
417
+ static saveToken(tokenRes) {
418
+ AppStorage.tokenStorage.setItem(this.JWT_TOKEN, tokenRes.Data.Token);
419
+ const userInfo = jwtDecode(tokenRes.Data.Token);
420
+ AppStorage.tokenStorage.setItem(this.USER_NAME, userInfo[this.USER_NAME]);
421
+ AppStorage.tokenStorage.setItem(this.FULL_NAME, userInfo[this.FULL_NAME]);
422
+ AppStorage.tokenStorage.setItem(this.ORG_ID, userInfo[this.ORG_ID]);
423
+ AppStorage.tokenStorage.setItem(this.ORG_CODE, userInfo[this.ORG_CODE]);
424
+ AppStorage.tokenStorage.setItem(this.ORG_NAME, userInfo[this.ORG_NAME]);
425
+ }
426
+ static saveUserMenu(menus) {
427
+ AppStorage.tokenStorage.setItem(this.USER_MENU, JSON.stringify(menus));
428
+ }
429
+ static getUserMenu() {
430
+ return JSON.parse(AppStorage.tokenStorage.getItem(this.USER_MENU) || '[]');
431
+ }
432
+ static getUsername() {
433
+ return AppStorage.tokenStorage.getItem(this.USER_NAME);
434
+ }
435
+ static getUserFullname() {
436
+ return AppStorage.tokenStorage.getItem(this.FULL_NAME);
437
+ }
438
+ static getOrgId() {
439
+ return AppStorage.tokenStorage.getItem(this.ORG_ID);
440
+ }
441
+ static getOrgCode() {
442
+ return AppStorage.tokenStorage.getItem(this.ORG_CODE);
443
+ }
444
+ static getOrgName() {
445
+ return AppStorage.tokenStorage.getItem(this.ORG_NAME);
446
+ }
447
+ static getToken() {
448
+ return AppStorage.tokenStorage.getItem(this.JWT_TOKEN);
449
+ }
450
+ static isLoggedIn() {
451
+ return AppStorage.tokenStorage.getItem(this.JWT_TOKEN) != null;
452
+ }
453
+ static clearToken() {
454
+ console.log('-- clearToken --');
455
+ AppStorage.tokenStorage.removeItem(this.JWT_TOKEN);
456
+ AppStorage.tokenStorage.removeItem(this.USER_NAME);
457
+ AppStorage.tokenStorage.removeItem(this.FULL_NAME);
458
+ AppStorage.tokenStorage.removeItem(this.USER_MENU);
459
+ AppStorage.tokenStorage.removeItem(this.ORG_ID);
460
+ AppStorage.tokenStorage.removeItem(this.ORG_CODE);
461
+ AppStorage.tokenStorage.removeItem(this.ORG_NAME);
462
+ }
463
+ }
464
+
465
+ const URLs = {
466
+ login: '/api/Auth/Login',
467
+ pingAuth: '/api/Auth/PingAuth',
468
+ changePassword: '/api/Auth/ChangePassword',
469
+ setPass: '/api/Auth/SetPass',
470
+ };
471
+ class AuthService extends HTTPService {
472
+ notiService = inject(NotiService);
473
+ commonService = inject(CommonService);
474
+ router = inject(Router);
475
+ translate = inject(TranslateService);
476
+ async pingAuth() {
477
+ try {
478
+ const res = await this.post(AppGlobals.apiEndpoint + URLs.pingAuth);
479
+ return res?.IsSuccess;
480
+ }
481
+ catch {
482
+ return false;
483
+ }
484
+ }
485
+ async signIn(username, password, orgid, returnUrl) {
486
+ try {
487
+ const body = {
488
+ UserName: username,
489
+ Password: password,
490
+ OrgId: orgid,
491
+ };
492
+ const res = await this.sendSignIn(body);
493
+ if (!res.IsSuccess) {
494
+ this.notiService.error(this.translate.instant(res.ErrorMessage));
495
+ return false;
496
+ }
497
+ this.notiService.success('Đăng nhập thành công');
498
+ TokenStorage.saveToken(res);
499
+ if (returnUrl) {
500
+ this.router.navigateByUrl(returnUrl);
501
+ }
502
+ }
503
+ catch (err) {
504
+ this.notiService.handleError(err);
505
+ return false;
506
+ }
507
+ return true;
508
+ }
509
+ async sendSignIn(body) {
510
+ return firstValueFrom(this.httpClient.post(AppGlobals.apiEndpoint + URLs.login, body, {
511
+ headers: new HttpHeaders().set('Content-Type', 'application/json'),
512
+ }));
513
+ }
514
+ signOut() {
515
+ TokenStorage.clearToken();
516
+ this.router.navigate(['/login']);
517
+ }
518
+ getUserMenu() {
519
+ let data = {
520
+ SPN: `App_User_getUserMenu`,
521
+ };
522
+ return this.commonService.ESP(data);
523
+ }
524
+ async checkUserMenu(url) {
525
+ try {
526
+ const ret = await this.commonService.ESP({
527
+ SPN: `App_User_checkUserMenu`,
528
+ Params: [url],
529
+ });
530
+ return ret.IsSuccess && ret.Data == '1';
531
+ }
532
+ catch (error) {
533
+ this.notiService.handleError(error);
534
+ return true;
535
+ }
536
+ }
537
+ changePassword(data) {
538
+ return this.postData(AppGlobals.apiEndpoint + URLs.changePassword, data);
539
+ }
540
+ setPass(data) {
541
+ return this.postData(AppGlobals.apiEndpoint + URLs.setPass, data);
542
+ }
543
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
544
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthService, providedIn: 'root' });
545
+ }
546
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthService, decorators: [{
547
+ type: Injectable,
548
+ args: [{
549
+ providedIn: 'root',
550
+ }]
551
+ }] });
552
+
553
+ class AuthGuard {
554
+ router = inject(Router);
555
+ authService = inject(AuthService);
556
+ async canActivate(route, state) {
557
+ // return true;
558
+ if (await this.authService.pingAuth()) {
559
+ return true;
560
+ }
561
+ TokenStorage.clearToken();
562
+ if (state.url != '/') {
563
+ this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
564
+ }
565
+ else {
566
+ this.router.navigate(['/login']);
567
+ }
568
+ return false;
569
+ }
570
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
571
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthGuard, providedIn: 'root' });
572
+ }
573
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthGuard, decorators: [{
574
+ type: Injectable,
575
+ args: [{
576
+ providedIn: 'root',
577
+ }]
578
+ }] });
579
+
580
+ class LoadingService {
581
+ static loadingStack = [];
582
+ loadingSubject = new BehaviorSubject(false);
583
+ update() {
584
+ const isLoading = LoadingService.loadingStack.length > 0;
585
+ this.loadingSubject.next(isLoading);
586
+ }
587
+ loadingUp() {
588
+ LoadingService.loadingStack.push(1);
589
+ this.update();
590
+ }
591
+ loadingDown() {
592
+ LoadingService.loadingStack.pop();
593
+ this.update();
594
+ }
595
+ /** Trả về observable loading có delay khi bật để tránh chớp nháy */
596
+ get loading$() {
597
+ return this.loadingSubject.asObservable().pipe(switchMap((loading) => {
598
+ return loading
599
+ ? of(true).pipe(delay(200)) // delay khi bật
600
+ : of(false); // tắt thì không delay
601
+ }), distinctUntilChanged());
602
+ }
603
+ /** Nếu chỉ cần giá trị hiện tại boolean (ít dùng hơn) */
604
+ get isLoading() {
605
+ return LoadingService.loadingStack.length > 0;
606
+ }
607
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: LoadingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
608
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: LoadingService, providedIn: 'root' });
609
+ }
610
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: LoadingService, decorators: [{
611
+ type: Injectable,
612
+ args: [{
613
+ providedIn: 'root',
614
+ }]
615
+ }] });
616
+
617
+ let initialReturnUrl = null;
618
+ function authInterceptor(req, next) {
619
+ const router = inject(Router);
620
+ const loadingService = inject(LoadingService);
621
+ const modalService = inject(NzModalService);
622
+ const notiService = inject(NotiService);
623
+ const translate = inject(TranslateService);
624
+ const authToken = TokenStorage.getToken();
625
+ loadingService.loadingUp();
626
+ if (!(req.body instanceof FormData)) {
627
+ const newBody = convertDatesInBody(req.body);
628
+ if (req.body !== newBody) {
629
+ req = req.clone({ body: newBody });
630
+ }
631
+ }
632
+ if (authToken) {
633
+ req = req.clone({
634
+ setHeaders: { Authorization: `Bearer ${authToken}` },
635
+ });
636
+ }
637
+ return next(req).pipe(catchError((error) => {
638
+ if (error.status === 401) {
639
+ modalService.closeAll();
640
+ notiService.error(translate.instant('EXPIRED_TOKEN'));
641
+ const currentUrl = router.routerState.snapshot.url;
642
+ if (!initialReturnUrl && !currentUrl.startsWith('/login')) {
643
+ initialReturnUrl = currentUrl;
644
+ }
645
+ router.navigate(['/login'], {
646
+ queryParams: { returnUrl: initialReturnUrl || '/' },
647
+ });
648
+ return EMPTY;
649
+ }
650
+ return throwError(() => error);
651
+ }), finalize(() => {
652
+ loadingService.loadingDown();
653
+ }));
654
+ }
655
+ function convertDatesInBody(obj) {
656
+ if (obj instanceof Date) {
657
+ return formatDate(obj);
658
+ }
659
+ if (Array.isArray(obj)) {
660
+ return obj.map(convertDatesInBody);
661
+ }
662
+ if (typeof obj === 'object' && obj !== null) {
663
+ const newObj = {};
664
+ for (const key of Object.keys(obj)) {
665
+ const value = obj[key];
666
+ if (value instanceof Date) {
667
+ newObj[key] = formatDate(value);
668
+ }
669
+ else if (typeof value === 'string' && isIsoDate(value)) {
670
+ newObj[key] = formatDate(new Date(value));
671
+ }
672
+ else if (typeof value === 'object') {
673
+ newObj[key] = convertDatesInBody(value);
674
+ }
675
+ else {
676
+ newObj[key] = value;
677
+ }
678
+ }
679
+ return newObj;
680
+ }
681
+ return obj;
682
+ }
683
+ function isIsoDate(str) {
684
+ // ISO string with optional time and timezone
685
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[\+\-]\d{2}:\d{2})?$/.test(str);
686
+ }
687
+ function formatDate(date) {
688
+ const pad = (n) => n.toString().padStart(2, '0');
689
+ return (`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
690
+ `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`);
691
+ }
692
+
693
+ class UnsavedChangesGuard {
694
+ canDeactivate(component) {
695
+ return component.canDeactivate ? component.canDeactivate() : true;
696
+ }
697
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UnsavedChangesGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
698
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UnsavedChangesGuard, providedIn: 'root' });
699
+ }
700
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UnsavedChangesGuard, decorators: [{
701
+ type: Injectable,
702
+ args: [{
703
+ providedIn: 'root',
704
+ }]
705
+ }] });
706
+
707
+ class CustomModalService {
708
+ modal;
709
+ constructor(modal) {
710
+ this.modal = modal;
711
+ }
712
+ create(options) {
713
+ const defaultOptions = {
714
+ nzMaskClosable: false,
715
+ nzCentered: true,
716
+ nzBodyStyle: {
717
+ 'max-height': 'calc(100vh - 180px)',
718
+ overflow: 'auto',
719
+ },
720
+ };
721
+ const mergedOptions = {
722
+ ...defaultOptions,
723
+ ...options,
724
+ nzStyle: {
725
+ ...defaultOptions.nzStyle,
726
+ ...options.nzStyle,
727
+ },
728
+ };
729
+ return this.modal.create(mergedOptions);
730
+ }
731
+ confirm(options) {
732
+ return this.modal.confirm(options);
733
+ }
734
+ info(options) {
735
+ return this.modal.info(options);
736
+ }
737
+ success(options) {
738
+ return this.modal.success(options);
739
+ }
740
+ warning(options) {
741
+ return this.modal.warning(options);
742
+ }
743
+ error(options) {
744
+ return this.modal.error(options);
745
+ }
746
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: CustomModalService, deps: [{ token: i1.NzModalService }], target: i0.ɵɵFactoryTarget.Injectable });
747
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: CustomModalService, providedIn: 'root' });
748
+ }
749
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: CustomModalService, decorators: [{
750
+ type: Injectable,
751
+ args: [{ providedIn: 'root' }]
752
+ }], ctorParameters: () => [{ type: i1.NzModalService }] });
753
+
754
+ class BaseComponent {
755
+ AppGlobals = AppGlobals;
756
+ TranslateKey = TranslateKey;
757
+ route = inject(ActivatedRoute);
758
+ router = inject(Router);
759
+ location = inject(Location);
760
+ notiService = inject(NotiService);
761
+ translate = inject(TranslateService);
762
+ modal = inject(CustomModalService);
763
+ routeSub;
764
+ onRouteChange(callback) {
765
+ this.routeSub = this.router.events
766
+ .pipe(filter((e) => e instanceof NavigationEnd))
767
+ .subscribe((e) => {
768
+ callback(e.urlAfterRedirects);
769
+ });
770
+ }
771
+ unSubRouteChange() {
772
+ this.routeSub?.unsubscribe();
773
+ }
774
+ goback() {
775
+ this.location.back();
776
+ }
777
+ goto(url) {
778
+ if (url) {
779
+ if (url.startsWith('/')) {
780
+ this.router.navigateByUrl(url);
781
+ }
782
+ else {
783
+ this.router.navigate([url], { relativeTo: this.route });
784
+ }
785
+ }
786
+ }
787
+ getUrlParam(paramName) {
788
+ const paramValue = this.route.snapshot.params[paramName];
789
+ // bằng 0 thì trả về null vì chuyển primary key từ bigint sang string, code cũ đang truyền vào 0
790
+ if (paramValue == '0' || paramValue == 'new' || paramValue == 'them-moi') {
791
+ return null;
792
+ }
793
+ return paramValue;
794
+ }
795
+ getUrlQueryParam(queryParamName) {
796
+ const queryParamValue = this.route.snapshot.queryParamMap.get(queryParamName);
797
+ return queryParamValue;
798
+ }
799
+ getUrlData(key) {
800
+ return this.route.snapshot.data[key];
801
+ }
802
+ getCurrentUrl() {
803
+ return this.router.url;
804
+ }
805
+ handleError(err) {
806
+ this.notiService.handleError(err);
807
+ }
808
+ touchControls(formData) {
809
+ Object.values(formData.controls).forEach((control) => {
810
+ if (control.invalid) {
811
+ control.markAsDirty();
812
+ control.updateValueAndValidity({ onlySelf: true });
813
+ }
814
+ });
815
+ }
816
+ logFormErrors(form, parentKey = '') {
817
+ Object.keys(form.controls).forEach((key) => {
818
+ const control = form.get(key);
819
+ const fieldPath = parentKey ? `${parentKey}.${key}` : key;
820
+ if (control instanceof FormGroup) {
821
+ this.logFormErrors(control, fieldPath);
822
+ }
823
+ else {
824
+ if (control?.errors) {
825
+ console.log(`Control: ${fieldPath}`, control.errors);
826
+ }
827
+ }
828
+ });
829
+ }
830
+ confirm(title, content = '') {
831
+ return new Promise((resolve) => {
832
+ this.modal.confirm({
833
+ // nzCentered: true,
834
+ nzTitle: title,
835
+ nzContent: content,
836
+ nzOkText: this.translate.instant(this.TranslateKey.AGREE),
837
+ nzOkType: 'primary',
838
+ nzOkDanger: true,
839
+ nzClosable: false,
840
+ nzOnOk: () => resolve(true),
841
+ nzAutofocus: 'ok',
842
+ nzCancelText: this.translate.instant(this.TranslateKey.CANCEL),
843
+ nzOnCancel: () => resolve(false),
844
+ });
845
+ });
846
+ }
847
+ backToTop() {
848
+ // go to top
849
+ window.scrollTo({
850
+ top: 0,
851
+ behavior: 'smooth',
852
+ });
853
+ const content = document.querySelector('nz-content');
854
+ if (content) {
855
+ content.scrollTo({
856
+ top: 0,
857
+ behavior: 'smooth',
858
+ });
859
+ }
860
+ }
861
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: BaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
862
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: BaseComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '', isInline: true });
863
+ }
864
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: BaseComponent, decorators: [{
865
+ type: Component,
866
+ args: [{ template: '' }]
867
+ }] });
868
+
869
+ class BaseGuardChangeComponent extends BaseComponent {
870
+ formData;
871
+ unloadNotification($event) {
872
+ if (this.formData?.dirty) {
873
+ $event.preventDefault();
874
+ $event.returnValue = true; // Chrome requires this line
875
+ }
876
+ }
877
+ async canDeactivate() {
878
+ if (this.formData?.dirty) {
879
+ return await this.confirm('Dữ liệu chưa được lưu. Bạn có chắc chắn muốn rời khỏi trang?');
880
+ }
881
+ return true;
882
+ }
883
+ clearChange() {
884
+ // bỏ dirty để không hỏi khi rời trang
885
+ this.formData?.markAsPristine();
886
+ this.formData?.markAsUntouched();
887
+ this.formData?.updateValueAndValidity();
888
+ }
889
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: BaseGuardChangeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
890
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: BaseGuardChangeComponent, isStandalone: true, selector: "ng-component", host: { listeners: { "window:beforeunload": "unloadNotification($event)" } }, usesInheritance: true, ngImport: i0, template: '', isInline: true });
891
+ }
892
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: BaseGuardChangeComponent, decorators: [{
893
+ type: Component,
894
+ args: [{
895
+ template: '',
896
+ }]
897
+ }], propDecorators: { unloadNotification: [{
898
+ type: HostListener,
899
+ args: ['window:beforeunload', ['$event']]
900
+ }] } });
901
+
902
+ class BaseOverlayComponent extends BaseComponent {
903
+ // custom dropdow
904
+ inputWidth = 0;
905
+ triggerSpan = 500;
906
+ overlayRef;
907
+ overlay = inject(Overlay);
908
+ vcr = inject(ViewContainerRef);
909
+ openOverlay(originEl, target, width = 0) {
910
+ const origin = originEl?.elementRef?.nativeElement ?? originEl?.nativeElement ?? originEl;
911
+ this.updateInputWidth(origin);
912
+ if (this.overlayRef) {
913
+ this.overlayRef.detach(); // Đóng nếu đã mở
914
+ }
915
+ width = width > origin.offsetWidth ? width : origin.offsetWidth; // 👈 Lấy chiều rộng của input
916
+ const positionStrategy = this.overlay
917
+ .position()
918
+ .flexibleConnectedTo(origin)
919
+ .withPositions([
920
+ {
921
+ originX: 'start',
922
+ originY: 'bottom',
923
+ overlayX: 'start',
924
+ overlayY: 'top',
925
+ offsetY: 5,
926
+ },
927
+ {
928
+ originX: 'start',
929
+ originY: 'top',
930
+ overlayX: 'start',
931
+ overlayY: 'bottom',
932
+ offsetY: -5,
933
+ },
934
+ ])
935
+ .withDefaultOffsetY(5);
936
+ this.overlayRef = this.overlay.create({
937
+ positionStrategy,
938
+ hasBackdrop: false,
939
+ backdropClass: 'cdk-overlay-transparent-backdrop',
940
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
941
+ width, // 👈 Gán chiều rộng cho overlay
942
+ });
943
+ this.overlayRef.backdropClick().subscribe(() => {
944
+ this.overlayRef.detach();
945
+ });
946
+ const portal = new TemplatePortal(target, this.vcr);
947
+ this.overlayRef.attach(portal);
948
+ const overlayElement = this.overlayRef.overlayElement;
949
+ // hasBackdrop: false, thêm cái này để đóng khi click ra ngoài
950
+ fromEvent(document, 'click')
951
+ .pipe(filter$1((event) => {
952
+ const clickTarget = event.target;
953
+ return (this.overlayRef &&
954
+ !overlayElement.contains(clickTarget) && // click không nằm trong overlay
955
+ !origin.contains(clickTarget) && // và cũng không phải click vào input gốc
956
+ !clickTarget.closest('.ant-select-dropdown') &&
957
+ !clickTarget.closest('.ant-select-item') &&
958
+ !clickTarget.closest('.ant-select-item-option-content') &&
959
+ !clickTarget.closest('.no-close-custom-dropdow'));
960
+ }), takeUntil(this.overlayRef.detachments()))
961
+ .subscribe(() => {
962
+ this.overlayRef?.detach();
963
+ });
964
+ }
965
+ updateInputWidth(inputEl) {
966
+ this.inputWidth = inputEl?.offsetWidth || 0;
967
+ }
968
+ }
969
+
970
+ class Breadcrumb extends BaseComponent {
971
+ Breadcrumb = Breadcrumb;
972
+ static lstBreadcrumb = [];
973
+ static clear() {
974
+ Breadcrumb.lstBreadcrumb = [];
975
+ }
976
+ gohome() {
977
+ this.goto('');
978
+ }
979
+ onclick(item) {
980
+ if (item.URL) {
981
+ this.goto(item.URL);
982
+ }
983
+ else if (item.Click) {
984
+ item.Click();
985
+ }
986
+ }
987
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Breadcrumb, deps: null, target: i0.ɵɵFactoryTarget.Component });
988
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: Breadcrumb, isStandalone: true, selector: "app-breadcrumb", usesInheritance: true, ngImport: i0, template: "<nz-breadcrumb>\n <nz-breadcrumb-item (click)=\"gohome()\">\n <nz-icon nzType=\"home\" nzTheme=\"outline\" />\n </nz-breadcrumb-item>\n @for (item of Breadcrumb.lstBreadcrumb; track $index) {\n <nz-breadcrumb-item (click)=\"onclick(item)\">{{ item.Name }}</nz-breadcrumb-item>\n }\n</nz-breadcrumb>\n", dependencies: [{ kind: "ngmodule", type: NzBreadCrumbModule }, { kind: "component", type: i1$1.NzBreadCrumbComponent, selector: "nz-breadcrumb", inputs: ["nzAutoGenerate", "nzSeparator", "nzRouteLabel", "nzRouteLabelFn", "nzRouteFn"], exportAs: ["nzBreadcrumb"] }, { kind: "component", type: i1$1.NzBreadCrumbItemComponent, selector: "nz-breadcrumb-item", inputs: ["nzOverlay"], exportAs: ["nzBreadcrumbItem"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i2.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }] });
989
+ }
990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Breadcrumb, decorators: [{
991
+ type: Component,
992
+ args: [{ selector: 'app-breadcrumb', imports: [NzBreadCrumbModule, NzIconModule], template: "<nz-breadcrumb>\n <nz-breadcrumb-item (click)=\"gohome()\">\n <nz-icon nzType=\"home\" nzTheme=\"outline\" />\n </nz-breadcrumb-item>\n @for (item of Breadcrumb.lstBreadcrumb; track $index) {\n <nz-breadcrumb-item (click)=\"onclick(item)\">{{ item.Name }}</nz-breadcrumb-item>\n }\n</nz-breadcrumb>\n" }]
993
+ }] });
994
+
995
+ class AnimatedDigitComponent {
996
+ duration = 0;
997
+ digit = 0;
998
+ steps = 0;
999
+ animatedDigit;
1000
+ currentValue = 0;
1001
+ animateCount() {
1002
+ if (!this.duration) {
1003
+ this.duration = 1000;
1004
+ }
1005
+ if (typeof this.digit === 'number') {
1006
+ this.counterFunc(this.currentValue, this.digit, this.duration, this.animatedDigit);
1007
+ }
1008
+ }
1009
+ counterFunc(startValue, endValue, durationMs, element) {
1010
+ if (!this.steps) {
1011
+ this.steps = 12;
1012
+ }
1013
+ const stepCount = Math.abs(durationMs / this.steps);
1014
+ const valueIncrement = (endValue - startValue) / stepCount;
1015
+ const sinValueIncrement = Math.PI / stepCount;
1016
+ let currentSinValue = 0;
1017
+ function step() {
1018
+ currentSinValue += sinValueIncrement;
1019
+ startValue += valueIncrement * Math.sin(currentSinValue) ** 2 * 2;
1020
+ if (element)
1021
+ element.nativeElement.textContent = Math.abs(Math.floor(startValue));
1022
+ if (currentSinValue < Math.PI) {
1023
+ window.requestAnimationFrame(step);
1024
+ }
1025
+ }
1026
+ step();
1027
+ }
1028
+ ngAfterViewInit() {
1029
+ if (this.digit) {
1030
+ this.animateCount();
1031
+ }
1032
+ }
1033
+ ngOnChanges(changes) {
1034
+ if (changes['digit']) {
1035
+ this.animateCount();
1036
+ setTimeout(() => {
1037
+ this.currentValue = this.digit;
1038
+ }, this.duration);
1039
+ }
1040
+ }
1041
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AnimatedDigitComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1042
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: AnimatedDigitComponent, isStandalone: true, selector: "animated-digit", inputs: { duration: "duration", digit: "digit", steps: "steps" }, viewQueries: [{ propertyName: "animatedDigit", first: true, predicate: ["animatedDigit"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span #animatedDigit class=\"animated-digit\">\n <span>{{digit}}</span>\n</span>", styles: [".animated-digit{display:inline-flex;padding:0}\n"] });
1043
+ }
1044
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AnimatedDigitComponent, decorators: [{
1045
+ type: Component,
1046
+ args: [{ selector: 'animated-digit', template: "<span #animatedDigit class=\"animated-digit\">\n <span>{{digit}}</span>\n</span>", styles: [".animated-digit{display:inline-flex;padding:0}\n"] }]
1047
+ }], propDecorators: { duration: [{
1048
+ type: Input
1049
+ }], digit: [{
1050
+ type: Input
1051
+ }], steps: [{
1052
+ type: Input
1053
+ }], animatedDigit: [{
1054
+ type: ViewChild,
1055
+ args: ['animatedDigit']
1056
+ }] } });
1057
+
1058
+ class BarGraphComponent {
1059
+ height = 0;
1060
+ id = '';
1061
+ chart;
1062
+ constructor() {
1063
+ Chart.register(...registerables);
1064
+ }
1065
+ ngOnInit() {
1066
+ setTimeout(() => {
1067
+ this.createBarGraph();
1068
+ }, 500);
1069
+ }
1070
+ ngOnDestroy() {
1071
+ if (this.chart) {
1072
+ this.chart.destroy();
1073
+ }
1074
+ }
1075
+ createBarGraph() {
1076
+ if (!this.id) {
1077
+ return;
1078
+ }
1079
+ this.chart = new Chart(this.id, {
1080
+ type: 'bar',
1081
+ data: {
1082
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
1083
+ datasets: [
1084
+ {
1085
+ backgroundColor: 'rgba(92, 107, 192, .7)',
1086
+ borderColor: 'rgba(92, 107, 192, .7)',
1087
+ data: [70, 88, 77, 93, 82, 100, 70, 67, 78, 99],
1088
+ label: 'Dataset',
1089
+ },
1090
+ {
1091
+ backgroundColor: 'rgba(66, 165, 245, .7)',
1092
+ borderColor: 'rgba(69, 39, 160, .7)',
1093
+ data: [80, 88, 67, 95, 76, 60, 67, 95, 95, 66],
1094
+ label: 'Dataset',
1095
+ },
1096
+ {
1097
+ backgroundColor: 'rgba(38, 166, 154, .7)',
1098
+ borderColor: 'rgba(69, 39, 160, .7)',
1099
+ data: [60, 88, 70, 67, 27, 83, 78, 88, 95, 60],
1100
+ label: 'Dataset',
1101
+ },
1102
+ {
1103
+ backgroundColor: 'rgba(102, 187, 106, .7)',
1104
+ borderColor: 'rgba(255, 99, 132)',
1105
+ data: [75, 55, 55, 95, 66, 88, 70, 78, 77, 100],
1106
+ label: 'Dataset',
1107
+ },
1108
+ ],
1109
+ },
1110
+ options: {
1111
+ elements: {
1112
+ line: {
1113
+ tension: 0.000001,
1114
+ },
1115
+ },
1116
+ maintainAspectRatio: false,
1117
+ plugins: {
1118
+ filler: {
1119
+ propagate: false,
1120
+ },
1121
+ },
1122
+ },
1123
+ });
1124
+ }
1125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: BarGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1126
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: BarGraphComponent, isStandalone: true, selector: "cdk-bar-graph", inputs: { height: "height", id: "id" }, ngImport: i0, template: "<div class=\"dash-bar-graph-holder mat-elevation-z4\" [ngStyle]=\"{ height: height + 'px' }\">\n <canvas [id]=\"id\"></canvas>\n</div>\n", styles: [".dash-bar-graph-holder{margin:10px 5px;background-color:#fff}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1127
+ }
1128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: BarGraphComponent, decorators: [{
1129
+ type: Component,
1130
+ args: [{ selector: 'cdk-bar-graph', imports: [CommonModule], template: "<div class=\"dash-bar-graph-holder mat-elevation-z4\" [ngStyle]=\"{ height: height + 'px' }\">\n <canvas [id]=\"id\"></canvas>\n</div>\n", styles: [".dash-bar-graph-holder{margin:10px 5px;background-color:#fff}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"] }]
1131
+ }], ctorParameters: () => [], propDecorators: { height: [{
1132
+ type: Input
1133
+ }], id: [{
1134
+ type: Input
1135
+ }] } });
1136
+
1137
+ class DashcardComponent {
1138
+ dashData;
1139
+ constructor() { }
1140
+ ngOnInit() { }
1141
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: DashcardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1142
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: DashcardComponent, isStandalone: true, selector: "cdk-dashcard", inputs: { dashData: "dashData" }, ngImport: i0, template: "<div nz-row class=\"dashcard mat-elevation-z2\" style=\"height: 100%\">\n <div nz-col [nzSpan]=\"8\" class=\"text-center\" [style.background]=\"dashData?.colorLight\">\n <nz-icon class=\"mat-icon\" style=\"padding-top: 50px\" [nzType]=\"dashData?.icon\" nzTheme=\"outline\" />\n </div>\n <div nz-col [nzSpan]=\"16\" [style.background]=\"dashData?.colorDark\">\n <div class=\"text-center animated-digit\">\n <animated-digit [digit]=\"dashData?.number\"></animated-digit>\n </div>\n <p\n class=\"text-center mat-body-1 border-top text-bold\"\n style=\"font-size: 16px; margin-bottom: 8px; padding-top: 3px\"\n >\n {{ dashData?.title }}\n </p>\n </div>\n</div>\n", styles: [".dashcard .dashcard{margin:10px 5px;height:100px;background-color:#fff}.dashcard .mat-icon{font-size:40px;height:40px;width:40px;color:#fff}.dashcard .border-top{border-top:1px solid white}.dashcard .mat-headline,.dashcard .mat-body-1{margin:0;color:#fff}.dashcard .animated-digit{color:#fff;font-size:40px;font-weight:700}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"], dependencies: [{ kind: "ngmodule", type: NzGridModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i2.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: AnimatedDigitComponent, selector: "animated-digit", inputs: ["duration", "digit", "steps"] }] });
1143
+ }
1144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: DashcardComponent, decorators: [{
1145
+ type: Component,
1146
+ args: [{ selector: 'cdk-dashcard', imports: [NzGridModule, NzIconModule, AnimatedDigitComponent], template: "<div nz-row class=\"dashcard mat-elevation-z2\" style=\"height: 100%\">\n <div nz-col [nzSpan]=\"8\" class=\"text-center\" [style.background]=\"dashData?.colorLight\">\n <nz-icon class=\"mat-icon\" style=\"padding-top: 50px\" [nzType]=\"dashData?.icon\" nzTheme=\"outline\" />\n </div>\n <div nz-col [nzSpan]=\"16\" [style.background]=\"dashData?.colorDark\">\n <div class=\"text-center animated-digit\">\n <animated-digit [digit]=\"dashData?.number\"></animated-digit>\n </div>\n <p\n class=\"text-center mat-body-1 border-top text-bold\"\n style=\"font-size: 16px; margin-bottom: 8px; padding-top: 3px\"\n >\n {{ dashData?.title }}\n </p>\n </div>\n</div>\n", styles: [".dashcard .dashcard{margin:10px 5px;height:100px;background-color:#fff}.dashcard .mat-icon{font-size:40px;height:40px;width:40px;color:#fff}.dashcard .border-top{border-top:1px solid white}.dashcard .mat-headline,.dashcard .mat-body-1{margin:0;color:#fff}.dashcard .animated-digit{color:#fff;font-size:40px;font-weight:700}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"] }]
1147
+ }], ctorParameters: () => [], propDecorators: { dashData: [{
1148
+ type: Input
1149
+ }] } });
1150
+
1151
+ class DoughnutGraphComponent {
1152
+ height = 0;
1153
+ id = '';
1154
+ chart;
1155
+ constructor() {
1156
+ Chart.register(...registerables);
1157
+ }
1158
+ ngOnInit() {
1159
+ setTimeout(() => {
1160
+ this.createDoughnutGraph();
1161
+ }, 500);
1162
+ }
1163
+ ngOnDestroy() {
1164
+ if (this.chart) {
1165
+ this.chart.destroy();
1166
+ }
1167
+ }
1168
+ randomNumber(min = 0, max = 0) {
1169
+ if (min == 0 || max == 0)
1170
+ return Math.round(Math.random() * 100);
1171
+ else
1172
+ return Math.random() * (max - min) + min;
1173
+ }
1174
+ createDoughnutGraph() {
1175
+ if (!this.id) {
1176
+ return;
1177
+ }
1178
+ this.chart = new Chart(this.id, {
1179
+ type: 'doughnut',
1180
+ data: {
1181
+ labels: ['Data '],
1182
+ datasets: [
1183
+ {
1184
+ data: [this.randomNumber(), this.randomNumber(), this.randomNumber(), this.randomNumber()],
1185
+ backgroundColor: [
1186
+ 'rgba(255, 99, 132,.7)',
1187
+ 'rgba(92, 107, 192,.7)',
1188
+ 'rgba(66, 165, 245,.7)',
1189
+ 'rgba(38, 166, 154,.7)',
1190
+ 'rgba(102, 187, 106,.7)',
1191
+ ],
1192
+ },
1193
+ ],
1194
+ },
1195
+ options: {
1196
+ elements: {
1197
+ line: {
1198
+ tension: 0.000001,
1199
+ },
1200
+ },
1201
+ maintainAspectRatio: false,
1202
+ responsive: true,
1203
+ plugins: {
1204
+ filler: {
1205
+ propagate: false,
1206
+ },
1207
+ },
1208
+ },
1209
+ });
1210
+ }
1211
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: DoughnutGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1212
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: DoughnutGraphComponent, isStandalone: true, selector: "cdk-doughnut-graph", inputs: { height: "height", id: "id" }, ngImport: i0, template: "<div class=\"doughnut-graph-graph-holder mat-elevation-z4 \" [ngStyle]=\"{'height': height + 'px'}\">\n <canvas [id]=\"id\"></canvas>\n</div>", styles: [".doughnut-graph-graph-holder{margin:10px 5px;background-color:#fff}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1213
+ }
1214
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: DoughnutGraphComponent, decorators: [{
1215
+ type: Component,
1216
+ args: [{ selector: 'cdk-doughnut-graph', imports: [CommonModule], template: "<div class=\"doughnut-graph-graph-holder mat-elevation-z4 \" [ngStyle]=\"{'height': height + 'px'}\">\n <canvas [id]=\"id\"></canvas>\n</div>", styles: [".doughnut-graph-graph-holder{margin:10px 5px;background-color:#fff}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"] }]
1217
+ }], ctorParameters: () => [], propDecorators: { height: [{
1218
+ type: Input
1219
+ }], id: [{
1220
+ type: Input
1221
+ }] } });
1222
+
1223
+ class LineGraphComponent {
1224
+ height = 0;
1225
+ id = '';
1226
+ chart;
1227
+ constructor() {
1228
+ Chart.register(...registerables);
1229
+ }
1230
+ ngOnInit() {
1231
+ setTimeout(() => {
1232
+ this.createLineChart();
1233
+ }, 500);
1234
+ }
1235
+ ngOnDestroy() {
1236
+ if (this.chart) {
1237
+ this.chart.destroy();
1238
+ }
1239
+ }
1240
+ createLineChart() {
1241
+ if (!this.id) {
1242
+ return;
1243
+ }
1244
+ this.chart = new Chart(this.id, {
1245
+ type: 'line',
1246
+ data: {
1247
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct'],
1248
+ datasets: [
1249
+ {
1250
+ backgroundColor: 'rgba(92, 107, 192, 0.36)',
1251
+ borderColor: 'rgba(92, 107, 192,.5)',
1252
+ data: [76.97, 88.91, 99.31, 122.19, 130.85, 140.91, 150.36, 142.66, 150.36, 142.66],
1253
+ label: 'Dataset',
1254
+ fill: 'start',
1255
+ },
1256
+ ],
1257
+ },
1258
+ options: {
1259
+ elements: {
1260
+ line: {
1261
+ tension: 0.000001,
1262
+ },
1263
+ },
1264
+ maintainAspectRatio: false,
1265
+ plugins: {
1266
+ filler: {
1267
+ propagate: false,
1268
+ },
1269
+ },
1270
+ },
1271
+ });
1272
+ }
1273
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: LineGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1274
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: LineGraphComponent, isStandalone: true, selector: "cdk-line-graph", inputs: { height: "height", id: "id" }, ngImport: i0, template: "<div class=\"line-graph-holder mat-elevation-z4 \" [ngStyle]=\"{'height': height + 'px'}\">\n <canvas [id]=\"id\"></canvas>\n</div>", styles: [".line-graph-holder{margin:10px 5px;background-color:#fff}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1275
+ }
1276
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: LineGraphComponent, decorators: [{
1277
+ type: Component,
1278
+ args: [{ selector: 'cdk-line-graph', imports: [CommonModule], template: "<div class=\"line-graph-holder mat-elevation-z4 \" [ngStyle]=\"{'height': height + 'px'}\">\n <canvas [id]=\"id\"></canvas>\n</div>", styles: [".line-graph-holder{margin:10px 5px;background-color:#fff}.nav-item{transition:all .6s cubic-bezier(.165,.84,.44,1);cursor:default}.nav-item:hover{transform:translateY(-8px);box-shadow:0 20px 20px #00000029}\n"] }]
1279
+ }], ctorParameters: () => [], propDecorators: { height: [{
1280
+ type: Input
1281
+ }], id: [{
1282
+ type: Input
1283
+ }] } });
1284
+
1285
+ class ExtendCheckbox {
1286
+ label = '';
1287
+ labelSpan = 8;
1288
+ disabled = false;
1289
+ formData;
1290
+ controlName;
1291
+ /**
1292
+ * default: boolean
1293
+ */
1294
+ valueType = 'boolean';
1295
+ get _ngModel() {
1296
+ if (this.valueType == 'boolean') {
1297
+ return this.checked;
1298
+ }
1299
+ if (this.valueType == 'number') {
1300
+ return this.checked ? 1 : 0;
1301
+ }
1302
+ if (this.valueType == 'string') {
1303
+ return this.checked ? 'Y' : 'N';
1304
+ }
1305
+ }
1306
+ set _ngModel(val) {
1307
+ if (this.controlName) {
1308
+ if (this.valueType == 'boolean') {
1309
+ this.formData.controls[this.controlName].valueChanges.subscribe((x) => {
1310
+ this.checked = x;
1311
+ });
1312
+ }
1313
+ else if (this.valueType == 'number') {
1314
+ this.formData.controls[this.controlName].valueChanges.subscribe((x) => {
1315
+ this.checked = x == 1;
1316
+ });
1317
+ }
1318
+ else {
1319
+ this.formData.controls[this.controlName].valueChanges.subscribe((x) => {
1320
+ this.checked = x == 'Y';
1321
+ });
1322
+ }
1323
+ }
1324
+ else {
1325
+ this.checked = val ? true : false;
1326
+ }
1327
+ }
1328
+ _ngModelChange = new EventEmitter();
1329
+ checked = false;
1330
+ ngOnInit() {
1331
+ if (this.controlName && this.formData?.controls[this.controlName]) {
1332
+ if (this.valueType === 'boolean') {
1333
+ this.checked = this.formData.controls[this.controlName].getRawValue();
1334
+ console.log(this.checked);
1335
+ }
1336
+ else if (this.valueType === 'number') {
1337
+ this.checked = this.formData.controls[this.controlName].getRawValue() === 1;
1338
+ }
1339
+ else {
1340
+ this.checked = this.formData.controls[this.controlName].getRawValue() === 'Y';
1341
+ }
1342
+ this.formData.controls[this.controlName].valueChanges.subscribe((x) => {
1343
+ if (this.valueType === 'boolean') {
1344
+ this.checked = x;
1345
+ }
1346
+ else if (this.valueType === 'number') {
1347
+ this.checked = x === 1;
1348
+ }
1349
+ else {
1350
+ this.checked = x === 'Y';
1351
+ }
1352
+ });
1353
+ }
1354
+ }
1355
+ onCheckChange(event) {
1356
+ if (this.controlName) {
1357
+ if (this.valueType == 'boolean') {
1358
+ this.formData.controls[this.controlName].setValue(event);
1359
+ }
1360
+ else if (this.valueType == 'number') {
1361
+ this.formData.controls[this.controlName].setValue(event ? 1 : 0);
1362
+ }
1363
+ else if (this.valueType == 'string') {
1364
+ this.formData.controls[this.controlName].setValue(event ? 'Y' : 'N');
1365
+ }
1366
+ }
1367
+ else {
1368
+ if (this.valueType == 'boolean') {
1369
+ this._ngModelChange.emit(event);
1370
+ }
1371
+ else if (this.valueType == 'number') {
1372
+ this._ngModelChange.emit(event ? 1 : 0);
1373
+ }
1374
+ else if (this.valueType == 'string') {
1375
+ this._ngModelChange.emit(event ? 'Y' : 'N');
1376
+ }
1377
+ }
1378
+ }
1379
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
1380
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: ExtendCheckbox, isStandalone: true, selector: "extend-checkbox", inputs: { label: "label", labelSpan: "labelSpan", disabled: "disabled", formData: "formData", controlName: "controlName", valueType: "valueType", _ngModel: "_ngModel" }, outputs: { _ngModelChange: "_ngModelChange" }, ngImport: i0, template: "@if (label) {\n <div nz-row>\n <div nz-col [nzSpan]=\"labelSpan\"></div>\n <div nz-col nzFlex=\"auto\">\n <label\n style=\"position: relative; top: 5px\"\n nz-checkbox\n [nzDisabled]=\"disabled\"\n [(nzChecked)]=\"checked\"\n (nzCheckedChange)=\"onCheckChange($event)\"\n >\n {{ label }}\n </label>\n </div>\n </div>\n} @else {\n <label\n nz-checkbox\n [nzDisabled]=\"disabled\"\n [(nzChecked)]=\"checked\"\n (nzCheckedChange)=\"onCheckChange($event)\"\n style=\"width: 16px\"\n >\n {{ label }}\n </label>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzCheckboxModule }, { kind: "component", type: i2$1.NzCheckboxComponent, selector: "[nz-checkbox]", inputs: ["nzValue", "nzAutoFocus", "nzDisabled", "nzIndeterminate", "nzChecked", "nzId", "nzName"], outputs: ["nzCheckedChange"], exportAs: ["nzCheckbox"] }] });
1381
+ }
1382
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendCheckbox, decorators: [{
1383
+ type: Component,
1384
+ args: [{ selector: 'extend-checkbox', imports: [CommonModule, FormsModule, ReactiveFormsModule, NzFormModule, NzCheckboxModule], template: "@if (label) {\n <div nz-row>\n <div nz-col [nzSpan]=\"labelSpan\"></div>\n <div nz-col nzFlex=\"auto\">\n <label\n style=\"position: relative; top: 5px\"\n nz-checkbox\n [nzDisabled]=\"disabled\"\n [(nzChecked)]=\"checked\"\n (nzCheckedChange)=\"onCheckChange($event)\"\n >\n {{ label }}\n </label>\n </div>\n </div>\n} @else {\n <label\n nz-checkbox\n [nzDisabled]=\"disabled\"\n [(nzChecked)]=\"checked\"\n (nzCheckedChange)=\"onCheckChange($event)\"\n style=\"width: 16px\"\n >\n {{ label }}\n </label>\n}\n" }]
1385
+ }], propDecorators: { label: [{
1386
+ type: Input
1387
+ }], labelSpan: [{
1388
+ type: Input
1389
+ }], disabled: [{
1390
+ type: Input
1391
+ }], formData: [{
1392
+ type: Input
1393
+ }], controlName: [{
1394
+ type: Input
1395
+ }], valueType: [{
1396
+ type: Input
1397
+ }], _ngModel: [{
1398
+ type: Input
1399
+ }], _ngModelChange: [{
1400
+ type: Output
1401
+ }] } });
1402
+
1403
+ class DateTimeHelper {
1404
+ static lstDay = Array.from({ length: 31 }, (_, i) => i + 1);
1405
+ static lstMonth = Array.from({ length: 12 }, (_, i) => i + 1);
1406
+ static fromYear = new Date().getFullYear() - 10;
1407
+ static toYear = new Date().getFullYear();
1408
+ static lstYear = Array.from({ length: DateTimeHelper.toYear - DateTimeHelper.fromYear }, (_, i) => DateTimeHelper.toYear - i);
1409
+ /**
1410
+ * Lấy ngày giờ hiện tại dưới dạng chuỗi "YYYY-MM-DD HH:mm:ss"
1411
+ * @return {string}
1412
+ */
1413
+ static now() {
1414
+ const now = new Date();
1415
+ return `${now.getFullYear()}-${this.pad(now.getMonth() + 1)}-${this.pad(now.getDate())} ${this.pad(now.getHours())}:${this.pad(now.getMinutes())}:${this.pad(now.getSeconds())}`;
1416
+ }
1417
+ /**
1418
+ * Lấy ngày hôm nay dưới dạng chuỗi "YYYY-MM-DD HH:mm:ss"
1419
+ * @return {string}
1420
+ */
1421
+ static today() {
1422
+ const now = new Date();
1423
+ return `${now.getFullYear()}-${this.pad(now.getMonth() + 1)}-${this.pad(now.getDate())} 00:00:00`;
1424
+ }
1425
+ /**
1426
+ * Tạo ngày từ năm, tháng, ngày (có kiểm tra hợp lệ, không bị lệch múi giờ).
1427
+ * @param {number} year Năm
1428
+ * @param {number} month Tháng (1-12)
1429
+ * @param {number} day Ngày (1-31)
1430
+ * @param {boolean} isEndOfDay Nếu true, trả về 23:59:59, ngược lại 00:00:00
1431
+ * @return {string | null} Chuỗi ngày định dạng "YYYY-MM-DD HH:mm:ss" hoặc null nếu ngày không hợp lệ
1432
+ */
1433
+ static createDate(year, month, day, isEndOfDay = false) {
1434
+ if (!this.isValidDate(year, month, day)) {
1435
+ return null;
1436
+ }
1437
+ const hour = isEndOfDay ? 23 : 0;
1438
+ const minute = isEndOfDay ? 59 : 0;
1439
+ const second = isEndOfDay ? 59 : 0;
1440
+ return `${year}-${this.pad(month)}-${this.pad(day)} ${this.pad(hour)}:${this.pad(minute)}:${this.pad(second)}`;
1441
+ }
1442
+ /**
1443
+ * Kiểm tra xem ngày có hợp lệ không.
1444
+ * @param {number} year Năm
1445
+ * @param {number} month Tháng (1-12)
1446
+ * @param {number} day Ngày (1-31)
1447
+ * @return {boolean} True nếu ngày hợp lệ, ngược lại False.
1448
+ */
1449
+ static isValidDate(year, month, day) {
1450
+ if (month < 1 || month > 12)
1451
+ return false;
1452
+ if (day < 1)
1453
+ return false;
1454
+ const lastDay = new Date(year, month, 0).getDate(); // Lấy ngày cuối tháng
1455
+ return day <= lastDay;
1456
+ }
1457
+ /**
1458
+ * Hàm hỗ trợ: Định dạng số thành 2 chữ số (01, 02, ..., 09)
1459
+ * @param {number} n The second number.
1460
+ * @return {string} The sum of the two numbers.
1461
+ */
1462
+ static pad(n) {
1463
+ return n.toString().padStart(2, '0');
1464
+ }
1465
+ static parser(dateStr) {
1466
+ if (!dateStr.includes('/')) {
1467
+ dateStr = this.formatNumberToDate(dateStr);
1468
+ }
1469
+ const parts = dateStr.split('/');
1470
+ const current = new Date();
1471
+ let normalizedValue = '';
1472
+ if (parts.length === 1 && /^\d{1,2}$/.test(parts[0])) {
1473
+ // Chỉ có ngày -> ghép tháng/năm hiện tại
1474
+ normalizedValue = `${parts[0].padStart(2, '0')}/${(current.getMonth() + 1).toString().padStart(2, '0')}/${current.getFullYear()}`;
1475
+ }
1476
+ else if (parts.length === 2 && /^\d{1,2}$/.test(parts[0]) && /^\d{1,2}$/.test(parts[1])) {
1477
+ // Có ngày + tháng -> ghép năm hiện tại
1478
+ normalizedValue = `${parts[0].padStart(2, '0')}/${parts[1].padStart(2, '0')}/${current.getFullYear()}`;
1479
+ }
1480
+ else {
1481
+ // Đã đủ 3 phần
1482
+ normalizedValue = dateStr;
1483
+ }
1484
+ if (normalizedValue) {
1485
+ const parts = normalizedValue.split('/');
1486
+ const day = +parts[0];
1487
+ const month = +parts[1];
1488
+ const year = +parts[2];
1489
+ if (DateTimeHelper.isValidDate(year, month, day)) {
1490
+ return DateTimeHelper.createDate(year, month, day);
1491
+ }
1492
+ }
1493
+ return '';
1494
+ }
1495
+ static formatNumberToDate(input) {
1496
+ // Lấy tối đa 8 ký tự
1497
+ input = input.replace(/\D/g, '').substring(0, 8);
1498
+ const day = input.substring(0, 2);
1499
+ const month = input.substring(2, 4);
1500
+ const year = input.substring(4, 8);
1501
+ let result = '';
1502
+ if (day) {
1503
+ result += day;
1504
+ if (month)
1505
+ result += '/';
1506
+ }
1507
+ if (month) {
1508
+ result += month;
1509
+ if (year)
1510
+ result += '/';
1511
+ }
1512
+ if (year) {
1513
+ result += year;
1514
+ }
1515
+ return result;
1516
+ }
1517
+ }
1518
+
1519
+ /**
1520
+ * Dùng cho nz-date-picker
1521
+ */
1522
+ class DateInputParserDirective {
1523
+ el;
1524
+ ngControl;
1525
+ format = 'dd/MM/yyyy';
1526
+ inputElement = null;
1527
+ blurHandler = this.tryParseAndSet.bind(this);
1528
+ constructor(el, ngControl) {
1529
+ this.el = el;
1530
+ this.ngControl = ngControl;
1531
+ }
1532
+ ngAfterViewInit() {
1533
+ // Tìm thẻ input bên trong nz-date-picker
1534
+ this.inputElement = this.el.nativeElement.querySelector('input');
1535
+ // Gắn listener blur vào input
1536
+ if (this.inputElement) {
1537
+ this.inputElement.addEventListener('blur', this.blurHandler);
1538
+ }
1539
+ }
1540
+ ngOnDestroy() {
1541
+ // Cleanup blur listener để tránh memory leak
1542
+ if (this.inputElement) {
1543
+ this.inputElement.removeEventListener('blur', this.blurHandler);
1544
+ }
1545
+ }
1546
+ onEnter() {
1547
+ this.tryParseAndSet();
1548
+ this.inputElement?.blur(); // Blur sau khi enter nếu muốn trigger binding ngoài
1549
+ }
1550
+ tryParseAndSet() {
1551
+ if (!this.inputElement)
1552
+ return;
1553
+ const rawValue = this.inputElement.value.trim();
1554
+ const parsed = DateTimeHelper.parser(rawValue);
1555
+ if (parsed) {
1556
+ this.ngControl?.control?.setValue(parsed);
1557
+ }
1558
+ }
1559
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: DateInputParserDirective, deps: [{ token: i0.ElementRef }, { token: i2$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
1560
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.7", type: DateInputParserDirective, isStandalone: true, selector: "nz-date-picker", inputs: { format: "format" }, host: { listeners: { "keyup.enter": "onEnter()" } }, ngImport: i0 });
1561
+ }
1562
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: DateInputParserDirective, decorators: [{
1563
+ type: Directive,
1564
+ args: [{
1565
+ selector: 'nz-date-picker',
1566
+ }]
1567
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i2$2.NgControl, decorators: [{
1568
+ type: Optional
1569
+ }, {
1570
+ type: Self
1571
+ }] }], propDecorators: { format: [{
1572
+ type: Input,
1573
+ args: ['format']
1574
+ }], onEnter: [{
1575
+ type: HostListener,
1576
+ args: ['keyup.enter']
1577
+ }] } });
1578
+
1579
+ class ExtendDatePicker {
1580
+ dateFormat = 'dd/MM/yyyy';
1581
+ layOutType = 'horizontal';
1582
+ label = '';
1583
+ placeHolder = '';
1584
+ labelAlign = 'left';
1585
+ labelSpan = 8;
1586
+ inputSpan = 16;
1587
+ disabled = false;
1588
+ required = false;
1589
+ noBottom = false;
1590
+ selectModeType = 'default';
1591
+ inputWidth = '';
1592
+ inputHeight = '';
1593
+ borderBottomOnly = false;
1594
+ displayInline = false;
1595
+ size = 'default';
1596
+ lstItem = [];
1597
+ displayField = '';
1598
+ valueField = '';
1599
+ formData;
1600
+ controlName;
1601
+ _ngModel = null;
1602
+ _ngModelChange = new EventEmitter();
1603
+ onChange = (_) => { };
1604
+ onTouched = () => { };
1605
+ writeValue(obj) {
1606
+ this._ngModel = obj;
1607
+ }
1608
+ registerOnChange(fn) {
1609
+ this.onChange = fn;
1610
+ }
1611
+ registerOnTouched(fn) {
1612
+ this.onTouched = fn;
1613
+ }
1614
+ setDisabledState(isDisabled) {
1615
+ this.disabled = isDisabled;
1616
+ }
1617
+ ngOnInit() { }
1618
+ onNgModelChange(val) {
1619
+ this._ngModel = val;
1620
+ this.onChange(val); // Gửi ngược ra form
1621
+ this.onTouched();
1622
+ this._ngModelChange.emit(val);
1623
+ }
1624
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1625
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: ExtendDatePicker, isStandalone: true, selector: "extend-date-picker", inputs: { dateFormat: "dateFormat", layOutType: "layOutType", label: "label", placeHolder: "placeHolder", labelAlign: "labelAlign", labelSpan: "labelSpan", inputSpan: "inputSpan", disabled: "disabled", required: "required", noBottom: "noBottom", selectModeType: "selectModeType", inputWidth: "inputWidth", inputHeight: "inputHeight", borderBottomOnly: "borderBottomOnly", displayInline: "displayInline", size: "size", lstItem: "lstItem", displayField: "displayField", valueField: "valueField", formData: "formData", controlName: "controlName", _ngModel: "_ngModel" }, outputs: { _ngModelChange: "_ngModelChange" }, ngImport: i0, template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? inputSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-date-picker\n class=\"full-width\"\n [nzPlaceHolder]=\"placeHolder || ' '\"\n [nzFormat]=\"dateFormat\"\n [formControlName]=\"controlName\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n }\"\n ></nz-date-picker>\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? inputSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-date-picker\n class=\"full-width\"\n [nzPlaceHolder]=\"placeHolder || ' '\"\n [nzFormat]=\"dateFormat\"\n [disabled]=\"disabled\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n }\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onNgModelChange($event)\"\n ></nz-date-picker>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <nz-date-picker\n class=\"full-width\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n }\"\n [nzPlaceHolder]=\"placeHolder || ' '\"\n [nzFormat]=\"dateFormat\"\n [disabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onNgModelChange($event)\"\n ></nz-date-picker>\n }\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "component", type: i5.NzFormItemComponent, selector: "nz-form-item", exportAs: ["nzFormItem"] }, { kind: "component", type: i5.NzFormLabelComponent, selector: "nz-form-label", inputs: ["nzFor", "nzRequired", "nzNoColon", "nzTooltipTitle", "nzTooltipIcon", "nzLabelAlign", "nzLabelWrap"], exportAs: ["nzFormLabel"] }, { kind: "component", type: i5.NzFormControlComponent, selector: "nz-form-control", inputs: ["nzSuccessTip", "nzWarningTip", "nzErrorTip", "nzValidatingTip", "nzExtra", "nzAutoTips", "nzDisableAutoTips", "nzHasFeedback", "nzValidateStatus"], exportAs: ["nzFormControl"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i5$1.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzAllowClear", "nzAutoFocus", "nzDisabled", "nzBorderless", "nzInputReadOnly", "nzInline", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "directive", type: DateInputParserDirective, selector: "nz-date-picker", inputs: ["format"] }] });
1626
+ }
1627
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendDatePicker, decorators: [{
1628
+ type: Component,
1629
+ args: [{ selector: 'extend-date-picker', imports: [
1630
+ CommonModule,
1631
+ FormsModule,
1632
+ ReactiveFormsModule,
1633
+ NzFormModule,
1634
+ NzDatePickerModule,
1635
+ TranslateModule,
1636
+ DateInputParserDirective,
1637
+ ], template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? inputSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-date-picker\n class=\"full-width\"\n [nzPlaceHolder]=\"placeHolder || ' '\"\n [nzFormat]=\"dateFormat\"\n [formControlName]=\"controlName\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n }\"\n ></nz-date-picker>\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? inputSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-date-picker\n class=\"full-width\"\n [nzPlaceHolder]=\"placeHolder || ' '\"\n [nzFormat]=\"dateFormat\"\n [disabled]=\"disabled\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n }\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onNgModelChange($event)\"\n ></nz-date-picker>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <nz-date-picker\n class=\"full-width\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n }\"\n [nzPlaceHolder]=\"placeHolder || ' '\"\n [nzFormat]=\"dateFormat\"\n [disabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onNgModelChange($event)\"\n ></nz-date-picker>\n }\n }\n</div>\n" }]
1638
+ }], propDecorators: { dateFormat: [{
1639
+ type: Input
1640
+ }], layOutType: [{
1641
+ type: Input
1642
+ }], label: [{
1643
+ type: Input
1644
+ }], placeHolder: [{
1645
+ type: Input
1646
+ }], labelAlign: [{
1647
+ type: Input
1648
+ }], labelSpan: [{
1649
+ type: Input
1650
+ }], inputSpan: [{
1651
+ type: Input
1652
+ }], disabled: [{
1653
+ type: Input
1654
+ }], required: [{
1655
+ type: Input
1656
+ }], noBottom: [{
1657
+ type: Input
1658
+ }], selectModeType: [{
1659
+ type: Input
1660
+ }], inputWidth: [{
1661
+ type: Input
1662
+ }], inputHeight: [{
1663
+ type: Input
1664
+ }], borderBottomOnly: [{
1665
+ type: Input
1666
+ }], displayInline: [{
1667
+ type: Input
1668
+ }], size: [{
1669
+ type: Input
1670
+ }], lstItem: [{
1671
+ type: Input
1672
+ }], displayField: [{
1673
+ type: Input
1674
+ }], valueField: [{
1675
+ type: Input
1676
+ }], formData: [{
1677
+ type: Input
1678
+ }], controlName: [{
1679
+ type: Input
1680
+ }], _ngModel: [{
1681
+ type: Input
1682
+ }], _ngModelChange: [{
1683
+ type: Output
1684
+ }] } });
1685
+
1686
+ class ExtendInputNumber {
1687
+ layOutType = 'horizontal'; // horizontal: ngang, vertical dọc
1688
+ label = '';
1689
+ placeHolder = '';
1690
+ labelAlign = 'left';
1691
+ labelSpan = 8;
1692
+ disabled = false;
1693
+ required = false;
1694
+ noBottom = false;
1695
+ size = 'default';
1696
+ min = null;
1697
+ max = null;
1698
+ precision = 0;
1699
+ inputWidth = '';
1700
+ inputHeight = '';
1701
+ borderBottomOnly = false;
1702
+ displayInline = false;
1703
+ /** separatorType: 'comma' (,) | 'dot' (.) */
1704
+ separatorType;
1705
+ /** defaultSeparatorType: 'comma' (,) | 'dot' (.) */
1706
+ static defaultSeparatorType = 'comma';
1707
+ formData;
1708
+ controlName;
1709
+ _ngModel = null;
1710
+ _ngModelChange = new EventEmitter();
1711
+ ngOnInit() { }
1712
+ _onNgModelChange() {
1713
+ this._ngModelChange.emit(this._ngModel);
1714
+ }
1715
+ inputElement;
1716
+ focus() {
1717
+ this.inputElement?.nativeElement?.focus();
1718
+ }
1719
+ formatterNumber = (value) => {
1720
+ if (value == null || isNaN(value))
1721
+ return '';
1722
+ if (!this.getSeparatorType()) {
1723
+ return value.toString();
1724
+ }
1725
+ const parts = `${value}`.split('.');
1726
+ const integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.getSeparatorType() === 'comma' ? ',' : '.');
1727
+ return parts.length > 1
1728
+ ? `${integerPart}${this.getSeparatorType() === 'comma' ? '.' : ','}${parts[1]}`
1729
+ : integerPart;
1730
+ };
1731
+ parserNumber = (value) => {
1732
+ if (!value)
1733
+ return 0;
1734
+ if (!this.getSeparatorType()) {
1735
+ return parseFloat(value);
1736
+ }
1737
+ // Bỏ ký tự phân cách hàng nghìn
1738
+ const cleaned = value
1739
+ .replace(new RegExp(`\\${this.getSeparatorType() === 'comma' ? ',' : '.'}`, 'g'), '')
1740
+ .replace(this.getSeparatorType() === 'comma' ? '.' : ',', '.');
1741
+ // Kiểm tra toàn bộ chuỗi có phải là số hợp lệ hay không
1742
+ if (!/^-?\d+(\.\d+)?$/.test(cleaned))
1743
+ return NaN;
1744
+ return parseFloat(cleaned);
1745
+ };
1746
+ getSeparatorType() {
1747
+ if (this.separatorType == 'blank') {
1748
+ return '';
1749
+ }
1750
+ if (this.separatorType) {
1751
+ return this.separatorType;
1752
+ }
1753
+ return ExtendInputNumber.defaultSeparatorType;
1754
+ }
1755
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendInputNumber, deps: [], target: i0.ɵɵFactoryTarget.Component });
1756
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: ExtendInputNumber, isStandalone: true, selector: "extend-input-number", inputs: { layOutType: "layOutType", label: "label", placeHolder: "placeHolder", labelAlign: "labelAlign", labelSpan: "labelSpan", disabled: "disabled", required: "required", noBottom: "noBottom", size: "size", min: "min", max: "max", precision: "precision", inputWidth: "inputWidth", inputHeight: "inputHeight", borderBottomOnly: "borderBottomOnly", displayInline: "displayInline", separatorType: "separatorType", formData: "formData", controlName: "controlName", _ngModel: "_ngModel" }, outputs: { _ngModelChange: "_ngModelChange" }, viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], ngImport: i0, template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [formControlName]=\"controlName\"\n />\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n @if (min != null && max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (min != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n }\n </nz-form-control>\n </nz-form-item>\n } @else {\n @if (min != null && max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (min != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n border: borderBottomOnly ? 'none' : '',\n 'border-bottom': borderBottomOnly ? '1px dashed' : '',\n }\"\n />\n }\n }\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "component", type: i5.NzFormItemComponent, selector: "nz-form-item", exportAs: ["nzFormItem"] }, { kind: "component", type: i5.NzFormLabelComponent, selector: "nz-form-label", inputs: ["nzFor", "nzRequired", "nzNoColon", "nzTooltipTitle", "nzTooltipIcon", "nzLabelAlign", "nzLabelWrap"], exportAs: ["nzFormLabel"] }, { kind: "component", type: i5.NzFormControlComponent, selector: "nz-form-control", inputs: ["nzSuccessTip", "nzWarningTip", "nzErrorTip", "nzValidatingTip", "nzExtra", "nzAutoTips", "nzDisableAutoTips", "nzHasFeedback", "nzValidateStatus"], exportAs: ["nzFormControl"] }, { kind: "ngmodule", type: NzInputNumberModule }, { kind: "component", type: i6.NzInputNumberComponent, selector: "nz-input-number", inputs: ["nzId", "nzSize", "nzPlaceHolder", "nzStatus", "nzStep", "nzMin", "nzMax", "nzPrecision", "nzParser", "nzFormatter", "nzDisabled", "nzReadOnly", "nzAutoFocus", "nzBordered", "nzKeyboard", "nzControls"], outputs: ["nzOnStep"], exportAs: ["nzInputNumber"] }] });
1757
+ }
1758
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendInputNumber, decorators: [{
1759
+ type: Component,
1760
+ args: [{ selector: 'extend-input-number', imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, NzFormModule, NzInputNumberModule], template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [formControlName]=\"controlName\"\n />\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n @if (min != null && max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (min != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n }\n </nz-form-control>\n </nz-form-item>\n } @else {\n @if (min != null && max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (min != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMin]=\"min\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else if (max != null) {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzMax]=\"max\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n />\n } @else {\n <nz-input-number\n class=\"full-width\"\n [nzSize]=\"size\"\n [nzFormatter]=\"formatterNumber\"\n [nzParser]=\"parserNumber\"\n [nzPrecision]=\"precision\"\n [nzDisabled]=\"disabled\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n border: borderBottomOnly ? 'none' : '',\n 'border-bottom': borderBottomOnly ? '1px dashed' : '',\n }\"\n />\n }\n }\n }\n</div>\n" }]
1761
+ }], propDecorators: { layOutType: [{
1762
+ type: Input
1763
+ }], label: [{
1764
+ type: Input
1765
+ }], placeHolder: [{
1766
+ type: Input
1767
+ }], labelAlign: [{
1768
+ type: Input
1769
+ }], labelSpan: [{
1770
+ type: Input
1771
+ }], disabled: [{
1772
+ type: Input
1773
+ }], required: [{
1774
+ type: Input
1775
+ }], noBottom: [{
1776
+ type: Input
1777
+ }], size: [{
1778
+ type: Input
1779
+ }], min: [{
1780
+ type: Input
1781
+ }], max: [{
1782
+ type: Input
1783
+ }], precision: [{
1784
+ type: Input
1785
+ }], inputWidth: [{
1786
+ type: Input
1787
+ }], inputHeight: [{
1788
+ type: Input
1789
+ }], borderBottomOnly: [{
1790
+ type: Input
1791
+ }], displayInline: [{
1792
+ type: Input
1793
+ }], separatorType: [{
1794
+ type: Input
1795
+ }], formData: [{
1796
+ type: Input
1797
+ }], controlName: [{
1798
+ type: Input
1799
+ }], _ngModel: [{
1800
+ type: Input
1801
+ }], _ngModelChange: [{
1802
+ type: Output
1803
+ }], inputElement: [{
1804
+ type: ViewChild,
1805
+ args: ['inputElement']
1806
+ }] } });
1807
+
1808
+ class ExtendInput {
1809
+ layOutType = 'horizontal'; // horizontal: ngang, vertical dọc
1810
+ label = '';
1811
+ placeHolder = '';
1812
+ labelAlign = 'left';
1813
+ inputClass = '';
1814
+ /**
1815
+ * default = 8
1816
+ */
1817
+ labelSpan = 8;
1818
+ allowClear = false;
1819
+ disabled = false;
1820
+ required = false;
1821
+ noBottom = false;
1822
+ selectModeType = 'default';
1823
+ autocomplete = '';
1824
+ inputWidth = '';
1825
+ inputHeight = '';
1826
+ borderBottomOnly = false;
1827
+ displayInline = false;
1828
+ size = 'default';
1829
+ lstItem = [];
1830
+ /**
1831
+ * Dùng trong word page
1832
+ */
1833
+ displayField = '';
1834
+ valueField = '';
1835
+ formData;
1836
+ controlName;
1837
+ _ngModel = null;
1838
+ _ngModelChange = new EventEmitter();
1839
+ onclickClearIcon = new EventEmitter();
1840
+ onenter = new EventEmitter();
1841
+ ngOnInit() { }
1842
+ _onNgModelChange() {
1843
+ this._ngModelChange.emit(this._ngModel);
1844
+ }
1845
+ inputElement;
1846
+ focus() {
1847
+ this.inputElement?.nativeElement?.select();
1848
+ }
1849
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
1850
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: ExtendInput, isStandalone: true, selector: "extend-input", inputs: { layOutType: "layOutType", label: "label", placeHolder: "placeHolder", labelAlign: "labelAlign", inputClass: "inputClass", labelSpan: "labelSpan", allowClear: "allowClear", disabled: "disabled", required: "required", noBottom: "noBottom", selectModeType: "selectModeType", autocomplete: "autocomplete", inputWidth: "inputWidth", inputHeight: "inputHeight", borderBottomOnly: "borderBottomOnly", displayInline: "displayInline", size: "size", lstItem: "lstItem", displayField: "displayField", valueField: "valueField", formData: "formData", controlName: "controlName", _ngModel: "_ngModel" }, outputs: { _ngModelChange: "_ngModelChange", onclickClearIcon: "onclickClearIcon", onenter: "onenter" }, viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], ngImport: i0, template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <input\n #inputElement\n nz-input\n [nzSize]=\"size\"\n [id]=\"controlName\"\n [name]=\"controlName\"\n [formControlName]=\"controlName\"\n [autocomplete]=\"autocomplete\"\n [placeholder]=\"placeHolder\"\n [ngClass]=\"inputClass\"\n (keyup.enter)=\"onenter.emit()\"\n />\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-input-group [nzSuffix]=\"allowClear ? clearIcon : undefined\">\n <input\n #inputElement\n nz-input\n [nzSize]=\"size\"\n [id]=\"controlName\"\n [name]=\"controlName\"\n [(ngModel)]=\"_ngModel\"\n [autocomplete]=\"autocomplete\"\n (ngModelChange)=\"_onNgModelChange()\"\n [disabled]=\"disabled\"\n [placeholder]=\"placeHolder\"\n [ngClass]=\"inputClass\"\n (keyup.enter)=\"onenter.emit()\"\n />\n </nz-input-group>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <input\n #inputElement\n nz-input\n [nzSize]=\"size\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [id]=\"controlName\"\n [name]=\"controlName\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n [autocomplete]=\"autocomplete\"\n [disabled]=\"disabled\"\n [placeholder]=\"placeHolder\"\n [ngClass]=\"inputClass + ' ' + (borderBottomOnly ? 'border-bottom-only' : '')\"\n (keyup.enter)=\"onenter.emit()\"\n />\n }\n }\n</div>\n\n<ng-template #clearIcon>\n <i\n nz-icon\n nzType=\"close-circle\"\n nzTheme=\"twotone\"\n nzTwotoneColor=\"#999\"\n *ngIf=\"_ngModel\"\n (click)=\"_ngModel = null; _onNgModelChange(); onclickClearIcon.emit()\"\n style=\"cursor: pointer\"\n ></i>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "component", type: i5.NzFormItemComponent, selector: "nz-form-item", exportAs: ["nzFormItem"] }, { kind: "component", type: i5.NzFormLabelComponent, selector: "nz-form-label", inputs: ["nzFor", "nzRequired", "nzNoColon", "nzTooltipTitle", "nzTooltipIcon", "nzLabelAlign", "nzLabelWrap"], exportAs: ["nzFormLabel"] }, { kind: "component", type: i5.NzFormControlComponent, selector: "nz-form-control", inputs: ["nzSuccessTip", "nzWarningTip", "nzErrorTip", "nzValidatingTip", "nzExtra", "nzAutoTips", "nzDisableAutoTips", "nzHasFeedback", "nzValidateStatus"], exportAs: ["nzFormControl"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i6$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: i6$1.NzInputGroupComponent, selector: "nz-input-group", inputs: ["nzAddOnBeforeIcon", "nzAddOnAfterIcon", "nzPrefixIcon", "nzSuffixIcon", "nzAddOnBefore", "nzAddOnAfter", "nzPrefix", "nzStatus", "nzSuffix", "nzSize", "nzSearch", "nzCompact"], exportAs: ["nzInputGroup"] }, { kind: "directive", type: i6$1.NzInputGroupWhitSuffixOrPrefixDirective, selector: "nz-input-group[nzSuffix], nz-input-group[nzPrefix]" }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i2.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }] });
1851
+ }
1852
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendInput, decorators: [{
1853
+ type: Component,
1854
+ args: [{ selector: 'extend-input', imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, NzFormModule, NzInputModule, NzIconModule], template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <input\n #inputElement\n nz-input\n [nzSize]=\"size\"\n [id]=\"controlName\"\n [name]=\"controlName\"\n [formControlName]=\"controlName\"\n [autocomplete]=\"autocomplete\"\n [placeholder]=\"placeHolder\"\n [ngClass]=\"inputClass\"\n (keyup.enter)=\"onenter.emit()\"\n />\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-input-group [nzSuffix]=\"allowClear ? clearIcon : undefined\">\n <input\n #inputElement\n nz-input\n [nzSize]=\"size\"\n [id]=\"controlName\"\n [name]=\"controlName\"\n [(ngModel)]=\"_ngModel\"\n [autocomplete]=\"autocomplete\"\n (ngModelChange)=\"_onNgModelChange()\"\n [disabled]=\"disabled\"\n [placeholder]=\"placeHolder\"\n [ngClass]=\"inputClass\"\n (keyup.enter)=\"onenter.emit()\"\n />\n </nz-input-group>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <input\n #inputElement\n nz-input\n [nzSize]=\"size\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [id]=\"controlName\"\n [name]=\"controlName\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"_onNgModelChange()\"\n [autocomplete]=\"autocomplete\"\n [disabled]=\"disabled\"\n [placeholder]=\"placeHolder\"\n [ngClass]=\"inputClass + ' ' + (borderBottomOnly ? 'border-bottom-only' : '')\"\n (keyup.enter)=\"onenter.emit()\"\n />\n }\n }\n</div>\n\n<ng-template #clearIcon>\n <i\n nz-icon\n nzType=\"close-circle\"\n nzTheme=\"twotone\"\n nzTwotoneColor=\"#999\"\n *ngIf=\"_ngModel\"\n (click)=\"_ngModel = null; _onNgModelChange(); onclickClearIcon.emit()\"\n style=\"cursor: pointer\"\n ></i>\n</ng-template>\n" }]
1855
+ }], propDecorators: { layOutType: [{
1856
+ type: Input
1857
+ }], label: [{
1858
+ type: Input
1859
+ }], placeHolder: [{
1860
+ type: Input
1861
+ }], labelAlign: [{
1862
+ type: Input
1863
+ }], inputClass: [{
1864
+ type: Input
1865
+ }], labelSpan: [{
1866
+ type: Input
1867
+ }], allowClear: [{
1868
+ type: Input
1869
+ }], disabled: [{
1870
+ type: Input
1871
+ }], required: [{
1872
+ type: Input
1873
+ }], noBottom: [{
1874
+ type: Input
1875
+ }], selectModeType: [{
1876
+ type: Input
1877
+ }], autocomplete: [{
1878
+ type: Input
1879
+ }], inputWidth: [{
1880
+ type: Input
1881
+ }], inputHeight: [{
1882
+ type: Input
1883
+ }], borderBottomOnly: [{
1884
+ type: Input
1885
+ }], displayInline: [{
1886
+ type: Input
1887
+ }], size: [{
1888
+ type: Input
1889
+ }], lstItem: [{
1890
+ type: Input
1891
+ }], displayField: [{
1892
+ type: Input
1893
+ }], valueField: [{
1894
+ type: Input
1895
+ }], formData: [{
1896
+ type: Input
1897
+ }], controlName: [{
1898
+ type: Input
1899
+ }], _ngModel: [{
1900
+ type: Input
1901
+ }], _ngModelChange: [{
1902
+ type: Output
1903
+ }], onclickClearIcon: [{
1904
+ type: Output
1905
+ }], onenter: [{
1906
+ type: Output
1907
+ }], inputElement: [{
1908
+ type: ViewChild,
1909
+ args: ['inputElement']
1910
+ }] } });
1911
+
1912
+ class ExtendSelectComponent {
1913
+ layOutType = 'horizontal';
1914
+ label = '';
1915
+ placeHolder = '';
1916
+ labelAlign = 'left';
1917
+ /**
1918
+ * default = 8
1919
+ */
1920
+ labelSpan = 8;
1921
+ disabled = false;
1922
+ required = false;
1923
+ noBottom = false;
1924
+ multiple = false;
1925
+ showSelectAll = false;
1926
+ maxTagCount = 10;
1927
+ inputWidth = '';
1928
+ inputHeight = '';
1929
+ borderBottomOnly = false;
1930
+ /**
1931
+ *
1932
+ */
1933
+ displayInline = false;
1934
+ size = 'default';
1935
+ lstItem = [];
1936
+ displayField = '';
1937
+ displayFields = [];
1938
+ valueField = '';
1939
+ formData;
1940
+ controlName;
1941
+ _ngModel = null;
1942
+ _ngModelChange = new EventEmitter();
1943
+ onFocus = new EventEmitter();
1944
+ get cssHeight() {
1945
+ return this.inputHeight ? +this.inputHeight.replaceAll('px', '') - 1 + 'px' : null;
1946
+ }
1947
+ ngOnInit() { }
1948
+ getDisplay(item) {
1949
+ if (this.displayField) {
1950
+ return item[this.displayField];
1951
+ }
1952
+ if (this.displayFields?.length) {
1953
+ const display = this.displayFields.map((field) => item[field]).join(' - ');
1954
+ return display;
1955
+ }
1956
+ return item;
1957
+ }
1958
+ onSelectChange(val) {
1959
+ if (val instanceof Array && val.find((x) => x == '__all__')) {
1960
+ const allIds = this.lstItem.map((x) => (this.valueField ? x[this.valueField] : x));
1961
+ val = allIds;
1962
+ }
1963
+ this._ngModel = val;
1964
+ this._ngModelChange.emit(val);
1965
+ }
1966
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1967
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: ExtendSelectComponent, isStandalone: true, selector: "extend-select", inputs: { layOutType: "layOutType", label: "label", placeHolder: "placeHolder", labelAlign: "labelAlign", labelSpan: "labelSpan", disabled: "disabled", required: "required", noBottom: "noBottom", multiple: "multiple", showSelectAll: "showSelectAll", maxTagCount: "maxTagCount", inputWidth: "inputWidth", inputHeight: "inputHeight", borderBottomOnly: "borderBottomOnly", displayInline: "displayInline", size: "size", lstItem: "lstItem", displayField: "displayField", displayFields: "displayFields", valueField: "valueField", formData: "formData", controlName: "controlName", _ngModel: "_ngModel" }, outputs: { _ngModelChange: "_ngModelChange", onFocus: "onFocus" }, host: { properties: { "style.--custom-select-height": "this.cssHeight" } }, ngImport: i0, template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (!multiple) {\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [formControlName]=\"controlName\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <nz-select\n class=\"full-width\"\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzPlaceHolder]=\"placeHolder\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n [disabled]=\"disabled\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n 'custom-height-select': inputHeight ? true : false,\n }\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n }\n }\n } @else {\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzMode]=\"'multiple'\"\n [nzMaxMultipleCount]=\"lstItem.length\"\n [nzMaxTagCount]=\"maxTagCount\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [formControlName]=\"controlName\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzMode]=\"'multiple'\"\n [nzMaxMultipleCount]=\"lstItem.length\"\n [nzMaxTagCount]=\"maxTagCount\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <nz-select\n class=\"full-width\"\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzPlaceHolder]=\"placeHolder\"\n [nzMode]=\"'multiple'\"\n [nzMaxMultipleCount]=\"lstItem.length\"\n [nzMaxTagCount]=\"maxTagCount\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n }\n }\n }\n</div>\n", styles: [":host ::ng-deep .ant-select-selector{height:var(--custom-select-height)!important;line-height:var(--custom-select-height)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "component", type: i5.NzFormItemComponent, selector: "nz-form-item", exportAs: ["nzFormItem"] }, { kind: "component", type: i5.NzFormLabelComponent, selector: "nz-form-label", inputs: ["nzFor", "nzRequired", "nzNoColon", "nzTooltipTitle", "nzTooltipIcon", "nzLabelAlign", "nzLabelWrap"], exportAs: ["nzFormLabel"] }, { kind: "component", type: i5.NzFormControlComponent, selector: "nz-form-control", inputs: ["nzSuccessTip", "nzWarningTip", "nzErrorTip", "nzValidatingTip", "nzExtra", "nzAutoTips", "nzDisableAutoTips", "nzHasFeedback", "nzValidateStatus"], exportAs: ["nzFormControl"] }, { kind: "ngmodule", type: NzSelectModule }, { kind: "component", type: i6$2.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i6$2.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzBorderless", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus"], exportAs: ["nzSelect"] }] });
1968
+ }
1969
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendSelectComponent, decorators: [{
1970
+ type: Component,
1971
+ args: [{ selector: 'extend-select', imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, NzFormModule, NzSelectModule], template: "<div class=\"extend-wrapper\" [ngStyle]=\"{ display: displayInline ? 'inline' : null }\">\n @if (!multiple) {\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [formControlName]=\"controlName\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <nz-select\n class=\"full-width\"\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzPlaceHolder]=\"placeHolder\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n [disabled]=\"disabled\"\n [ngStyle]=\"{\n width: inputWidth,\n height: inputHeight,\n }\"\n [ngClass]=\"{\n 'border-bottom-only': borderBottomOnly,\n 'custom-height-select': inputHeight ? true : false,\n }\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n }\n }\n } @else {\n @if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzMode]=\"'multiple'\"\n [nzMaxMultipleCount]=\"lstItem.length\"\n [nzMaxTagCount]=\"maxTagCount\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [formControlName]=\"controlName\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n </div>\n } @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [nzSpan]=\"layOutType == 'horizontal' ? 24 - labelSpan : null\"\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <nz-select\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzMode]=\"'multiple'\"\n [nzMaxMultipleCount]=\"lstItem.length\"\n [nzMaxTagCount]=\"maxTagCount\"\n [nzAllowClear]=\"true\"\n [nzShowSearch]=\"true\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <nz-select\n class=\"full-width\"\n nzShowSearch\n nzAllowClear\n [nzSize]=\"size\"\n [nzPlaceHolder]=\"placeHolder\"\n [nzMode]=\"'multiple'\"\n [nzMaxMultipleCount]=\"lstItem.length\"\n [nzMaxTagCount]=\"maxTagCount\"\n [nzDropdownMatchSelectWidth]=\"false\"\n [ngModel]=\"_ngModel\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectChange($event)\"\n (nzFocus)=\"onFocus.emit()\"\n >\n @if (showSelectAll) {\n <nz-option [nzLabel]=\"'-- Ch\u1ECDn t\u1EA5t c\u1EA3 --'\" [nzValue]=\"'__all__'\"></nz-option>\n }\n @for (item of lstItem; track $index) {\n <nz-option [nzLabel]=\"getDisplay(item)\" [nzValue]=\"valueField ? item[valueField] : item\"></nz-option>\n }\n </nz-select>\n }\n }\n }\n</div>\n", styles: [":host ::ng-deep .ant-select-selector{height:var(--custom-select-height)!important;line-height:var(--custom-select-height)!important}\n"] }]
1972
+ }], propDecorators: { layOutType: [{
1973
+ type: Input
1974
+ }], label: [{
1975
+ type: Input
1976
+ }], placeHolder: [{
1977
+ type: Input
1978
+ }], labelAlign: [{
1979
+ type: Input
1980
+ }], labelSpan: [{
1981
+ type: Input
1982
+ }], disabled: [{
1983
+ type: Input
1984
+ }], required: [{
1985
+ type: Input
1986
+ }], noBottom: [{
1987
+ type: Input
1988
+ }], multiple: [{
1989
+ type: Input
1990
+ }], showSelectAll: [{
1991
+ type: Input
1992
+ }], maxTagCount: [{
1993
+ type: Input
1994
+ }], inputWidth: [{
1995
+ type: Input
1996
+ }], inputHeight: [{
1997
+ type: Input
1998
+ }], borderBottomOnly: [{
1999
+ type: Input
2000
+ }], displayInline: [{
2001
+ type: Input
2002
+ }], size: [{
2003
+ type: Input
2004
+ }], lstItem: [{
2005
+ type: Input
2006
+ }], displayField: [{
2007
+ type: Input
2008
+ }], displayFields: [{
2009
+ type: Input
2010
+ }], valueField: [{
2011
+ type: Input
2012
+ }], formData: [{
2013
+ type: Input
2014
+ }], controlName: [{
2015
+ type: Input
2016
+ }], _ngModel: [{
2017
+ type: Input
2018
+ }], _ngModelChange: [{
2019
+ type: Output
2020
+ }], onFocus: [{
2021
+ type: Output
2022
+ }], cssHeight: [{
2023
+ type: HostBinding,
2024
+ args: ['style.--custom-select-height']
2025
+ }] } });
2026
+
2027
+ class ExtendTextArea {
2028
+ layOutType = 'horizontal';
2029
+ label = '';
2030
+ placeHolder = '';
2031
+ labelAlign = 'left';
2032
+ labelSpan = 8;
2033
+ inputSpan = 16;
2034
+ disabled = false;
2035
+ required = false;
2036
+ noBottom = false;
2037
+ selectModeType = 'default';
2038
+ inputClass = '';
2039
+ minRows = 3;
2040
+ maxRows = 5;
2041
+ autoSize = false;
2042
+ lstItem = [];
2043
+ displayField = '';
2044
+ valueField = '';
2045
+ formData;
2046
+ controlName;
2047
+ _ngModel = null;
2048
+ _ngModelChange = new EventEmitter();
2049
+ ngAfterViewInit() { }
2050
+ onChange() {
2051
+ this._ngModelChange.emit(this._ngModel);
2052
+ }
2053
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendTextArea, deps: [], target: i0.ɵɵFactoryTarget.Component });
2054
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: ExtendTextArea, isStandalone: true, selector: "extend-textarea", inputs: { layOutType: "layOutType", label: "label", placeHolder: "placeHolder", labelAlign: "labelAlign", labelSpan: "labelSpan", inputSpan: "inputSpan", disabled: "disabled", required: "required", noBottom: "noBottom", selectModeType: "selectModeType", inputClass: "inputClass", minRows: "minRows", maxRows: "maxRows", autoSize: "autoSize", lstItem: "lstItem", displayField: "displayField", valueField: "valueField", formData: "formData", controlName: "controlName", _ngModel: "_ngModel" }, outputs: { _ngModelChange: "_ngModelChange" }, ngImport: i0, template: "@if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <textarea\n nz-input\n [nzAutosize]=\"autoSize || { minRows: minRows, maxRows: maxRows }\"\n [formControlName]=\"controlName\"\n [ngClass]=\"inputClass\"\n ></textarea>\n </nz-form-control>\n </nz-form-item>\n </div>\n} @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <textarea\n nz-input\n [nzAutosize]=\"autoSize || { minRows: minRows, maxRows: maxRows }\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onChange()\"\n [disabled]=\"disabled\"\n [ngClass]=\"inputClass\"\n ></textarea>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <textarea\n nz-input\n [nzAutosize]=\"autoSize || { minRows: minRows, maxRows: maxRows }\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onChange()\"\n [disabled]=\"disabled\"\n [ngClass]=\"inputClass\"\n ></textarea>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "component", type: i5.NzFormItemComponent, selector: "nz-form-item", exportAs: ["nzFormItem"] }, { kind: "component", type: i5.NzFormLabelComponent, selector: "nz-form-label", inputs: ["nzFor", "nzRequired", "nzNoColon", "nzTooltipTitle", "nzTooltipIcon", "nzLabelAlign", "nzLabelWrap"], exportAs: ["nzFormLabel"] }, { kind: "component", type: i5.NzFormControlComponent, selector: "nz-form-control", inputs: ["nzSuccessTip", "nzWarningTip", "nzErrorTip", "nzValidatingTip", "nzExtra", "nzAutoTips", "nzDisableAutoTips", "nzHasFeedback", "nzValidateStatus"], exportAs: ["nzFormControl"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i6$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "directive", type: i6$1.NzAutosizeDirective, selector: "textarea[nzAutosize]", inputs: ["nzAutosize"], exportAs: ["nzAutosize"] }] });
2055
+ }
2056
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ExtendTextArea, decorators: [{
2057
+ type: Component,
2058
+ args: [{ selector: 'extend-textarea', imports: [
2059
+ CommonModule,
2060
+ FormsModule,
2061
+ ReactiveFormsModule,
2062
+ NzFormModule,
2063
+ NzDatePickerModule,
2064
+ TranslateModule,
2065
+ NzInputModule,
2066
+ ], template: "@if (controlName) {\n <div [formGroup]=\"formData\">\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <textarea\n nz-input\n [nzAutosize]=\"autoSize || { minRows: minRows, maxRows: maxRows }\"\n [formControlName]=\"controlName\"\n [ngClass]=\"inputClass\"\n ></textarea>\n </nz-form-control>\n </nz-form-item>\n </div>\n} @else {\n @if (label) {\n <nz-form-item>\n <nz-form-label\n [nzSpan]=\"layOutType == 'horizontal' ? labelSpan : null\"\n [nzLabelAlign]=\"labelAlign\"\n [nzRequired]=\"required\"\n [nzFor]=\"controlName\"\n nzNoColon\n nzLabelWrap\n >\n {{ label }}\n </nz-form-label>\n <nz-form-control\n [ngClass]=\"{ 'full-width': layOutType == 'vertical' }\"\n [nzErrorTip]=\"'REQUIRED_FIELD' | translate\"\n >\n <textarea\n nz-input\n [nzAutosize]=\"autoSize || { minRows: minRows, maxRows: maxRows }\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onChange()\"\n [disabled]=\"disabled\"\n [ngClass]=\"inputClass\"\n ></textarea>\n </nz-form-control>\n </nz-form-item>\n } @else {\n <textarea\n nz-input\n [nzAutosize]=\"autoSize || { minRows: minRows, maxRows: maxRows }\"\n [(ngModel)]=\"_ngModel\"\n (ngModelChange)=\"onChange()\"\n [disabled]=\"disabled\"\n [ngClass]=\"inputClass\"\n ></textarea>\n }\n}\n" }]
2067
+ }], propDecorators: { layOutType: [{
2068
+ type: Input
2069
+ }], label: [{
2070
+ type: Input
2071
+ }], placeHolder: [{
2072
+ type: Input
2073
+ }], labelAlign: [{
2074
+ type: Input
2075
+ }], labelSpan: [{
2076
+ type: Input
2077
+ }], inputSpan: [{
2078
+ type: Input
2079
+ }], disabled: [{
2080
+ type: Input
2081
+ }], required: [{
2082
+ type: Input
2083
+ }], noBottom: [{
2084
+ type: Input
2085
+ }], selectModeType: [{
2086
+ type: Input
2087
+ }], inputClass: [{
2088
+ type: Input
2089
+ }], minRows: [{
2090
+ type: Input
2091
+ }], maxRows: [{
2092
+ type: Input
2093
+ }], autoSize: [{
2094
+ type: Input
2095
+ }], lstItem: [{
2096
+ type: Input
2097
+ }], displayField: [{
2098
+ type: Input
2099
+ }], valueField: [{
2100
+ type: Input
2101
+ }], formData: [{
2102
+ type: Input
2103
+ }], controlName: [{
2104
+ type: Input
2105
+ }], _ngModel: [{
2106
+ type: Input
2107
+ }], _ngModelChange: [{
2108
+ type: Output
2109
+ }] } });
2110
+
2111
+ class NoPermission {
2112
+ router;
2113
+ deniedUrl = null;
2114
+ message = null;
2115
+ constructor(router) {
2116
+ this.router = router;
2117
+ }
2118
+ ngOnInit() {
2119
+ const state = history.state;
2120
+ this.deniedUrl = state?.deniedUrl || null;
2121
+ this.message = state?.message || null;
2122
+ console.log('Lấy từ history.state:', state);
2123
+ }
2124
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NoPermission, deps: [{ token: i1$3.Router }], target: i0.ɵɵFactoryTarget.Component });
2125
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: NoPermission, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
2126
+ <h2>Không có quyền truy cập</h2>
2127
+ <p *ngIf="message">{{ message }}</p>
2128
+ <p *ngIf="deniedUrl">
2129
+ Bạn đã cố gắng truy cập: <strong>{{ deniedUrl }}</strong>
2130
+ </p>
2131
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
2132
+ }
2133
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NoPermission, decorators: [{
2134
+ type: Component,
2135
+ args: [{
2136
+ template: `
2137
+ <h2>Không có quyền truy cập</h2>
2138
+ <p *ngIf="message">{{ message }}</p>
2139
+ <p *ngIf="deniedUrl">
2140
+ Bạn đã cố gắng truy cập: <strong>{{ deniedUrl }}</strong>
2141
+ </p>
2142
+ `,
2143
+ imports: [CommonModule],
2144
+ }]
2145
+ }], ctorParameters: () => [{ type: i1$3.Router }] });
2146
+
2147
+ class PdfViewerComponent {
2148
+ // data = inject(NZ_MODAL_DATA);
2149
+ dataType = null;
2150
+ pdfData;
2151
+ ngOnInit() {
2152
+ // this.dataType = this.data.dataType;
2153
+ // this.pdfData = this.data.pdfData;
2154
+ // this.showPrintButton = this.data.showPrintButton;
2155
+ }
2156
+ print() {
2157
+ if (this.dataType == 'base64') {
2158
+ const byteCharacters = atob(this.pdfData);
2159
+ const byteNumbers = new Array(byteCharacters.length).fill(0).map((_, i) => byteCharacters.charCodeAt(i));
2160
+ const byteArray = new Uint8Array(byteNumbers);
2161
+ const blob = new Blob([byteArray], { type: 'application/pdf' });
2162
+ const blobUrl = window.URL.createObjectURL(blob);
2163
+ const iframe = document.createElement('iframe');
2164
+ iframe.style.display = 'none';
2165
+ iframe.src = blobUrl;
2166
+ document.body.appendChild(iframe);
2167
+ iframe.contentWindow?.print();
2168
+ }
2169
+ else if (this.dataType == 'bytes') {
2170
+ const blob = new Blob([this.pdfData], { type: 'application/pdf' });
2171
+ const blobUrl = window.URL.createObjectURL(blob);
2172
+ const iframe = document.createElement('iframe');
2173
+ iframe.style.display = 'none';
2174
+ iframe.src = blobUrl;
2175
+ document.body.appendChild(iframe);
2176
+ iframe.contentWindow?.print();
2177
+ }
2178
+ }
2179
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: PdfViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2180
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: PdfViewerComponent, isStandalone: true, selector: "pdf-viewer", inputs: { dataType: "dataType", pdfData: "pdfData" }, ngImport: i0, template: "@if (dataType == \"base64\") {\n <ngx-extended-pdf-viewer\n [zoom]=\"100\"\n [base64Src]=\"this.pdfData\"\n [showPrintButton]=\"false\"\n [showOpenFileButton]=\"false\"\n [showDownloadButton]=\"false\"\n ></ngx-extended-pdf-viewer>\n}\n\n@if (dataType == \"bytes\") {\n <ngx-extended-pdf-viewer\n [zoom]=\"100\"\n [src]=\"this.pdfData\"\n [showPrintButton]=\"false\"\n [showOpenFileButton]=\"false\"\n [showDownloadButton]=\"false\"\n ></ngx-extended-pdf-viewer>\n}\n", dependencies: [{ kind: "ngmodule", type: NgxExtendedPdfViewerModule }, { kind: "component", type: i1$4.NgxExtendedPdfViewerComponent, selector: "ngx-extended-pdf-viewer", inputs: ["customFindbarInputArea", "customToolbar", "customFindbar", "customFindbarButtons", "customPdfViewer", "customSecondaryToolbar", "customSidebar", "customThumbnail", "customFreeFloatingBar", "showFreeFloatingBar", "enableDragAndDrop", "forceUsingLegacyES5", "formData", "disableForms", "pageViewMode", "scrollMode", "authorization", "httpHeaders", "contextMenuAllowed", "enablePrint", "enablePrintAutoRotate", "forceFullReloadOfJavaScriptCode", "showTextEditor", "showStampEditor", "showDrawEditor", "showHighlightEditor", "logLevel", "relativeCoordsOptions", "minifiedJSLibraries", "printResolution", "rotation", "src", "base64Src", "minHeight", "height", "backgroundColor", "filenameForDownload", "ignoreKeyboard", "ignoreKeys", "acceptKeys", "imageResourcesPath", "localeFolderPath", "language", "listenToURL", "nameddest", "password", "replaceBrowserPrint", "useInlineScripts", "showUnverifiedSignatures", "startTabindex", "showSidebarButton", "sidebarVisible", "activeSidebarView", "findbarVisible", "propertiesDialogVisible", "showFindButton", "showFindHighlightAll", "showFindMatchCase", "showFindMultiple", "showFindRegexp", "showFindEntireWord", "showFindMatchDiacritics", "showFindResultsCount", "showFindMessages", "showPagingButtons", "showFirstAndLastPageButtons", "showPreviousAndNextPageButtons", "showPageNumber", "showPageLabel", "showZoomButtons", "showZoomDropdown", "showPresentationModeButton", "showOpenFileButton", "showPrintButton", "showDownloadButton", "theme", "showToolbar", "showSecondaryToolbarButton", "showSinglePageModeButton", "showVerticalScrollButton", "showHorizontalScrollButton", "showWrappedScrollButton", "showInfiniteScrollButton", "showBookModeButton", "showRotateButton", "showRotateCwButton", "showRotateCcwButton", "handTool", "showHandToolButton", "showSpreadButton", "showPropertiesButton", "showBorders", "spread", "showScrollingButtons", "page", "pageLabel", "textLayer", "zoom", "zoomLevels", "maxZoom", "minZoom", "mobileFriendlyZoom"], outputs: ["annotationEditorEvent", "formDataChange", "pageViewModeChange", "progress", "srcChange", "scrollModeChange", "afterPrint", "beforePrint", "currentZoomFactor", "rotationChange", "annotationLayerRendered", "annotationEditorLayerRendered", "xfaLayerRendered", "outlineLoaded", "attachmentsloaded", "layersloaded", "sidebarVisibleChange", "activeSidebarViewChange", "findbarVisibleChange", "propertiesDialogVisibleChange", "handToolChange", "spreadChange", "thumbnailDrawn", "pageChange", "pageLabelChange", "pagesLoaded", "pageRender", "pageRendered", "pdfDownloaded", "pdfLoaded", "pdfLoadingStarts", "pdfLoadingFailed", "textLayerRendered", "annotationEditorModeChanged", "updateFindMatchesCount", "updateFindState", "zoomChange"] }] });
2181
+ }
2182
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: PdfViewerComponent, decorators: [{
2183
+ type: Component,
2184
+ args: [{ selector: 'pdf-viewer', imports: [NgxExtendedPdfViewerModule], template: "@if (dataType == \"base64\") {\n <ngx-extended-pdf-viewer\n [zoom]=\"100\"\n [base64Src]=\"this.pdfData\"\n [showPrintButton]=\"false\"\n [showOpenFileButton]=\"false\"\n [showDownloadButton]=\"false\"\n ></ngx-extended-pdf-viewer>\n}\n\n@if (dataType == \"bytes\") {\n <ngx-extended-pdf-viewer\n [zoom]=\"100\"\n [src]=\"this.pdfData\"\n [showPrintButton]=\"false\"\n [showOpenFileButton]=\"false\"\n [showDownloadButton]=\"false\"\n ></ngx-extended-pdf-viewer>\n}\n" }]
2185
+ }], propDecorators: { dataType: [{
2186
+ type: Input
2187
+ }], pdfData: [{
2188
+ type: Input
2189
+ }] } });
2190
+
2191
+ // global-spinner.component.ts
2192
+ class GlobalSpinnerComponent {
2193
+ loadingService;
2194
+ visible = false;
2195
+ sub;
2196
+ constructor(loadingService) {
2197
+ this.loadingService = loadingService;
2198
+ }
2199
+ ngOnInit() {
2200
+ this.sub = this.loadingService.loading$.subscribe((v) => {
2201
+ this.visible = v;
2202
+ });
2203
+ }
2204
+ ngOnDestroy() {
2205
+ this.sub.unsubscribe();
2206
+ }
2207
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: GlobalSpinnerComponent, deps: [{ token: LoadingService }], target: i0.ɵɵFactoryTarget.Component });
2208
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: GlobalSpinnerComponent, isStandalone: true, selector: "app-global-spinner", ngImport: i0, template: `
2209
+ @if (visible) {
2210
+ <div class="global-spinner" [@fadeInOut]>
2211
+ <nz-spin [nzSpinning]="true" style="position: relative; bottom: 50px;"></nz-spin>
2212
+ </div>
2213
+ }
2214
+ `, isInline: true, styles: [".global-spinner{position:fixed;z-index:1200;top:50px;left:0;width:100vw;height:100vh;background-color:#fffc;display:flex;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "ngmodule", type: NzSpinModule }, { kind: "component", type: i2$3.NzSpinComponent, selector: "nz-spin", inputs: ["nzIndicator", "nzSize", "nzTip", "nzDelay", "nzSimple", "nzSpinning"], exportAs: ["nzSpin"] }], animations: [
2215
+ trigger('fadeInOut', [
2216
+ // transition(':enter', [style({ opacity: 0 }), animate('250ms ease-in', style({ opacity: 1 }))]),
2217
+ transition(':leave', [animate('250ms ease-out', style({ opacity: 0 }))]),
2218
+ ]),
2219
+ ] });
2220
+ }
2221
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: GlobalSpinnerComponent, decorators: [{
2222
+ type: Component,
2223
+ args: [{ selector: 'app-global-spinner', template: `
2224
+ @if (visible) {
2225
+ <div class="global-spinner" [@fadeInOut]>
2226
+ <nz-spin [nzSpinning]="true" style="position: relative; bottom: 50px;"></nz-spin>
2227
+ </div>
2228
+ }
2229
+ `, animations: [
2230
+ trigger('fadeInOut', [
2231
+ // transition(':enter', [style({ opacity: 0 }), animate('250ms ease-in', style({ opacity: 1 }))]),
2232
+ transition(':leave', [animate('250ms ease-out', style({ opacity: 0 }))]),
2233
+ ]),
2234
+ ], imports: [NzSpinModule], styles: [".global-spinner{position:fixed;z-index:1200;top:50px;left:0;width:100vw;height:100vh;background-color:#fffc;display:flex;align-items:center;justify-content:center}\n"] }]
2235
+ }], ctorParameters: () => [{ type: LoadingService }] });
2236
+
2237
+ class Height {
2238
+ height = 0;
2239
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Height, deps: [], target: i0.ɵɵFactoryTarget.Component });
2240
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: Height, isStandalone: true, selector: "height", inputs: { height: "height" }, ngImport: i0, template: `<div [ngStyle]="{ height: height + 'px' }"></div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
2241
+ }
2242
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Height, decorators: [{
2243
+ type: Component,
2244
+ args: [{
2245
+ selector: 'height',
2246
+ template: `<div [ngStyle]="{ height: height + 'px' }"></div>`,
2247
+ imports: [CommonModule],
2248
+ }]
2249
+ }], propDecorators: { height: [{
2250
+ type: Input
2251
+ }] } });
2252
+
2253
+ class Width {
2254
+ width = 0;
2255
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Width, deps: [], target: i0.ɵɵFactoryTarget.Component });
2256
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: Width, isStandalone: true, selector: "width", inputs: { width: "width" }, ngImport: i0, template: `<div style="display: inline" [ngStyle]="{ 'padding-left': width + 'px' }"></div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
2257
+ }
2258
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Width, decorators: [{
2259
+ type: Component,
2260
+ args: [{
2261
+ selector: 'width',
2262
+ template: `<div style="display: inline" [ngStyle]="{ 'padding-left': width + 'px' }"></div>`,
2263
+ imports: [CommonModule],
2264
+ }]
2265
+ }], propDecorators: { width: [{
2266
+ type: Input
2267
+ }] } });
2268
+
2269
+ class Box {
2270
+ display = '';
2271
+ width = 0;
2272
+ height = 0;
2273
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Box, deps: [], target: i0.ɵɵFactoryTarget.Component });
2274
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: Box, isStandalone: true, selector: "box", inputs: { display: "display", width: "width", height: "height" }, ngImport: i0, template: `<div
2275
+ [ngStyle]="{
2276
+ height: height + 'px',
2277
+ 'padding-left': width + 'px',
2278
+ display: display ? display : width && height ? 'block' : height ? 'block' : width ? 'inline' : display,
2279
+ }"
2280
+ ></div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
2281
+ }
2282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: Box, decorators: [{
2283
+ type: Component,
2284
+ args: [{
2285
+ selector: 'box',
2286
+ template: `<div
2287
+ [ngStyle]="{
2288
+ height: height + 'px',
2289
+ 'padding-left': width + 'px',
2290
+ display: display ? display : width && height ? 'block' : height ? 'block' : width ? 'inline' : display,
2291
+ }"
2292
+ ></div>`,
2293
+ imports: [CommonModule],
2294
+ }]
2295
+ }], propDecorators: { display: [{
2296
+ type: Input
2297
+ }], width: [{
2298
+ type: Input
2299
+ }], height: [{
2300
+ type: Input
2301
+ }] } });
2302
+
2303
+ class AutoFocusDirective {
2304
+ el;
2305
+ renderer;
2306
+ appAutoFocus = false;
2307
+ constructor(el, renderer) {
2308
+ this.el = el;
2309
+ this.renderer = renderer;
2310
+ }
2311
+ ngOnChanges(changes) {
2312
+ if (changes['appAutoFocus'] && this.appAutoFocus) {
2313
+ setTimeout(() => this.el.nativeElement.focus(), 0);
2314
+ }
2315
+ }
2316
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AutoFocusDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
2317
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.7", type: AutoFocusDirective, isStandalone: true, selector: "[appAutoFocus]", inputs: { appAutoFocus: "appAutoFocus" }, usesOnChanges: true, ngImport: i0 });
2318
+ }
2319
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AutoFocusDirective, decorators: [{
2320
+ type: Directive,
2321
+ args: [{
2322
+ selector: '[appAutoFocus]'
2323
+ }]
2324
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { appAutoFocus: [{
2325
+ type: Input
2326
+ }] } });
2327
+
2328
+ class NullIfEmptyDirective {
2329
+ el;
2330
+ ngControl;
2331
+ constructor(el, ngControl) {
2332
+ this.el = el;
2333
+ this.ngControl = ngControl;
2334
+ }
2335
+ onInput() {
2336
+ // const value = this.el.nativeElement.value;
2337
+ // const newValue = value.trim() === '' ? null : value;
2338
+ // this.ngControl?.control?.setValue(newValue, { emitEvent: false });
2339
+ }
2340
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NullIfEmptyDirective, deps: [{ token: i0.ElementRef }, { token: i2$2.NgControl, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
2341
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.7", type: NullIfEmptyDirective, isStandalone: true, selector: "input", host: { listeners: { "input": "onInput()" } }, ngImport: i0 });
2342
+ }
2343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NullIfEmptyDirective, decorators: [{
2344
+ type: Directive,
2345
+ args: [{
2346
+ selector: 'input',
2347
+ }]
2348
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i2$2.NgControl, decorators: [{
2349
+ type: Optional
2350
+ }] }], propDecorators: { onInput: [{
2351
+ type: HostListener,
2352
+ args: ['input']
2353
+ }] } });
2354
+
2355
+ class NumberOnlyDirective {
2356
+ el;
2357
+ renderer;
2358
+ onChange = (value) => { };
2359
+ onTouched = () => { };
2360
+ constructor(el, renderer) {
2361
+ this.el = el;
2362
+ this.renderer = renderer;
2363
+ }
2364
+ onInput(value) {
2365
+ const formattedValue = this.formatValue(value);
2366
+ this.renderer.setProperty(this.el.nativeElement, 'value', formattedValue);
2367
+ if (this.onChange) {
2368
+ this.onChange(formattedValue);
2369
+ }
2370
+ }
2371
+ writeValue(value) {
2372
+ const formattedValue = value ? this.formatValue(value) : '';
2373
+ this.renderer.setProperty(this.el.nativeElement, 'value', formattedValue);
2374
+ }
2375
+ registerOnChange(fn) {
2376
+ this.onChange = fn;
2377
+ }
2378
+ registerOnTouched(fn) {
2379
+ this.onTouched = fn;
2380
+ }
2381
+ setDisabledState(isDisabled) {
2382
+ this.renderer.setProperty(this.el.nativeElement, 'disabled', isDisabled);
2383
+ }
2384
+ formatValue(value) {
2385
+ return value.replace(/\D/g, '');
2386
+ }
2387
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NumberOnlyDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
2388
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.7", type: NumberOnlyDirective, isStandalone: true, selector: "[numberOnly]", host: { listeners: { "input": "onInput($event.target.value)" } }, providers: [
2389
+ {
2390
+ provide: NG_VALUE_ACCESSOR,
2391
+ useExisting: forwardRef(() => NumberOnlyDirective),
2392
+ multi: true,
2393
+ },
2394
+ ], ngImport: i0 });
2395
+ }
2396
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: NumberOnlyDirective, decorators: [{
2397
+ type: Directive,
2398
+ args: [{
2399
+ selector: '[numberOnly]',
2400
+ providers: [
2401
+ {
2402
+ provide: NG_VALUE_ACCESSOR,
2403
+ useExisting: forwardRef(() => NumberOnlyDirective),
2404
+ multi: true,
2405
+ },
2406
+ ],
2407
+ }]
2408
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { onInput: [{
2409
+ type: HostListener,
2410
+ args: ['input', ['$event.target.value']]
2411
+ }] } });
2412
+
2413
+ class UpperCaseFirsLetterEachWordDirective {
2414
+ el;
2415
+ renderer;
2416
+ inputElement = null;
2417
+ constructor(el, renderer) {
2418
+ this.el = el;
2419
+ this.renderer = renderer;
2420
+ }
2421
+ ngAfterViewInit() {
2422
+ setTimeout(() => {
2423
+ // Nếu gắn vào <input>, thì chính nó là input
2424
+ if (this.el.nativeElement.tagName.toLowerCase() === 'input') {
2425
+ this.inputElement = this.el.nativeElement;
2426
+ }
2427
+ else {
2428
+ // Nếu không, tìm input con bên trong
2429
+ this.inputElement = this.el.nativeElement.querySelector('input');
2430
+ }
2431
+ if (this.inputElement) {
2432
+ this.renderer.listen(this.inputElement, 'input', (event) => {
2433
+ const formatted = this.formatValue(event.target.value);
2434
+ this.renderer.setProperty(this.inputElement, 'value', formatted);
2435
+ this.onChange(formatted);
2436
+ });
2437
+ }
2438
+ if (this.pendingValue !== null) {
2439
+ this.renderer.setProperty(this.inputElement, 'value', this.pendingValue);
2440
+ this.pendingValue = null;
2441
+ }
2442
+ }, 0);
2443
+ }
2444
+ pendingValue = null;
2445
+ writeValue(value) {
2446
+ const formattedValue = value ? this.formatValue(value) : '';
2447
+ if (this.inputElement) {
2448
+ this.renderer.setProperty(this.inputElement, 'value', formattedValue);
2449
+ }
2450
+ else {
2451
+ this.pendingValue = formattedValue;
2452
+ }
2453
+ }
2454
+ onChange = (_) => { };
2455
+ onTouched = () => { };
2456
+ registerOnChange(fn) {
2457
+ this.onChange = fn;
2458
+ }
2459
+ registerOnTouched(fn) {
2460
+ this.onTouched = fn;
2461
+ }
2462
+ setDisabledState(isDisabled) {
2463
+ if (this.inputElement) {
2464
+ this.renderer.setProperty(this.inputElement, 'disabled', isDisabled);
2465
+ }
2466
+ }
2467
+ formatValue(value) {
2468
+ return value
2469
+ .split(' ')
2470
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
2471
+ .join(' ');
2472
+ }
2473
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UpperCaseFirsLetterEachWordDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
2474
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.7", type: UpperCaseFirsLetterEachWordDirective, isStandalone: true, selector: "[uppercaseFirstLetterEachWord]", providers: [
2475
+ {
2476
+ provide: NG_VALUE_ACCESSOR,
2477
+ useExisting: forwardRef(() => UpperCaseFirsLetterEachWordDirective),
2478
+ multi: true,
2479
+ },
2480
+ ], ngImport: i0 });
2481
+ }
2482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UpperCaseFirsLetterEachWordDirective, decorators: [{
2483
+ type: Directive,
2484
+ args: [{
2485
+ selector: '[uppercaseFirstLetterEachWord]',
2486
+ providers: [
2487
+ {
2488
+ provide: NG_VALUE_ACCESSOR,
2489
+ useExisting: forwardRef(() => UpperCaseFirsLetterEachWordDirective),
2490
+ multi: true,
2491
+ },
2492
+ ],
2493
+ }]
2494
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }] });
2495
+
2496
+ class UppercaseFirstLetterDirective {
2497
+ el;
2498
+ renderer;
2499
+ onChange = (value) => { };
2500
+ onTouched = () => { };
2501
+ constructor(el, renderer) {
2502
+ this.el = el;
2503
+ this.renderer = renderer;
2504
+ }
2505
+ onInput(value) {
2506
+ const formattedValue = this.formatValue(value);
2507
+ this.renderer.setProperty(this.el.nativeElement, 'value', formattedValue);
2508
+ if (this.onChange) {
2509
+ this.onChange(formattedValue);
2510
+ }
2511
+ }
2512
+ writeValue(value) {
2513
+ const formattedValue = value ? this.formatValue(value) : '';
2514
+ this.renderer.setProperty(this.el.nativeElement, 'value', formattedValue);
2515
+ }
2516
+ registerOnChange(fn) {
2517
+ this.onChange = fn;
2518
+ }
2519
+ registerOnTouched(fn) {
2520
+ this.onTouched = fn;
2521
+ }
2522
+ setDisabledState(isDisabled) {
2523
+ this.renderer.setProperty(this.el.nativeElement, 'disabled', isDisabled);
2524
+ }
2525
+ formatValue(value) {
2526
+ const ls = value.split('');
2527
+ ls[0] = ls[0].toUpperCase();
2528
+ return ls.join('');
2529
+ }
2530
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UppercaseFirstLetterDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
2531
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.7", type: UppercaseFirstLetterDirective, isStandalone: true, selector: "[uppercaseFirstLetter]", host: { listeners: { "input": "onInput($event.target.value)" } }, providers: [
2532
+ {
2533
+ provide: NG_VALUE_ACCESSOR,
2534
+ useExisting: forwardRef(() => UppercaseFirstLetterDirective),
2535
+ multi: true,
2536
+ },
2537
+ ], ngImport: i0 });
2538
+ }
2539
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UppercaseFirstLetterDirective, decorators: [{
2540
+ type: Directive,
2541
+ args: [{
2542
+ selector: '[uppercaseFirstLetter]',
2543
+ providers: [
2544
+ {
2545
+ provide: NG_VALUE_ACCESSOR,
2546
+ useExisting: forwardRef(() => UppercaseFirstLetterDirective),
2547
+ multi: true,
2548
+ },
2549
+ ],
2550
+ }]
2551
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { onInput: [{
2552
+ type: HostListener,
2553
+ args: ['input', ['$event.target.value']]
2554
+ }] } });
2555
+
2556
+ class UppercaseDirective {
2557
+ el;
2558
+ renderer;
2559
+ onChange = (value) => { };
2560
+ onTouched = () => { };
2561
+ constructor(el, renderer) {
2562
+ this.el = el;
2563
+ this.renderer = renderer;
2564
+ }
2565
+ onInput(value) {
2566
+ const formattedValue = this.formatValue(value);
2567
+ this.renderer.setProperty(this.el.nativeElement, 'value', formattedValue);
2568
+ if (this.onChange) {
2569
+ this.onChange(formattedValue);
2570
+ }
2571
+ }
2572
+ writeValue(value) {
2573
+ const formattedValue = value ? this.formatValue(value) : '';
2574
+ this.renderer.setProperty(this.el.nativeElement, 'value', formattedValue);
2575
+ }
2576
+ registerOnChange(fn) {
2577
+ this.onChange = fn;
2578
+ }
2579
+ registerOnTouched(fn) {
2580
+ this.onTouched = fn;
2581
+ }
2582
+ setDisabledState(isDisabled) {
2583
+ this.renderer.setProperty(this.el.nativeElement, 'disabled', isDisabled);
2584
+ }
2585
+ formatValue(value) {
2586
+ return value.toUpperCase();
2587
+ }
2588
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UppercaseDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
2589
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.7", type: UppercaseDirective, isStandalone: true, selector: "[uppercase]", host: { listeners: { "input": "onInput($event.target.value)" } }, providers: [
2590
+ {
2591
+ provide: NG_VALUE_ACCESSOR,
2592
+ useExisting: forwardRef(() => UppercaseDirective),
2593
+ multi: true,
2594
+ },
2595
+ ], ngImport: i0 });
2596
+ }
2597
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: UppercaseDirective, decorators: [{
2598
+ type: Directive,
2599
+ args: [{
2600
+ selector: '[uppercase]',
2601
+ providers: [
2602
+ {
2603
+ provide: NG_VALUE_ACCESSOR,
2604
+ useExisting: forwardRef(() => UppercaseDirective),
2605
+ multi: true,
2606
+ },
2607
+ ],
2608
+ }]
2609
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { onInput: [{
2610
+ type: HostListener,
2611
+ args: ['input', ['$event.target.value']]
2612
+ }] } });
2613
+
2614
+ class LimitWordsPipe {
2615
+ transform(value, limit = 3) {
2616
+ if (!value)
2617
+ return '';
2618
+ const words = value.split(' ');
2619
+ return words.length <= limit ? value : words.slice(0, limit).join(' ') + '...';
2620
+ }
2621
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: LimitWordsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
2622
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.1.7", ngImport: i0, type: LimitWordsPipe, isStandalone: true, name: "limitWords" });
2623
+ }
2624
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: LimitWordsPipe, decorators: [{
2625
+ type: Pipe,
2626
+ args: [{
2627
+ name: 'limitWords',
2628
+ }]
2629
+ }] });
2630
+
2631
+ class DownloadHelper {
2632
+ static downloadFileBlop(response) {
2633
+ const contentDisposition = response.headers.get('Content-Disposition');
2634
+ let filename = 'downloaded-file';
2635
+ if (contentDisposition) {
2636
+ const filenameStarMatch = contentDisposition.match(/filename\*\=UTF-8''(.+?)(;|$)/);
2637
+ const filenameMatch = contentDisposition.match(/filename="?([^"]+)"?/);
2638
+ if (filenameStarMatch?.[1]) {
2639
+ filename = decodeURIComponent(filenameStarMatch[1]);
2640
+ }
2641
+ else if (filenameMatch?.[1]) {
2642
+ filename = filenameMatch[1];
2643
+ }
2644
+ }
2645
+ const blob = new Blob([response.body], { type: 'application/octet-stream' });
2646
+ if (blob.size <= 4) {
2647
+ console.log(blob.size);
2648
+ alert('Không có dữ liệu file');
2649
+ return;
2650
+ }
2651
+ const link = document.createElement('a');
2652
+ link.href = window.URL.createObjectURL(blob);
2653
+ link.download = filename;
2654
+ link.click();
2655
+ }
2656
+ static downloadFile(data, filename) {
2657
+ const contentType = 'application/octet-stream';
2658
+ const blob = new Blob([data], { type: contentType });
2659
+ if (blob.size <= 4) {
2660
+ console.log(blob.size);
2661
+ alert('Không có dữ liệu file');
2662
+ return;
2663
+ }
2664
+ const link = document.createElement('a');
2665
+ link.href = window.URL.createObjectURL(blob);
2666
+ link.download = filename;
2667
+ link.click();
2668
+ }
2669
+ static downloadFileBase64(base64Data, fileName) {
2670
+ // Chuyển đổi Base64 thành dữ liệu nhị phân
2671
+ const binaryString = window.atob(base64Data);
2672
+ const binaryLen = binaryString.length;
2673
+ const bytes = new Uint8Array(binaryLen);
2674
+ for (let i = 0; i < binaryLen; i++) {
2675
+ bytes[i] = binaryString.charCodeAt(i);
2676
+ }
2677
+ // Tạo một Blob từ dữ liệu nhị phân
2678
+ const blob = new Blob([bytes], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
2679
+ if (blob.size <= 4) {
2680
+ console.log(blob.size);
2681
+ alert('Không có dữ liệu file');
2682
+ return;
2683
+ }
2684
+ // Tạo một liên kết tạm thời để tải tệp về
2685
+ const link = document.createElement('a');
2686
+ link.href = window.URL.createObjectURL(blob);
2687
+ link.download = fileName;
2688
+ // Kích hoạt việc tải tệp
2689
+ document.body.appendChild(link);
2690
+ link.click();
2691
+ // Xóa liên kết sau khi tải
2692
+ document.body.removeChild(link);
2693
+ }
2694
+ }
2695
+
2696
+ class XLSXHelper {
2697
+ static readExcelFileToObjects(file, columnCount, readAllSheets) {
2698
+ return new Promise((resolve, reject) => {
2699
+ const reader = new FileReader();
2700
+ reader.onload = (e) => {
2701
+ const data = new Uint8Array(e.target?.result);
2702
+ const workbook = XLSX.read(data, { type: 'array' });
2703
+ const sheetNames = workbook.SheetNames;
2704
+ // Trả về nhiều sheet
2705
+ if (readAllSheets) {
2706
+ const sheetsdata = {};
2707
+ for (const sheetName of sheetNames) {
2708
+ const worksheet = workbook.Sheets[sheetName];
2709
+ const rawData = XLSX.utils.sheet_to_json(worksheet, {
2710
+ header: 1,
2711
+ defval: '',
2712
+ });
2713
+ let rows = rawData.slice(1);
2714
+ while (rows.length > 0 && rows[rows.length - 1].every((cell) => cell === '' || cell == null)) {
2715
+ rows.pop();
2716
+ }
2717
+ const result = rows.map((row, index) => {
2718
+ const obj = {};
2719
+ const limit = columnCount ?? row.length;
2720
+ for (let i = 0; i < limit; i++) {
2721
+ obj[`col${i + 1}`] = row[i] ?? '';
2722
+ }
2723
+ obj.rowIndex = index + 2;
2724
+ return obj;
2725
+ });
2726
+ sheetsdata[sheetName] = result;
2727
+ }
2728
+ postMessage({
2729
+ sheets: sheetNames,
2730
+ sheetsdata,
2731
+ });
2732
+ resolve({
2733
+ sheets: sheetNames,
2734
+ sheetsdata,
2735
+ });
2736
+ }
2737
+ // Trả về sheet đầu tiên
2738
+ else {
2739
+ const sheetName = sheetNames[0];
2740
+ const worksheet = workbook.Sheets[sheetName];
2741
+ const rawData = XLSX.utils.sheet_to_json(worksheet, {
2742
+ header: 1,
2743
+ defval: '',
2744
+ });
2745
+ let rows = rawData.slice(1);
2746
+ while (rows.length > 0 && rows[rows.length - 1].every((cell) => cell === '' || cell == null)) {
2747
+ rows.pop();
2748
+ }
2749
+ const result = rows.map((row, index) => {
2750
+ const obj = {};
2751
+ const limit = columnCount ?? row.length;
2752
+ for (let i = 0; i < limit; i++) {
2753
+ obj[`col${i + 1}`] = row[i] ?? '';
2754
+ }
2755
+ obj.rowIndex = index + 2;
2756
+ return obj;
2757
+ });
2758
+ resolve(result);
2759
+ }
2760
+ };
2761
+ reader.onerror = (error) => reject(error);
2762
+ reader.readAsArrayBuffer(file);
2763
+ });
2764
+ }
2765
+ }
2766
+
2767
+ class PagingModel {
2768
+ PageIndex = 0;
2769
+ PageSize = AppGlobals.pageSizeOptions[1];
2770
+ }
2771
+ class GridFilter extends PagingModel {
2772
+ Keyword = null;
2773
+ OrderOption = null;
2774
+ }
2775
+ class OrderOption {
2776
+ FieldName = null;
2777
+ Direction = null;
2778
+ }
2779
+ class PagingData {
2780
+ TypeConstructor;
2781
+ LstHeader = [];
2782
+ LstItem = [];
2783
+ TotalCount = 0;
2784
+ constructor(obj, TypeConstructor) {
2785
+ this.TypeConstructor = TypeConstructor;
2786
+ obj = obj ?? {};
2787
+ this.LstHeader = obj.LstHeader || [];
2788
+ this.TotalCount = obj.TotalCount || 0;
2789
+ if (Array.isArray(obj.LstItem) && this.TypeConstructor) {
2790
+ this.LstItem = obj.LstItem.map((item) => new this.TypeConstructor(item));
2791
+ }
2792
+ else {
2793
+ this.LstItem = obj.LstItem || [];
2794
+ }
2795
+ }
2796
+ }
2797
+ class TableHeader {
2798
+ Code = '';
2799
+ Name = '';
2800
+ Class = '';
2801
+ Type = '';
2802
+ Width = '';
2803
+ MinWidth = '';
2804
+ }
2805
+ class CheckModel {
2806
+ ConfirmMessage = '';
2807
+ ConfirmContent = '';
2808
+ ErrorMessage = '';
2809
+ ErrorContent = '';
2810
+ }
2811
+
2812
+ class RouteMonitorService {
2813
+ router;
2814
+ authService;
2815
+ notiService;
2816
+ constructor(router, authService, notiService) {
2817
+ this.router = router;
2818
+ this.authService = authService;
2819
+ this.notiService = notiService;
2820
+ this.router.events.subscribe(async (event) => {
2821
+ if (event instanceof NavigationEnd) {
2822
+ const url = event.urlAfterRedirects;
2823
+ if (url.startsWith('/') || url.startsWith('/login') || url == '/no-permission') {
2824
+ return;
2825
+ }
2826
+ const hasMenu = await this.authService.checkUserMenu(url);
2827
+ if (!hasMenu) {
2828
+ this.notiService.error(`Không có quyền truy cập: ${url}`);
2829
+ this.router.navigate(['/no-permission'], {
2830
+ state: {
2831
+ deniedUrl: url,
2832
+ message: `Bạn không có quyền truy cập vào đường dẫn ${url}`,
2833
+ },
2834
+ });
2835
+ }
2836
+ }
2837
+ });
2838
+ }
2839
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: RouteMonitorService, deps: [{ token: i1$3.Router }, { token: AuthService }, { token: NotiService }], target: i0.ɵɵFactoryTarget.Injectable });
2840
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: RouteMonitorService, providedIn: 'root' });
2841
+ }
2842
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: RouteMonitorService, decorators: [{
2843
+ type: Injectable,
2844
+ args: [{ providedIn: 'root' }]
2845
+ }], ctorParameters: () => [{ type: i1$3.Router }, { type: AuthService }, { type: NotiService }] });
2846
+
2847
+ class ThemeService {
2848
+ setHighContrast(enabled) {
2849
+ document.body.classList.toggle('high-contrast', enabled);
2850
+ localStorage.setItem('high-contrast', enabled ? '1' : '0');
2851
+ }
2852
+ isHighContrast() {
2853
+ return localStorage.getItem('high-contrast') == '1';
2854
+ }
2855
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2856
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ThemeService, providedIn: 'root' });
2857
+ }
2858
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: ThemeService, decorators: [{
2859
+ type: Injectable,
2860
+ args: [{ providedIn: 'root' }]
2861
+ }] });
2862
+
2863
+ class VscService extends HTTPService {
2864
+ // private readonly currentVersion = '{{POST_BUILD_ENTERS_VERSION_HERE}}';
2865
+ static feClientVersion = '{{POST_BUILD_ENTERS_VERSION_HERE}}';
2866
+ static feServerVersion;
2867
+ static beVersion;
2868
+ static dbVersion;
2869
+ static jsReportTemplateVersion;
2870
+ modal = inject(NzModalService);
2871
+ notiService = inject(NotiService);
2872
+ interval;
2873
+ isShowingPopup = false;
2874
+ // 10 phút
2875
+ initVersionCheck(frequency = 1000 * 60 * 10) {
2876
+ this.interval = setInterval(() => {
2877
+ if (!this.isShowingPopup) {
2878
+ this.checkVersion();
2879
+ }
2880
+ }, frequency);
2881
+ this.checkVersion();
2882
+ }
2883
+ checkVersion(all = false) {
2884
+ console.log('Check version');
2885
+ this.checkFrontendVersion();
2886
+ if (all) {
2887
+ this.checkBackendVersion();
2888
+ // this.checkDatabaseVersion();
2889
+ // this.checkJSReportTemplateVersion();
2890
+ }
2891
+ }
2892
+ checkFrontendVersion() {
2893
+ if (this.isShowingPopup) {
2894
+ return;
2895
+ }
2896
+ console.log('Check version');
2897
+ console.log('current version: ', VscService.feClientVersion);
2898
+ this.get(AppGlobals.versionCheck + '?t=' + new Date().getTime()).then(async (response) => {
2899
+ VscService.feServerVersion = response.version;
2900
+ console.log('version check: ', VscService.feServerVersion);
2901
+ const hashChanged = this.hasVersionChanged(VscService.feClientVersion, VscService.feServerVersion);
2902
+ if (hashChanged) {
2903
+ // window.location.reload();
2904
+ // window.location.href = window.location.href;
2905
+ this.isShowingPopup = true;
2906
+ // await this.notiService.warning('Có phiên bản mới', 'Vui lòng ấn "Ctrl + F5" để cập nhật');
2907
+ // this.isShowingPopup = false;
2908
+ const modalRef = this.modal.warning({
2909
+ nzTitle: 'Có phiên bản mới',
2910
+ nzContent: 'Vui lòng ấn "Ctrl + F5" để cập nhật',
2911
+ });
2912
+ }
2913
+ }, (err) => {
2914
+ console.error(err, 'Could not get version');
2915
+ });
2916
+ }
2917
+ hasVersionChanged(currentVersion, newVersion) {
2918
+ if (!currentVersion || newVersion === currentVersion) {
2919
+ return false;
2920
+ }
2921
+ return currentVersion !== newVersion;
2922
+ }
2923
+ clearInterval() {
2924
+ if (this.interval) {
2925
+ clearInterval(this.interval);
2926
+ }
2927
+ }
2928
+ checkBackendVersion() {
2929
+ this.httpClient.get(AppGlobals.apiEndpoint + '/version').subscribe(async (response) => {
2930
+ VscService.beVersion = response;
2931
+ }, (err) => {
2932
+ console.error(err, 'Could not get backend version');
2933
+ VscService.beVersion = 'Could not get backend version';
2934
+ });
2935
+ }
2936
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: VscService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2937
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: VscService, providedIn: 'root' });
2938
+ }
2939
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: VscService, decorators: [{
2940
+ type: Injectable,
2941
+ args: [{
2942
+ providedIn: 'root',
2943
+ }]
2944
+ }] });
2945
+
2946
+ /**
2947
+ * Generated bundle index. Do not edit.
2948
+ */
2949
+
2950
+ export { AnimatedDigitComponent, AppGlobals, AppStorage, AuthGuard, AutoFocusDirective, BarGraphComponent, BaseComponent, BaseGuardChangeComponent, BaseOverlayComponent, Box, Breadcrumb, CheckModel, CommonService, DashcardComponent, DateInputParserDirective, DateTimeHelper, DoughnutGraphComponent, DownloadHelper, ENUM_ResponseType, ExtendCheckbox, ExtendDatePicker, ExtendInput, ExtendInputNumber, ExtendSelectComponent, ExtendTextArea, GlobalSpinnerComponent, GridFilter, HTTPService, Height, LimitWordsPipe, LineGraphComponent, LoadingService, NoPermission, NotiService, NullIfEmptyDirective, NumberOnlyDirective, OrderOption, PagingData, PagingModel, PdfViewerComponent, RouteMonitorService, TableHeader, ThemeService, TokenStorage, TranslateKey, UnsavedChangesGuard, UpperCaseFirsLetterEachWordDirective, UppercaseDirective, UppercaseFirstLetterDirective, VscService, Width, XLSXHelper, authInterceptor };
2951
+ //# sourceMappingURL=brggroup-share-lib.mjs.map