@libs-ui/utils 0.2.300 → 0.2.303
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/cache.mjs +1 -2
- package/esm2022/date.mjs +2 -2
- package/esm2022/file.mjs +5 -2
- package/esm2022/helpers.mjs +10 -1
- package/fesm2022/libs-ui-utils.mjs +1472 -1463
- package/fesm2022/libs-ui-utils.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fromEvent, tap, takeUntil, mergeMap, startWith, finalize,
|
|
1
|
+
import { fromEvent, tap, takeUntil, mergeMap, startWith, finalize, Subject, filter, Observable } from 'rxjs';
|
|
2
2
|
import Quill from 'quill';
|
|
3
3
|
import DeviceDetector from 'device-detector-js';
|
|
4
4
|
import CryptoES from 'crypto-es';
|
|
@@ -598,1422 +598,1607 @@ class UtilsHttpParamsRequest extends HttpParams {
|
|
|
598
598
|
// "pathVariable-name": '124',
|
|
599
599
|
// };
|
|
600
600
|
|
|
601
|
-
|
|
602
|
-
/**Các hàm tương tự thư viện lodash */
|
|
603
|
-
/**
|
|
604
|
-
* Kiểm tra xem một giá trị có phải là null hoặc undefined hay không
|
|
605
|
-
* @param value Giá trị cần kiểm tra
|
|
606
|
-
* @returns true nếu giá trị là null hoặc undefined, false nếu không
|
|
607
|
-
* @example
|
|
608
|
-
* isNil(null); // true
|
|
609
|
-
* isNil(undefined); // true
|
|
610
|
-
* isNil(0); // false
|
|
611
|
-
* isNil('hello'); // false
|
|
612
|
-
*/
|
|
613
|
-
const isNil = (value) => {
|
|
614
|
-
return value === null || value === undefined;
|
|
615
|
-
};
|
|
601
|
+
let key = '12~@#loqwsxacva(3rdhaq12';
|
|
616
602
|
/**
|
|
617
|
-
*
|
|
618
|
-
* @param value
|
|
619
|
-
* @returns true nếu giá trị là null, rỗng hoặc undefined, false nếu không
|
|
620
|
-
* @example
|
|
621
|
-
* isEmpty(null); // true
|
|
622
|
-
* isEmpty(''); // true
|
|
623
|
-
* isEmpty(undefined); // true
|
|
624
|
-
* isEmpty({}); // true
|
|
625
|
-
* isEmpty([]); // true
|
|
626
|
-
* isEmpty([1, 2, 3]); // false
|
|
627
|
-
* isEmpty({ a: 1 }); // false
|
|
603
|
+
* @description Thiết lập key mã hóa
|
|
604
|
+
* @param value key mã hóa, độ dài bằng 24 hoặc 32 ký tự.
|
|
628
605
|
*/
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
|
|
606
|
+
const setKeyCrypto3rd = (value) => {
|
|
607
|
+
if (value.length !== 24 && value.length !== 32) {
|
|
608
|
+
throw Error(`key.length = ${value.length}; Key phải là 1 chuỗi dài 24 hoặc 32 ký tự`);
|
|
632
609
|
}
|
|
633
|
-
|
|
610
|
+
key = value;
|
|
634
611
|
};
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
* const obj = { a: 1, b: null, c: 3, d: undefined };
|
|
642
|
-
* omitBy(obj, isNil); // { a: 1, c: 3 }
|
|
643
|
-
*/
|
|
644
|
-
const omitBy = (objData, predicate) => {
|
|
645
|
-
if (!objData || typeof objData !== 'object' || Array.isArray(objData)) {
|
|
646
|
-
return objData;
|
|
612
|
+
const keyStore = () => {
|
|
613
|
+
return key;
|
|
614
|
+
};
|
|
615
|
+
const encrypt3rd = (plainData) => {
|
|
616
|
+
if (!keyStore()) {
|
|
617
|
+
throw Error("lỗi chưa setup key mã hóa");
|
|
647
618
|
}
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
});
|
|
655
|
-
return newObj;
|
|
619
|
+
const key = CryptoES.enc.Hex.parse(keyStore());
|
|
620
|
+
const iv = CryptoES.enc.Hex.parse(keyStore());
|
|
621
|
+
const mode = CryptoES.mode.CBC;
|
|
622
|
+
const padding = CryptoES.pad.Pkcs7;
|
|
623
|
+
const options = { iv: iv, mode: mode, padding: padding };
|
|
624
|
+
return CryptoES.AES.encrypt(plainData, key, options).toString();
|
|
656
625
|
};
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
* Hàm này giúp bạn truy cập vào các thuộc tính sâu bên trong một đối tượng một cách an toàn,
|
|
661
|
-
* tránh lỗi khi thuộc tính không tồn tại.
|
|
662
|
-
*
|
|
663
|
-
* @param obj Đối tượng nguồn cần lấy giá trị
|
|
664
|
-
* @param path Đường dẫn đến thuộc tính cần lấy. Có thể là:
|
|
665
|
-
* - Chuỗi: 'user.profile.name' hoặc 'items[0].title'
|
|
666
|
-
* - Mảng: ['user', 'profile', 'name'] hoặc ['items', '0', 'title']
|
|
667
|
-
* - Chuỗi rỗng '': trả về chính đối tượng gốc
|
|
668
|
-
* @param defaultValue Giá trị mặc định trả về khi không tìm thấy thuộc tính (mặc định: undefined)
|
|
669
|
-
* @param keepLastValueIfSignal Có giữ nguyên signal cuối cùng hay không (mặc định: false - sẽ gọi signal())
|
|
670
|
-
* @returns Giá trị tìm được hoặc giá trị mặc định
|
|
671
|
-
*
|
|
672
|
-
* @example
|
|
673
|
-
* // Ví dụ cơ bản
|
|
674
|
-
* const user = { name: 'John', age: 30 };
|
|
675
|
-
* get(user, 'name'); // 'John'
|
|
676
|
-
* get(user, 'email'); // undefined
|
|
677
|
-
* get(user, 'email', 'no-email'); // 'no-email'
|
|
678
|
-
*
|
|
679
|
-
* @example
|
|
680
|
-
* // Truyền path rỗng - trả về chính đối tượng gốc
|
|
681
|
-
* const data = { name: 'Alice', age: 25 };
|
|
682
|
-
* get(data, ''); // { name: 'Alice', age: 25 } (chính đối tượng data)
|
|
683
|
-
* get(data, '', 'default'); // { name: 'Alice', age: 25 } (bỏ qua defaultValue)
|
|
684
|
-
*
|
|
685
|
-
* @example
|
|
686
|
-
* // Truy cập thuộc tính sâu
|
|
687
|
-
* const data = {
|
|
688
|
-
* user: {
|
|
689
|
-
* profile: {
|
|
690
|
-
* name: 'Alice',
|
|
691
|
-
* settings: { theme: 'dark' }
|
|
692
|
-
* }
|
|
693
|
-
* }
|
|
694
|
-
* };
|
|
695
|
-
* get(data, 'user.profile.name'); // 'Alice'
|
|
696
|
-
* get(data, 'user.profile.settings.theme'); // 'dark'
|
|
697
|
-
* get(data, 'user.profile.avatar', 'default.jpg'); // 'default.jpg'
|
|
698
|
-
*
|
|
699
|
-
* @example
|
|
700
|
-
* // Truy cập mảng
|
|
701
|
-
* const items = [
|
|
702
|
-
* { name: 'Item 1', price: 100 },
|
|
703
|
-
* { name: 'Item 2', price: 200 }
|
|
704
|
-
* ];
|
|
705
|
-
* get(items, '[0].name'); // 'Item 1'
|
|
706
|
-
* get(items, '[1].name'); // 'Item 2'
|
|
707
|
-
* get(items, '[2].name', 'Not found'); // 'Not found'
|
|
708
|
-
*
|
|
709
|
-
* @example
|
|
710
|
-
* // Sử dụng với mảng path
|
|
711
|
-
* const nested = { a: { b: { c: 'deep value' } } };
|
|
712
|
-
* get(nested, ['a', 'b', 'c']); // 'deep value'
|
|
713
|
-
* get(nested, ['a', 'b', 'd'], 'default'); // 'default'
|
|
714
|
-
*
|
|
715
|
-
* @example
|
|
716
|
-
* // Trường hợp đặc biệt
|
|
717
|
-
* get(null, 'any.path'); // undefined
|
|
718
|
-
* get(undefined, 'any.path', 'fallback'); // 'fallback'
|
|
719
|
-
*/
|
|
720
|
-
const get = (obj, path, defaultValue = undefined, keepLastValueIfSignal) => {
|
|
721
|
-
if (isNil(obj)) {
|
|
722
|
-
return defaultValue;
|
|
626
|
+
const decrypt3rd = (encryptedData) => {
|
|
627
|
+
if (!keyStore()) {
|
|
628
|
+
throw Error("lỗi chưa setup key mã hóa");
|
|
723
629
|
}
|
|
724
|
-
|
|
725
|
-
|
|
630
|
+
const key = CryptoES.enc.Hex.parse(keyStore());
|
|
631
|
+
const iv = CryptoES.enc.Hex.parse(keyStore());
|
|
632
|
+
const mode = CryptoES.mode.CBC;
|
|
633
|
+
const padding = CryptoES.pad.Pkcs7;
|
|
634
|
+
const options = { iv: iv, mode: mode, padding: padding };
|
|
635
|
+
return CryptoES.AES.decrypt(encryptedData, key, options).toString(CryptoES.enc.Utf8);
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
let functionCheck = () => {
|
|
639
|
+
return window.parent !== window.top;
|
|
640
|
+
};
|
|
641
|
+
const updateFunctionCheckEmbedFrame = (functionCustom) => {
|
|
642
|
+
functionCheck = functionCustom;
|
|
643
|
+
};
|
|
644
|
+
const isEmbedFrame = () => {
|
|
645
|
+
return functionCheck();
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
const ERROR_MESSAGE_EMPTY_VALID = 'i18n_valid_empty_message';
|
|
649
|
+
const ERROR_MESSAGE_PATTEN_VALID = 'i18n_valid_pattern_message';
|
|
650
|
+
const ERROR_MESSAGE_MIN_VALID = 'i18n_message_error_input_min_value';
|
|
651
|
+
const ERROR_MESSAGE_MAX_VALID = 'i18n_message_error_input_max_value';
|
|
652
|
+
const ERROR_MESSAGE_MIN_LENGTH = 'i18n_message_error_input_min_length';
|
|
653
|
+
const ERROR_MESSAGE_MAX_LENGTH = 'i18n_message_error_input_max_length';
|
|
654
|
+
const CHARACTER_DATA_EMPTY = '__';
|
|
655
|
+
const DEFAULT_START_PAGE_0 = 'defaultStartPage0';
|
|
656
|
+
const COMMUNICATE_MICRO_PREFIX_TYPE = '3RD_INTEGRATE_MICRO_SITE_';
|
|
657
|
+
const COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE = 'MICRO_SITES_ALL_MESSAGE';
|
|
658
|
+
|
|
659
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
660
|
+
class UtilsCommunicateMicroKeyGlobal {
|
|
661
|
+
static KEY_MESSAGE_MODAL = 'LIBS_UI_MODEL_EVENT';
|
|
662
|
+
}
|
|
663
|
+
class UtilsCommunicateMicro {
|
|
664
|
+
static initdEvent;
|
|
665
|
+
static subs = new Map();
|
|
666
|
+
static allMessageSub = new Subject();
|
|
667
|
+
static initEvent(currentWindow, onDestroy) {
|
|
668
|
+
if (this.initdEvent) {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
this.initdEvent = true;
|
|
672
|
+
if (!this.subs.get(COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE)) {
|
|
673
|
+
this.subs.set(COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE, UtilsCommunicateMicro.allMessageSub);
|
|
674
|
+
}
|
|
675
|
+
fromEvent(currentWindow, 'message').pipe(takeUntil(onDestroy)).subscribe(e => {
|
|
676
|
+
const event = { data: { ...e.data } };
|
|
677
|
+
const data = event.data;
|
|
678
|
+
const type = data.type;
|
|
679
|
+
if (!type) {
|
|
680
|
+
return this.allMessageSub.next(event);
|
|
681
|
+
}
|
|
682
|
+
const sub = UtilsCommunicateMicro.GetMessage(type);
|
|
683
|
+
if (!type || !data.response) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
try {
|
|
687
|
+
if (type.includes(COMMUNICATE_MICRO_PREFIX_TYPE)) {
|
|
688
|
+
data.response = JSON.parse(decrypt3rd(data.response));
|
|
689
|
+
sub.next(event);
|
|
690
|
+
this.allMessageSub.next(event);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
data.response = JSON.parse(decrypt(data.response));
|
|
694
|
+
sub.next(event);
|
|
695
|
+
this.allMessageSub.next(event);
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
console.log(error);
|
|
699
|
+
sub.next(event);
|
|
700
|
+
this.allMessageSub.next(event);
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
UtilsCommunicateMicro.GetMessage(UtilsCache.typeKeyClearLocalStorage).pipe(filter(e => e.data.response !== UtilsCache.idService), takeUntil(onDestroy)).subscribe(() => {
|
|
704
|
+
console.log('clear all cache by event');
|
|
705
|
+
UtilsCache.ClearAll();
|
|
706
|
+
});
|
|
726
707
|
}
|
|
727
|
-
|
|
728
|
-
|
|
708
|
+
static PostMessageToParent(data) {
|
|
709
|
+
data = this.convertData(data);
|
|
710
|
+
try {
|
|
711
|
+
if (isEmbedFrame()) {
|
|
712
|
+
window?.parent?.postMessage(data, "*");
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
window?.top?.postMessage(data, "*");
|
|
716
|
+
}
|
|
717
|
+
catch (error) {
|
|
718
|
+
console.log(error);
|
|
719
|
+
}
|
|
729
720
|
}
|
|
730
|
-
|
|
731
|
-
|
|
721
|
+
static PostMessageToChildren(data) {
|
|
722
|
+
data = this.convertData(data);
|
|
723
|
+
const iframes = document.querySelectorAll("iframe");
|
|
724
|
+
Array.from(iframes).forEach(iframe => {
|
|
725
|
+
iframe?.contentWindow?.postMessage(data, '*');
|
|
726
|
+
});
|
|
732
727
|
}
|
|
733
|
-
|
|
734
|
-
|
|
728
|
+
static PostMessageToOpener(data) {
|
|
729
|
+
if (!window.opener) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
data = this.convertData(data);
|
|
733
|
+
window.opener.postMessage(data, '*');
|
|
735
734
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
if (obj instanceof CSSStyleDeclaration) {
|
|
740
|
-
obj = obj[key];
|
|
741
|
-
continue;
|
|
735
|
+
static convertData(data) {
|
|
736
|
+
if (!data || !data.type || !data.response) {
|
|
737
|
+
return data;
|
|
742
738
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
739
|
+
data = { ...data };
|
|
740
|
+
const type = data.type;
|
|
741
|
+
if (type.includes(COMMUNICATE_MICRO_PREFIX_TYPE)) {
|
|
742
|
+
try {
|
|
743
|
+
JSON.parse(decrypt3rd(data.response));
|
|
744
|
+
return data;
|
|
745
|
+
}
|
|
746
|
+
catch (_) {
|
|
747
|
+
data.response = encrypt3rd(JSON.stringify(data.response));
|
|
748
|
+
return data;
|
|
749
|
+
}
|
|
746
750
|
}
|
|
747
|
-
|
|
748
|
-
|
|
751
|
+
try {
|
|
752
|
+
JSON.parse(decrypt(data.response));
|
|
753
|
+
return data;
|
|
754
|
+
}
|
|
755
|
+
catch (_) {
|
|
756
|
+
data.response = encrypt(JSON.stringify(data.response));
|
|
757
|
+
return data;
|
|
749
758
|
}
|
|
750
|
-
const val = isSignal(obj[key]) && !keepLastValueIfSignal ? obj[key]() : obj[key];
|
|
751
|
-
obj = val;
|
|
752
|
-
}
|
|
753
|
-
return obj;
|
|
754
|
-
};
|
|
755
|
-
/**
|
|
756
|
-
* Thiết lập giá trị cho một thuộc tính trong đối tượng theo đường dẫn chỉ định
|
|
757
|
-
* @param obj Đối tượng cần thiết lập giá trị
|
|
758
|
-
* @param path Đường dẫn đến thuộc tính, có thể là chuỗi (vd: 'a.b.c') hoặc mảng (vd: ['a', 'b', 'c'])
|
|
759
|
-
* @param value Giá trị cần thiết lập
|
|
760
|
-
* @returns Đối tượng sau khi đã thiết lập giá trị
|
|
761
|
-
* @throws Error nếu tham số đầu tiên không phải là đối tượng
|
|
762
|
-
* @example
|
|
763
|
-
* const obj = { a: { b: 1 } };
|
|
764
|
-
* set(obj, 'a.b', 2); // { a: { b: 2 } }
|
|
765
|
-
*/
|
|
766
|
-
const set = (obj, path, value) => {
|
|
767
|
-
if (!obj || (typeof obj !== "object" && !isSignal(obj)) || (isSignal(obj) && typeof obj() !== "object")) {
|
|
768
|
-
throw new Error("The first argument must be an object");
|
|
769
|
-
}
|
|
770
|
-
if (obj instanceof HttpParams) {
|
|
771
|
-
return obj.set(`${path}`, value);
|
|
772
759
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
if (
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
760
|
+
static GetMessage(messageType) {
|
|
761
|
+
if (!this.initdEvent) {
|
|
762
|
+
throw Error("chưa khơi tạo hàm lắng nghe sự kiện, gọi UtilsCommunicateMicro.initEvent(window) tại root component");
|
|
763
|
+
}
|
|
764
|
+
if (typeof messageType === 'string') {
|
|
765
|
+
let sub = this.subs.get(messageType);
|
|
766
|
+
if (!sub) {
|
|
767
|
+
sub = new Subject();
|
|
768
|
+
this.subs.set(messageType, sub);
|
|
769
|
+
return sub;
|
|
782
770
|
}
|
|
783
|
-
|
|
784
|
-
preObjectByKey = currentObjectByKey;
|
|
785
|
-
currentObjectByKey = isSignal(currentObjectByKey) ? currentObjectByKey() : currentObjectByKey;
|
|
786
|
-
return;
|
|
771
|
+
return sub;
|
|
787
772
|
}
|
|
788
|
-
if (
|
|
789
|
-
|
|
773
|
+
if (!Array.isArray(messageType) || !messageType.length) {
|
|
774
|
+
throw new Error('message type empty');
|
|
790
775
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
const valueOfKey = currentObjectByKey[key];
|
|
794
|
-
const valueOfKeyIsSignal = isSignal(valueOfKey);
|
|
795
|
-
if (valueOfKeyIsSignal && (typeof valueOfKey() !== 'object' || valueOfKey() === null)) {
|
|
796
|
-
valueOfKey.set(isSignal(value) ? value() : value);
|
|
797
|
-
return;
|
|
776
|
+
if (messageType.length === 1) {
|
|
777
|
+
return this.GetMessage(messageType[0]);
|
|
798
778
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
779
|
+
const types = messageType.sort().join(';');
|
|
780
|
+
let sub = this.subs.get(types);
|
|
781
|
+
if (sub) {
|
|
782
|
+
return sub;
|
|
783
|
+
}
|
|
784
|
+
sub = new Subject();
|
|
785
|
+
this.subs.set(types, sub);
|
|
786
|
+
this.initSubject(sub, messageType);
|
|
787
|
+
return sub;
|
|
788
|
+
}
|
|
789
|
+
static initSubject(subRoot, messageType) {
|
|
790
|
+
messageType.forEach(key => {
|
|
791
|
+
this.GetMessage(key).subscribe(e => {
|
|
792
|
+
subRoot.next(e);
|
|
812
793
|
});
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
class UtilsLanguageConstants {
|
|
799
|
+
static VI = "vi"; // Tiếng Việt
|
|
800
|
+
static EN = "en"; // Tiếng Anh
|
|
801
|
+
static FR = "fr"; // Tiếng Pháp
|
|
802
|
+
static DE = "de"; // Tiếng Đức
|
|
803
|
+
static ES = "es"; // Tiếng Tây Ban Nha
|
|
804
|
+
static ZH = "zh"; // Tiếng Trung (Giản thể)
|
|
805
|
+
static ZH_TW = "zh-TW"; // Tiếng Trung (Phồn thể)
|
|
806
|
+
static JA = "ja"; // Tiếng Nhật
|
|
807
|
+
static KO = "ko"; // Tiếng Hàn
|
|
808
|
+
static RU = "ru"; // Tiếng Nga
|
|
809
|
+
static IT = "it"; // Tiếng Ý
|
|
810
|
+
static PT = "pt"; // Tiếng Bồ Đào Nha
|
|
811
|
+
static TH = "th"; // Tiếng Thái
|
|
812
|
+
static ID = "id"; // Tiếng Indonesia
|
|
813
|
+
static MS = "ms"; // Tiếng Malaysia
|
|
814
|
+
static AR = "ar"; // Tiếng Ả Rập
|
|
815
|
+
static HI = "hi"; // Tiếng Hindi
|
|
816
|
+
static BN = "bn"; // Tiếng Bengal
|
|
817
|
+
static TR = "tr"; // Tiếng Thổ Nhĩ Kỳ
|
|
818
|
+
static NL = "nl"; // Tiếng Hà Lan
|
|
819
|
+
static KM = "km"; // Tiếng Khmer (Campuchia)
|
|
820
|
+
static LO = "lo"; // Tiếng Lào
|
|
821
|
+
static MY = "my"; // Tiếng Miến Điện (Myanmar)
|
|
822
|
+
static TL = "tl"; // Tiếng Tagalog (Philippines)
|
|
823
|
+
static CEB = "ceb"; // Tiếng Cebuano (Philippines)
|
|
824
|
+
static JV = "jv"; // Tiếng Java (Indonesia)
|
|
825
|
+
static SU = "su"; // Tiếng Sundanese (Indonesia)
|
|
826
|
+
// Ngôn ngữ mặc định
|
|
827
|
+
static defaultLang = UtilsLanguageConstants.VI;
|
|
828
|
+
// Danh sách các ngôn ngữ được hỗ trợ
|
|
829
|
+
static supportedLanguages = new Set([
|
|
830
|
+
UtilsLanguageConstants.VI,
|
|
831
|
+
UtilsLanguageConstants.EN,
|
|
832
|
+
UtilsLanguageConstants.FR,
|
|
833
|
+
UtilsLanguageConstants.DE,
|
|
834
|
+
UtilsLanguageConstants.ES,
|
|
835
|
+
UtilsLanguageConstants.ZH,
|
|
836
|
+
UtilsLanguageConstants.ZH_TW,
|
|
837
|
+
UtilsLanguageConstants.JA,
|
|
838
|
+
UtilsLanguageConstants.KO,
|
|
839
|
+
UtilsLanguageConstants.RU,
|
|
840
|
+
UtilsLanguageConstants.IT,
|
|
841
|
+
UtilsLanguageConstants.PT,
|
|
842
|
+
UtilsLanguageConstants.TH,
|
|
843
|
+
UtilsLanguageConstants.ID,
|
|
844
|
+
UtilsLanguageConstants.MS,
|
|
845
|
+
UtilsLanguageConstants.AR,
|
|
846
|
+
UtilsLanguageConstants.HI,
|
|
847
|
+
UtilsLanguageConstants.BN,
|
|
848
|
+
UtilsLanguageConstants.TR,
|
|
849
|
+
UtilsLanguageConstants.NL,
|
|
850
|
+
UtilsLanguageConstants.KM,
|
|
851
|
+
UtilsLanguageConstants.LO,
|
|
852
|
+
UtilsLanguageConstants.MY,
|
|
853
|
+
UtilsLanguageConstants.TL,
|
|
854
|
+
UtilsLanguageConstants.CEB,
|
|
855
|
+
UtilsLanguageConstants.JV,
|
|
856
|
+
UtilsLanguageConstants.SU,
|
|
857
|
+
]);
|
|
858
|
+
/**
|
|
859
|
+
* Kiểm tra xem ngôn ngữ đầu vào có được hỗ trợ không
|
|
860
|
+
* @param lang Mã ngôn ngữ cần kiểm tra
|
|
861
|
+
* @returns True nếu được hỗ trợ, False nếu không
|
|
862
|
+
*/
|
|
863
|
+
static isSupported(lang) {
|
|
864
|
+
return UtilsLanguageConstants.supportedLanguages.has(lang);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/* eslint-disable no-async-promise-executor */
|
|
869
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
870
|
+
class UtilsCache {
|
|
871
|
+
static CACHE_EXPIRE_TIME_DEFAULT = 5 * 60;
|
|
872
|
+
static CACHE_EXPIRE_NONE = -1;
|
|
873
|
+
static idService = uuid();
|
|
874
|
+
static typeKeyClearLocalStorage = 'LIBS_UI_CLEAR_LOCAL_STORAGE_EVENT';
|
|
875
|
+
static languageKeyCache = 'SR3xQKxHgffiCevPQRralg';
|
|
876
|
+
static listKeyKeepWhenClearALll = Array();
|
|
877
|
+
static initdEvent;
|
|
878
|
+
static storage;
|
|
879
|
+
static dbName = 'libs-ui-cache';
|
|
880
|
+
static itemIndexByKey = 'key';
|
|
881
|
+
static dbVersion = 1;
|
|
882
|
+
static db = null;
|
|
883
|
+
static init(config) {
|
|
884
|
+
if (this.initdEvent) {
|
|
813
885
|
return;
|
|
814
886
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
887
|
+
this.initdEvent = true;
|
|
888
|
+
if (config.indexedDBName) {
|
|
889
|
+
this.dbName = config.indexedDBName;
|
|
890
|
+
}
|
|
891
|
+
if (config.typeKeyClearLocalStorage) {
|
|
892
|
+
this.typeKeyClearLocalStorage = config.typeKeyClearLocalStorage;
|
|
893
|
+
}
|
|
894
|
+
if (config.listKeyKeepWhenClearAll) {
|
|
895
|
+
this.listKeyKeepWhenClearALll = config.listKeyKeepWhenClearAll;
|
|
896
|
+
}
|
|
897
|
+
if (config.languageKeyCache) {
|
|
898
|
+
this.languageKeyCache = config.languageKeyCache;
|
|
818
899
|
}
|
|
819
|
-
currentObjectByKey[key] = value;
|
|
820
|
-
});
|
|
821
|
-
return obj;
|
|
822
|
-
};
|
|
823
|
-
/**
|
|
824
|
-
* Tạo một bản sao sâu của một đối tượng hoặc giá trị bất kỳ
|
|
825
|
-
* @param data Dữ liệu cần sao chép
|
|
826
|
-
* @param options Tùy chọn cấu hình
|
|
827
|
-
* @param options.ignoreSignal Nếu true, sẽ không sao chép các signal mà trả về signal gốc
|
|
828
|
-
* @param seen WeakMap để theo dõi các tham chiếu đã được sao chép, tránh lặp vô hạn với các tham chiếu vòng
|
|
829
|
-
* @returns Bản sao sâu của dữ liệu đầu vào
|
|
830
|
-
* @example
|
|
831
|
-
* const obj = {
|
|
832
|
-
* a: 1,
|
|
833
|
-
* b: { c: 2 },
|
|
834
|
-
* d: [1, 2, 3]
|
|
835
|
-
* };
|
|
836
|
-
* const clone = cloneDeep(obj);
|
|
837
|
-
* // clone là một bản sao hoàn toàn độc lập của obj
|
|
838
|
-
*/
|
|
839
|
-
const cloneDeep = (data, options = { ignoreSignal: false }, seen = new WeakMap()) => {
|
|
840
|
-
if (data === null || (typeof data !== 'object' && !isSignal(data))) {
|
|
841
|
-
return data;
|
|
842
|
-
}
|
|
843
|
-
if (seen.has(data)) {
|
|
844
|
-
return seen.get(data);
|
|
845
|
-
}
|
|
846
|
-
if (data instanceof HttpParams) {
|
|
847
|
-
return new UtilsHttpParamsRequest(undefined, data);
|
|
848
900
|
}
|
|
849
|
-
|
|
850
|
-
|
|
901
|
+
static setLang(lang) {
|
|
902
|
+
if (!UtilsLanguageConstants.isSupported(lang)) {
|
|
903
|
+
throw Error(`Language not support ${lang}`);
|
|
904
|
+
}
|
|
905
|
+
this.Set(this.languageKeyCache, lang, this.CACHE_EXPIRE_NONE);
|
|
851
906
|
}
|
|
852
|
-
|
|
853
|
-
return
|
|
907
|
+
static getLang() {
|
|
908
|
+
return this.Get(this.languageKeyCache, UtilsLanguageConstants.defaultLang);
|
|
854
909
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
910
|
+
static openDB() {
|
|
911
|
+
return new Promise(resolve => {
|
|
912
|
+
const request = indexedDB.open(this.dbName, this.dbVersion);
|
|
913
|
+
request.onupgradeneeded = (event) => {
|
|
914
|
+
const db = event.target.result;
|
|
915
|
+
if (!db.objectStoreNames.contains(this.dbName)) {
|
|
916
|
+
const objectStore = db.createObjectStore(this.dbName, { keyPath: this.itemIndexByKey });
|
|
917
|
+
objectStore.createIndex(this.itemIndexByKey, this.itemIndexByKey, { unique: true });
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
request.onsuccess = () => {
|
|
921
|
+
this.db = request.result;
|
|
922
|
+
resolve(true);
|
|
923
|
+
};
|
|
924
|
+
request.onerror = (event) => {
|
|
925
|
+
console.trace('Error opening IndexedDB:', event);
|
|
926
|
+
resolve(false);
|
|
927
|
+
};
|
|
868
928
|
});
|
|
869
|
-
return setCopy;
|
|
870
|
-
}
|
|
871
|
-
if (Array.isArray(data)) {
|
|
872
|
-
seen.set(data, data.map(item => cloneDeep(item, options, seen)));
|
|
873
|
-
return seen.get(data);
|
|
874
|
-
}
|
|
875
|
-
if (data instanceof File || data instanceof Blob || Object.prototype.toString.call(data) === '[object File]') {
|
|
876
|
-
return data;
|
|
877
|
-
}
|
|
878
|
-
if (data instanceof TemplateRef || data instanceof ElementRef || data instanceof Element || data instanceof Promise || data instanceof Observable) {
|
|
879
|
-
return data;
|
|
880
929
|
}
|
|
881
|
-
|
|
882
|
-
if (
|
|
883
|
-
|
|
930
|
+
static async getObjectStore() {
|
|
931
|
+
if (!this.db) {
|
|
932
|
+
await this.openDB();
|
|
884
933
|
}
|
|
885
|
-
|
|
886
|
-
|
|
934
|
+
const transaction = this.db?.transaction([this.dbName], 'readwrite');
|
|
935
|
+
if (!transaction) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
return transaction.objectStore(this.dbName);
|
|
887
939
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
940
|
+
static get LocalStorage() {
|
|
941
|
+
try {
|
|
942
|
+
if (typeof window.localStorage !== 'undefined') {
|
|
943
|
+
const OS = getPlatFromBrowser();
|
|
944
|
+
if (OS.includes('Safari') && parseFloat(OS.split(' ').pop() || '0') >= 16) {
|
|
945
|
+
return this.getLocalStorageFakeOnSafari();
|
|
946
|
+
}
|
|
947
|
+
return localStorage;
|
|
948
|
+
}
|
|
949
|
+
return this.getLocalStorageFake();
|
|
895
950
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
951
|
+
catch (error) {
|
|
952
|
+
console.trace(`LocalStorage `, error);
|
|
953
|
+
return this.getLocalStorageFake();
|
|
899
954
|
}
|
|
900
|
-
|
|
901
|
-
|
|
955
|
+
}
|
|
956
|
+
static getLocalStorageFakeOnSafari() {
|
|
957
|
+
if (typeof window.localStorage !== 'undefined' && !this.storage && Object.keys(localStorage).length) {
|
|
958
|
+
this.storage = { ...localStorage };
|
|
902
959
|
}
|
|
960
|
+
return {
|
|
961
|
+
setItem: (key, value) => {
|
|
962
|
+
localStorage.setItem(key, value);
|
|
963
|
+
this.storage[key] = value;
|
|
964
|
+
},
|
|
965
|
+
getItem: (key) => {
|
|
966
|
+
const value = localStorage.getItem(key);
|
|
967
|
+
if (value) {
|
|
968
|
+
return value;
|
|
969
|
+
}
|
|
970
|
+
if (!this.storage || isNil(this.storage[key])) {
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
localStorage.setItem(key, this.storage[key]);
|
|
974
|
+
return this.storage?.[key];
|
|
975
|
+
},
|
|
976
|
+
removeItem: (key) => {
|
|
977
|
+
delete this.storage?.[key];
|
|
978
|
+
localStorage.removeItem(key);
|
|
979
|
+
},
|
|
980
|
+
clear: () => {
|
|
981
|
+
this.storage = {};
|
|
982
|
+
localStorage.clear();
|
|
983
|
+
}
|
|
984
|
+
};
|
|
903
985
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
const keyBy = (data, key) => {
|
|
923
|
-
if (!data || !data.length || !key) {
|
|
924
|
-
return {};
|
|
986
|
+
static getLocalStorageFake() {
|
|
987
|
+
if (!this.storage) {
|
|
988
|
+
this.storage = {};
|
|
989
|
+
}
|
|
990
|
+
return {
|
|
991
|
+
setItem: (key, value) => {
|
|
992
|
+
this.storage[key] = value;
|
|
993
|
+
},
|
|
994
|
+
getItem: (key) => {
|
|
995
|
+
return this.storage?.[key];
|
|
996
|
+
},
|
|
997
|
+
removeItem: (key) => {
|
|
998
|
+
delete this.storage?.[key];
|
|
999
|
+
},
|
|
1000
|
+
clear: () => {
|
|
1001
|
+
this.storage = {};
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
925
1004
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1005
|
+
static async GetAsync(key, default_value, isKeyMD5 = false) {
|
|
1006
|
+
key = isKeyMD5 ? key : md5(key);
|
|
1007
|
+
return new Promise(async (resolve) => {
|
|
1008
|
+
const objectStore = await this.getObjectStore();
|
|
1009
|
+
if (!objectStore) {
|
|
1010
|
+
return resolve(default_value);
|
|
1011
|
+
}
|
|
1012
|
+
const request = objectStore.get(key);
|
|
1013
|
+
request.onsuccess = () => {
|
|
1014
|
+
if (!request.result) {
|
|
1015
|
+
return resolve(default_value);
|
|
1016
|
+
}
|
|
1017
|
+
const data = JSON.parse(decrypt(request.result.value));
|
|
1018
|
+
if (data.expire === this.CACHE_EXPIRE_NONE) {
|
|
1019
|
+
return resolve(data.json);
|
|
1020
|
+
}
|
|
1021
|
+
const currentMillisecond = (new Date().valueOf() / 1000);
|
|
1022
|
+
if (data.expire < currentMillisecond) {
|
|
1023
|
+
return resolve(default_value);
|
|
1024
|
+
}
|
|
1025
|
+
return resolve(data.json);
|
|
1026
|
+
};
|
|
1027
|
+
request.onerror = () => {
|
|
1028
|
+
console.trace(`Get key ${key} Error, return default value: ${default_value}`);
|
|
1029
|
+
return resolve(default_value);
|
|
1030
|
+
};
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
static Get(key, default_value) {
|
|
1034
|
+
if (!key) {
|
|
1035
|
+
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
930
1036
|
}
|
|
931
|
-
|
|
932
|
-
|
|
1037
|
+
const cachedData = this.LocalStorage.getItem(key);
|
|
1038
|
+
if (!cachedData) {
|
|
1039
|
+
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
933
1040
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
* { id: 1, name: 'John' },
|
|
945
|
-
* { id: 2, name: 'Jane' },
|
|
946
|
-
* { id: 1, name: 'John' }
|
|
947
|
-
* ];
|
|
948
|
-
* groupBy(data, 'id');
|
|
949
|
-
* // Kết quả: {
|
|
950
|
-
* // '1': [
|
|
951
|
-
* // { id: 1, name: 'John' },
|
|
952
|
-
* // { id: 1, name: 'John' }
|
|
953
|
-
* // ],
|
|
954
|
-
* // '2': [
|
|
955
|
-
* // { id: 2, name: 'Jane' }
|
|
956
|
-
* // }
|
|
957
|
-
*/
|
|
958
|
-
const groupBy = (data, key) => {
|
|
959
|
-
if (!data || !data.length || !Object.keys(get(data, '0')).length || !key) {
|
|
960
|
-
return {};
|
|
961
|
-
}
|
|
962
|
-
return data.reduce((dir, nextItem) => {
|
|
963
|
-
const valueOfKey = get(nextItem, key);
|
|
964
|
-
if (typeof valueOfKey !== 'string' && typeof valueOfKey !== 'number' && typeof valueOfKey !== 'boolean') {
|
|
965
|
-
return dir;
|
|
1041
|
+
try {
|
|
1042
|
+
const data = JSON.parse(decrypt(cachedData));
|
|
1043
|
+
if (data.expire === this.CACHE_EXPIRE_NONE) {
|
|
1044
|
+
return data.value ?? default_value;
|
|
1045
|
+
}
|
|
1046
|
+
const currentMillisecond = (new Date().valueOf() / 1000);
|
|
1047
|
+
if (data.expire < currentMillisecond) {
|
|
1048
|
+
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
1049
|
+
}
|
|
1050
|
+
return data.value;
|
|
966
1051
|
}
|
|
967
|
-
|
|
968
|
-
|
|
1052
|
+
catch (error) {
|
|
1053
|
+
console.trace(`Get key ${key} Error, return default value: ${default_value}`, error);
|
|
1054
|
+
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
969
1055
|
}
|
|
970
|
-
dir[`${valueOfKey}`].push(nextItem);
|
|
971
|
-
return dir;
|
|
972
|
-
}, {});
|
|
973
|
-
};
|
|
974
|
-
/**
|
|
975
|
-
* Tạo một mảng các số từ giá trị bắt đầu đến giá trị kết thúc với bước nhảy tùy chọn
|
|
976
|
-
* @param start Giá trị bắt đầu của dãy số. Nếu chỉ có một tham số, đây sẽ là giá trị kết thúc và giá trị bắt đầu sẽ là 0
|
|
977
|
-
* @param end Giá trị kết thúc của dãy số (tùy chọn)
|
|
978
|
-
* @param step Bước nhảy giữa các số trong dãy (tùy chọn). Mặc định là 1 nếu end > start, -1 nếu end < start
|
|
979
|
-
* @returns Mảng các số từ start đến end với bước nhảy step
|
|
980
|
-
* @example
|
|
981
|
-
* range(4); // [0, 1, 2, 3]
|
|
982
|
-
* range(1, 5); // [1, 2, 3, 4]
|
|
983
|
-
* range(0, 20, 5); // [0, 5, 10, 15]
|
|
984
|
-
* range(5, 2); // [5, 4, 3]
|
|
985
|
-
*/
|
|
986
|
-
const range = (start, end, step) => {
|
|
987
|
-
if (end === undefined || end === null) {
|
|
988
|
-
end = start;
|
|
989
|
-
start = 0;
|
|
990
1056
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
}
|
|
994
|
-
if (end < start && step > 0) {
|
|
995
|
-
step *= -1;
|
|
1057
|
+
static GetDefaultValueBySpecificKey(key, default_value) {
|
|
1058
|
+
return default_value;
|
|
996
1059
|
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1060
|
+
static async SetAsync(key, value, expireTimeBySecond = this.CACHE_EXPIRE_TIME_DEFAULT, isKeyMD5 = false) {
|
|
1061
|
+
return new Promise(async (resolve) => {
|
|
1062
|
+
const objectStore = await this.getObjectStore();
|
|
1063
|
+
key = isKeyMD5 ? key : md5(key);
|
|
1064
|
+
try {
|
|
1065
|
+
const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
|
|
1066
|
+
const data = {
|
|
1067
|
+
value: encrypt(JSON.stringify({ json: value, expire: currentMillisecond })),
|
|
1068
|
+
};
|
|
1069
|
+
data[this.itemIndexByKey] = key;
|
|
1070
|
+
if (!objectStore) {
|
|
1071
|
+
console.trace(`Can not open object store`);
|
|
1072
|
+
return resolve({ key, messageError: 'Can not open object store' });
|
|
1073
|
+
}
|
|
1074
|
+
const request = objectStore?.put(data);
|
|
1075
|
+
request.onsuccess = () => {
|
|
1076
|
+
console.log(`Set key ${key} Success`);
|
|
1077
|
+
resolve(request.result);
|
|
1078
|
+
};
|
|
1079
|
+
request.onerror = (error) => {
|
|
1080
|
+
console.trace(`Set key ${key} Error`);
|
|
1081
|
+
resolve({ key, messageError: get(error, 'message') });
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
catch (error) {
|
|
1085
|
+
console.trace(`Set key ${key} Error`);
|
|
1086
|
+
resolve({ key, messageError: get(error, 'message') });
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1001
1089
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1090
|
+
static Set(key, value, expireTimeBySecond = this.CACHE_EXPIRE_TIME_DEFAULT) {
|
|
1091
|
+
const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
|
|
1092
|
+
const data = {
|
|
1093
|
+
value: value,
|
|
1094
|
+
expire: currentMillisecond
|
|
1095
|
+
};
|
|
1096
|
+
try {
|
|
1097
|
+
this.LocalStorage.setItem(key, encrypt(JSON.stringify(data)));
|
|
1098
|
+
return true;
|
|
1007
1099
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1100
|
+
catch (error) {
|
|
1101
|
+
console.trace(`Set key ${key} Error`, error);
|
|
1102
|
+
return false;
|
|
1010
1103
|
}
|
|
1011
|
-
arr.push(value);
|
|
1012
1104
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
const { exactlyPosition = false, ignoreExactlyDataType = false } = options || {};
|
|
1029
|
-
if (value1 === value2 || (value1 === null && value2 === null) || (value1 === undefined && value2 === undefined)) {
|
|
1030
|
-
return true;
|
|
1105
|
+
static async ClearAsync(key, isMD5 = false) {
|
|
1106
|
+
return new Promise(async (resolve) => {
|
|
1107
|
+
const objectStore = await this.getObjectStore();
|
|
1108
|
+
if (!objectStore) {
|
|
1109
|
+
return resolve();
|
|
1110
|
+
}
|
|
1111
|
+
const request = objectStore.delete(isMD5 ? key : md5(key));
|
|
1112
|
+
request.onsuccess = () => {
|
|
1113
|
+
resolve({ clearSuccess: true });
|
|
1114
|
+
};
|
|
1115
|
+
request.onerror = (event) => {
|
|
1116
|
+
console.trace('Error deleting Key:', get(event.target.error, 'message'));
|
|
1117
|
+
resolve({ messageError: get(event.target.error, 'message'), clearSuccess: false });
|
|
1118
|
+
};
|
|
1119
|
+
});
|
|
1031
1120
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1121
|
+
static Clear(key) {
|
|
1122
|
+
if (key.includes('kc-callback-')) {
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
this.LocalStorage.removeItem(key);
|
|
1034
1126
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1127
|
+
static ClearAllAsync() {
|
|
1128
|
+
return new Promise(async (resolve) => {
|
|
1129
|
+
const objectStore = await this.getObjectStore();
|
|
1130
|
+
if (!objectStore) {
|
|
1131
|
+
return resolve();
|
|
1132
|
+
}
|
|
1133
|
+
const request = objectStore.clear();
|
|
1134
|
+
request.onsuccess = () => {
|
|
1135
|
+
console.log('clear all successfully');
|
|
1136
|
+
resolve({ clearSuccess: true });
|
|
1137
|
+
};
|
|
1138
|
+
request.onerror = (event) => {
|
|
1139
|
+
console.trace('Error deleting key:', get(event.target.error, 'message'));
|
|
1140
|
+
resolve({ messageError: get(event.target.error, 'message'), clearSuccess: false });
|
|
1141
|
+
};
|
|
1142
|
+
});
|
|
1038
1143
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1144
|
+
static ClearAll() {
|
|
1145
|
+
if (isEmbedFrame()) {
|
|
1146
|
+
const data = {
|
|
1147
|
+
type: this.typeKeyClearLocalStorage,
|
|
1148
|
+
response: {
|
|
1149
|
+
idEvent: this.idService
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
UtilsCommunicateMicro.PostMessageToParent(data);
|
|
1153
|
+
}
|
|
1154
|
+
const keys = [...this.listKeyKeepWhenClearALll];
|
|
1155
|
+
Object.keys(this.LocalStorage).forEach(key => {
|
|
1156
|
+
if (key.includes('kc-callback-')) {
|
|
1157
|
+
keys.push(key);
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
const stores = this.GetDataByKeys(Array.from(keys));
|
|
1161
|
+
this.LocalStorage.clear();
|
|
1162
|
+
this.SetDataByKey(stores);
|
|
1041
1163
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1164
|
+
static GetDataByKeys(keys) {
|
|
1165
|
+
const stores = new Map();
|
|
1166
|
+
keys.forEach((key) => {
|
|
1167
|
+
if (key.includes('kc-callback-')) {
|
|
1168
|
+
stores.set(key, this.LocalStorage.getItem(key));
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
stores.set(key, this.Get(key));
|
|
1172
|
+
});
|
|
1173
|
+
return stores;
|
|
1044
1174
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1175
|
+
static SetDataByKey(stores) {
|
|
1176
|
+
stores.forEach((value, key) => {
|
|
1177
|
+
if (key.includes('kc-callback-')) {
|
|
1178
|
+
this.LocalStorage.setItem(key, value);
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
if (key === this.languageKeyCache) {
|
|
1182
|
+
return this.setLang(value);
|
|
1183
|
+
}
|
|
1184
|
+
this.Set(key, value, this.CACHE_EXPIRE_NONE);
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
static DeleteKeyStartWithAsync(keyCacheStartWith, isKeyMD5 = false) {
|
|
1188
|
+
return new Promise(async (resolve) => {
|
|
1189
|
+
const objectStore = await this.getObjectStore();
|
|
1190
|
+
if (!objectStore) {
|
|
1191
|
+
return resolve({});
|
|
1192
|
+
}
|
|
1193
|
+
// Lấy tất cả các keys từ index
|
|
1194
|
+
const request = objectStore.getAll();
|
|
1195
|
+
keyCacheStartWith = isKeyMD5 ? keyCacheStartWith : md5(keyCacheStartWith);
|
|
1196
|
+
request.onsuccess = (e) => {
|
|
1197
|
+
const data = e.target.result;
|
|
1198
|
+
if (!Array.isArray(data)) {
|
|
1199
|
+
return resolve({});
|
|
1200
|
+
}
|
|
1201
|
+
data.forEach(obj => {
|
|
1202
|
+
if (obj[this.itemIndexByKey].startsWith(keyCacheStartWith)) {
|
|
1203
|
+
this.ClearAsync(obj[this.itemIndexByKey], true);
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
return resolve({});
|
|
1207
|
+
};
|
|
1208
|
+
request.onerror = () => {
|
|
1209
|
+
return resolve({});
|
|
1210
|
+
};
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1213
|
+
static DeleteKeyStartWith(keyCache, isMD5 = false) {
|
|
1214
|
+
keyCache = isMD5 ? md5(keyCache) : keyCache;
|
|
1215
|
+
const keys = Object.keys(this.LocalStorage);
|
|
1216
|
+
if (!keys || !keys.length) {
|
|
1217
|
+
return;
|
|
1051
1218
|
}
|
|
1052
|
-
|
|
1219
|
+
keys.forEach(key => {
|
|
1220
|
+
if (key.startsWith(keyCache)) {
|
|
1221
|
+
this.Clear(key);
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1053
1224
|
}
|
|
1054
|
-
|
|
1055
|
-
return
|
|
1225
|
+
static DeleteDatabaseIndexDB(dbName) {
|
|
1226
|
+
return new Promise((resolve) => {
|
|
1227
|
+
dbName = (dbName || this.dbName);
|
|
1228
|
+
const request = indexedDB.deleteDatabase(dbName);
|
|
1229
|
+
request.onsuccess = () => {
|
|
1230
|
+
console.trace('Database deleted successfully');
|
|
1231
|
+
resolve({ deleteSuccess: true });
|
|
1232
|
+
};
|
|
1233
|
+
request.onerror = (event) => {
|
|
1234
|
+
console.trace('Error deleting database:', event.target.error);
|
|
1235
|
+
resolve({ messageError: get(event.target.error, 'message'), deleteSuccess: false });
|
|
1236
|
+
};
|
|
1237
|
+
request.onblocked = () => {
|
|
1238
|
+
console.trace('Delete request is blocked');
|
|
1239
|
+
resolve({ messageError: 'Delete request is blocked', deleteSuccess: false });
|
|
1240
|
+
};
|
|
1241
|
+
});
|
|
1056
1242
|
}
|
|
1057
|
-
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
dayjs.extend(localeData);
|
|
1246
|
+
dayjs.extend(updateLocale);
|
|
1247
|
+
dayjs.extend(utc);
|
|
1248
|
+
dayjs.extend(timezone);
|
|
1249
|
+
dayjs.extend(customParseFormat);
|
|
1250
|
+
let timeZoneSetup = "Asia/Ho_Chi_Minh";
|
|
1251
|
+
const setDefaultTimeZone = (localeZone = timeZoneSetup) => {
|
|
1252
|
+
timeZoneSetup = localeZone;
|
|
1253
|
+
dayjs.tz.setDefault(localeZone);
|
|
1254
|
+
};
|
|
1255
|
+
let functionFormatDate = undefined;
|
|
1256
|
+
const updateFunctionFormatDate = (functionCustom) => {
|
|
1257
|
+
functionFormatDate = functionCustom;
|
|
1058
1258
|
};
|
|
1059
1259
|
/**
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
* uniqBy(arr, 'id'); // [{ id: 1, name: 'A' }, { id: 2, name: 'B' }]
|
|
1071
|
-
*
|
|
1072
|
-
* const numbers = [1, 2, 2, 3, 3];
|
|
1073
|
-
* uniqBy(numbers); // [1, 2, 3]
|
|
1074
|
-
*
|
|
1075
|
-
* const numbersSignal = [signal(1), signal(2), signal(3), signal(2), signal(5), signal(4), signal(1), signal(6), signal(7), signal(6)];
|
|
1076
|
-
* uniqBy(numbersSignal); // [signal(1), signal(2), signal(3), signal(5), signal(4), signal(6), signal(7)]
|
|
1077
|
-
*/
|
|
1078
|
-
const uniqBy = (data, key) => {
|
|
1079
|
-
if (!key || !data?.length || typeof get(data, '0') !== 'object') {
|
|
1080
|
-
// Xử lý mảng chứa signal values
|
|
1081
|
-
if (data[0] && isSignal(data[0])) {
|
|
1082
|
-
const seen = new Set();
|
|
1083
|
-
return data.filter(item => {
|
|
1084
|
-
const value = `${get(item, '')}`;
|
|
1085
|
-
if (seen.has(value)) {
|
|
1086
|
-
return false;
|
|
1087
|
-
}
|
|
1088
|
-
seen.add(value);
|
|
1089
|
-
return true;
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
// Xử lý mảng primitive values
|
|
1093
|
-
return Array.from(new Set(data));
|
|
1260
|
+
* @description Lấy đối tượng dayjs theo config
|
|
1261
|
+
* @param config nếu không có config sẽ trả về đối tượng dayjs là thời gian hiện tại
|
|
1262
|
+
* @param config.date thời gian cần lấy
|
|
1263
|
+
* @param config.returnDayjsIfConfigDateNotExist true nếu muốn trả về đối tượng dayjs nếu config.date không có
|
|
1264
|
+
* @param config.utc true nếu muốn lấy thời gian UTC
|
|
1265
|
+
* @param config.formatOfDate định dạng thời gian đang được truyền vào
|
|
1266
|
+
*/
|
|
1267
|
+
const getDayjs = (config) => {
|
|
1268
|
+
if (!config) {
|
|
1269
|
+
return dayjs().tz();
|
|
1094
1270
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
if (
|
|
1114
|
-
return
|
|
1115
|
-
}
|
|
1116
|
-
if (value instanceof Date) {
|
|
1117
|
-
return 'Date';
|
|
1118
|
-
}
|
|
1119
|
-
if (value instanceof RegExp) {
|
|
1120
|
-
return 'RegExp';
|
|
1121
|
-
}
|
|
1122
|
-
if (Array.isArray(value)) {
|
|
1123
|
-
if (value.length === 0) {
|
|
1124
|
-
return 'Array<any>';
|
|
1125
|
-
}
|
|
1126
|
-
return `Array<${generateType(value[0])}>`;
|
|
1127
|
-
}
|
|
1128
|
-
if (type === 'object') {
|
|
1129
|
-
let interfaceStr = '{\n';
|
|
1130
|
-
for (const key in value) {
|
|
1131
|
-
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
1132
|
-
const valueType = generateType(value[key]);
|
|
1133
|
-
interfaceStr += ` ${key}: ${valueType};\n`;
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
interfaceStr += '}';
|
|
1137
|
-
return interfaceStr;
|
|
1138
|
-
}
|
|
1139
|
-
return 'any';
|
|
1140
|
-
};
|
|
1141
|
-
const interfaceStr = `interface ${interfaceName} ${generateType(obj)}`;
|
|
1142
|
-
return interfaceStr;
|
|
1143
|
-
};
|
|
1144
|
-
|
|
1145
|
-
;
|
|
1146
|
-
const step = 20;
|
|
1147
|
-
const percent = 0.05;
|
|
1148
|
-
const colorStepContrastFromOrigin = (color, stepNumber) => {
|
|
1149
|
-
return colorContrastFromOrigin(color).find(item => item.step === stepNumber);
|
|
1150
|
-
};
|
|
1151
|
-
const colorContrastFromOrigin = (color) => {
|
|
1152
|
-
const parsedColorsArray = parseColorValues(color);
|
|
1153
|
-
const colors = [];
|
|
1154
|
-
let calculatedShades = [];
|
|
1155
|
-
let calculatedTints = [];
|
|
1156
|
-
if (parsedColorsArray !== null) {
|
|
1157
|
-
for (let i = 0; i < parsedColorsArray.length; i++) {
|
|
1158
|
-
calculatedShades = calculateShades(parsedColorsArray[i]);
|
|
1159
|
-
calculatedTints = calculateTints(parsedColorsArray[i]);
|
|
1271
|
+
config.date = !config.date && config.returnDayjsIfConfigDateNotExist ? dayjs().tz() : config.date;
|
|
1272
|
+
if (typeof config.date === 'number') {
|
|
1273
|
+
config.date = dayjs.unix(config.date);
|
|
1274
|
+
}
|
|
1275
|
+
if (!config.date) {
|
|
1276
|
+
return undefined;
|
|
1277
|
+
}
|
|
1278
|
+
let { date, utc, formatOfDate } = config;
|
|
1279
|
+
while (isSignal(date)) {
|
|
1280
|
+
date = date();
|
|
1281
|
+
}
|
|
1282
|
+
while (isSignal(utc)) {
|
|
1283
|
+
utc = utc();
|
|
1284
|
+
}
|
|
1285
|
+
while (isSignal(formatOfDate)) {
|
|
1286
|
+
formatOfDate = formatOfDate();
|
|
1287
|
+
}
|
|
1288
|
+
if (utc) {
|
|
1289
|
+
if (formatOfDate) {
|
|
1290
|
+
return dayjs(date, formatOfDate).utc();
|
|
1160
1291
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1292
|
+
const dateInputIsUTC = (dayjs.isDayjs(date) && date.isUTC()) || (typeof date === 'string' && date.includes('Z'));
|
|
1293
|
+
if (dateInputIsUTC) {
|
|
1294
|
+
return dayjs(date);
|
|
1163
1295
|
}
|
|
1296
|
+
return dayjs(date).utc();
|
|
1164
1297
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
const parseColorValues = (colorValues) => {
|
|
1168
|
-
let colorValuesArray = colorValues.match(/\b[0-9A-Fa-f]{3}\b|[0-9A-Fa-f]{6}\b/g);
|
|
1169
|
-
if (colorValuesArray) {
|
|
1170
|
-
colorValuesArray = colorValuesArray.map((item) => {
|
|
1171
|
-
if (item.length === 3) {
|
|
1172
|
-
let newItem = item.toString().split('');
|
|
1173
|
-
newItem = newItem.reduce((acc, it) => {
|
|
1174
|
-
return acc + it + it;
|
|
1175
|
-
}, '');
|
|
1176
|
-
return newItem;
|
|
1177
|
-
}
|
|
1178
|
-
return item;
|
|
1179
|
-
});
|
|
1298
|
+
if (typeof date === 'string' && !date.includes('Z') && !date.includes('+')) {
|
|
1299
|
+
return (formatOfDate ? dayjs.tz(date, formatOfDate, config.localeZone || timeZoneSetup) : dayjs.tz(date, config.localeZone || timeZoneSetup));
|
|
1180
1300
|
}
|
|
1181
|
-
return
|
|
1182
|
-
};
|
|
1183
|
-
const calculateShades = (colorValue) => {
|
|
1184
|
-
return calculate(colorValue, rgbShade).concat("000000");
|
|
1185
|
-
};
|
|
1186
|
-
const calculateTints = (colorValue) => {
|
|
1187
|
-
return calculate(colorValue, rgbTint).concat("ffffff");
|
|
1301
|
+
return (formatOfDate ? dayjs(date, formatOfDate) : dayjs(date)).tz();
|
|
1188
1302
|
};
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1303
|
+
/**
|
|
1304
|
+
* @description Kiểm tra xem hai ngày có khác nhau không (khác ngày trong tuần)
|
|
1305
|
+
* @param date1 ngày thứ nhất cần so sánh
|
|
1306
|
+
* @param date2 ngày thứ hai cần so sánh
|
|
1307
|
+
* @returns true nếu hai ngày khác nhau, false nếu giống nhau hoặc không thể so sánh
|
|
1308
|
+
*/
|
|
1309
|
+
const isDifferenceDay = (date1, date2) => {
|
|
1310
|
+
if (isDifferenceMonth(date1, date2)) {
|
|
1311
|
+
return true;
|
|
1194
1312
|
}
|
|
1195
|
-
|
|
1313
|
+
const day1 = getDayjs({ date: date1 })?.day();
|
|
1314
|
+
const day2 = getDayjs({ date: date2 })?.day();
|
|
1315
|
+
return day1 !== day2;
|
|
1196
1316
|
};
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1317
|
+
/**
|
|
1318
|
+
* @description Kiểm tra xem hai ngày có khác tháng không
|
|
1319
|
+
* @param date1 ngày thứ nhất cần so sánh
|
|
1320
|
+
* @param date2 ngày thứ hai cần so sánh
|
|
1321
|
+
* @returns true nếu hai ngày khác tháng, false nếu cùng tháng hoặc không thể so sánh
|
|
1322
|
+
*/
|
|
1323
|
+
const isDifferenceMonth = (date1, date2) => {
|
|
1324
|
+
if (isDifferenceYear(date1, date2)) {
|
|
1325
|
+
return true;
|
|
1206
1326
|
}
|
|
1207
|
-
|
|
1327
|
+
const month1 = getDayjs({ date: date1 })?.month();
|
|
1328
|
+
const month2 = getDayjs({ date: date2 })?.month();
|
|
1329
|
+
return month1 !== month2;
|
|
1208
1330
|
};
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
const char = str.charCodeAt(i);
|
|
1220
|
-
hashString = ((hashString << 5) - hashString) + char;
|
|
1221
|
-
hashString = hashString & hashString;
|
|
1222
|
-
}
|
|
1223
|
-
return listColorDefine[Math.abs(hashString) % listColorDefine.length];
|
|
1331
|
+
/**
|
|
1332
|
+
* @description Kiểm tra xem hai ngày có khác năm không
|
|
1333
|
+
* @param date1 ngày thứ nhất cần so sánh
|
|
1334
|
+
* @param date2 ngày thứ hai cần so sánh
|
|
1335
|
+
* @returns true nếu hai ngày khác năm, false nếu cùng năm hoặc không thể so sánh
|
|
1336
|
+
*/
|
|
1337
|
+
const isDifferenceYear = (date1, date2) => {
|
|
1338
|
+
const year1 = getDayjs({ date: date1 })?.year();
|
|
1339
|
+
const year2 = getDayjs({ date: date2 })?.year();
|
|
1340
|
+
return year1 !== year2;
|
|
1224
1341
|
};
|
|
1225
|
-
|
|
1226
|
-
let key = '12~@#loqwsxacva(3rdhaq12';
|
|
1227
1342
|
/**
|
|
1228
|
-
* @description
|
|
1229
|
-
* @param
|
|
1343
|
+
* @description Lấy ra chuỗi thời gian hiển thị theo định dạng và ngôn ngữ
|
|
1344
|
+
* @param date thời gian cần định dạng
|
|
1345
|
+
* @param format định dạng thời gian muốn lấy ra
|
|
1346
|
+
* @param lang lấy theo ngôn ngữ
|
|
1230
1347
|
*/
|
|
1231
|
-
const
|
|
1232
|
-
if (
|
|
1233
|
-
|
|
1348
|
+
const formatDate = (date, formatOutput = 'YYYY/MM/DD HH:mm', lang, formatInput) => {
|
|
1349
|
+
if (!date) {
|
|
1350
|
+
return '';
|
|
1234
1351
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
return key;
|
|
1239
|
-
};
|
|
1240
|
-
const encrypt3rd = (plainData) => {
|
|
1241
|
-
if (!keyStore()) {
|
|
1242
|
-
throw Error("lỗi chưa setup key mã hóa");
|
|
1352
|
+
lang = lang || UtilsCache.getLang();
|
|
1353
|
+
if (functionFormatDate) {
|
|
1354
|
+
return functionFormatDate(date, formatOutput, lang);
|
|
1243
1355
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1356
|
+
date = getDayjs({ date, formatOfDate: formatInput }).locale(lang);
|
|
1357
|
+
if (lang === 'vi') {
|
|
1358
|
+
dayjs.updateLocale('vi', {
|
|
1359
|
+
monthsShort: 'Thg 1_Thg 2_Thg 3_Thg 4_Thg 5_Thg 6_Thg 7_Thg 8_Thg 9_Thg 10_Thg 11_Thg 12'.split('_')
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
return date.format(getFormatData(getTypeByFormat(formatOutput), lang)) || '';
|
|
1363
|
+
};
|
|
1364
|
+
const getTypeByFormat = (format) => {
|
|
1365
|
+
if (format === 'dm' || format === 'dmy' || format === 'dmy hm' || format === 'my') {
|
|
1366
|
+
return format;
|
|
1367
|
+
}
|
|
1368
|
+
if (format === 'DD/MM/YYYY' || format === 'YYYY-MM-DD' || format === 'dd/MM/yyyy' || format === 'dd-MM-yyyy' || format === 'dd/mm/yyyy') {
|
|
1369
|
+
return 'dmy';
|
|
1370
|
+
}
|
|
1371
|
+
if (format === 'MM-DD' || format === 'dd/MM' || format === 'dd/mm') {
|
|
1372
|
+
return 'dm';
|
|
1373
|
+
}
|
|
1374
|
+
if (format === 'M/YYYY' || format === 'YYYY-MM' || format === 'MM/yyyy') {
|
|
1375
|
+
return 'my';
|
|
1376
|
+
}
|
|
1377
|
+
if (format === 'YYYY/MM/DD hh:mm:ss' || format === 'dmy hms' || format === 'dd/mm/yyyy hh:mm:ss') {
|
|
1378
|
+
return 'dmy hms';
|
|
1379
|
+
}
|
|
1380
|
+
if (format === 'hh:mm' || format === 'HH:mm') {
|
|
1381
|
+
return 'hh:mm';
|
|
1382
|
+
}
|
|
1383
|
+
if (format === 'hh:mm A' || format === 'HH:mm A') {
|
|
1384
|
+
return 'hh:mm A';
|
|
1385
|
+
}
|
|
1386
|
+
return 'dmy hm';
|
|
1387
|
+
};
|
|
1388
|
+
const getFormatData = (type, lang) => {
|
|
1389
|
+
switch (type) {
|
|
1390
|
+
case 'dm':
|
|
1391
|
+
if (lang === 'vi') {
|
|
1392
|
+
return 'D MMM';
|
|
1393
|
+
}
|
|
1394
|
+
return 'MMM D';
|
|
1395
|
+
case 'dmy':
|
|
1396
|
+
if (lang === 'vi') {
|
|
1397
|
+
return 'D MMM, YYYY';
|
|
1398
|
+
}
|
|
1399
|
+
return 'MMM D, YYYY';
|
|
1400
|
+
case 'dmy hm':
|
|
1401
|
+
if (lang === 'vi') {
|
|
1402
|
+
return 'D MMM, YYYY HH:mm';
|
|
1403
|
+
}
|
|
1404
|
+
return 'MMM D, YYYY HH:mm';
|
|
1405
|
+
case 'my':
|
|
1406
|
+
if (lang === 'vi') {
|
|
1407
|
+
return 'MMM, YYYY';
|
|
1408
|
+
}
|
|
1409
|
+
return 'MMM YYYY ';
|
|
1410
|
+
case 'dmy hms':
|
|
1411
|
+
if (lang === 'vi') {
|
|
1412
|
+
return 'D MMM, YYYY HH:mm:ss';
|
|
1413
|
+
}
|
|
1414
|
+
return 'MMM D, YYYY HH:mm:ss';
|
|
1415
|
+
case 'hh:mm':
|
|
1416
|
+
case 'HH:mm':
|
|
1417
|
+
return 'HH:mm';
|
|
1418
|
+
case 'hh:mm A':
|
|
1419
|
+
case 'HH:mm A':
|
|
1420
|
+
return 'HH:mm A';
|
|
1254
1421
|
}
|
|
1255
|
-
const key = CryptoES.enc.Hex.parse(keyStore());
|
|
1256
|
-
const iv = CryptoES.enc.Hex.parse(keyStore());
|
|
1257
|
-
const mode = CryptoES.mode.CBC;
|
|
1258
|
-
const padding = CryptoES.pad.Pkcs7;
|
|
1259
|
-
const options = { iv: iv, mode: mode, padding: padding };
|
|
1260
|
-
return CryptoES.AES.decrypt(encryptedData, key, options).toString(CryptoES.enc.Utf8);
|
|
1261
1422
|
};
|
|
1262
1423
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
class UtilsLanguageConstants {
|
|
1386
|
-
static VI = "vi"; // Tiếng Việt
|
|
1387
|
-
static EN = "en"; // Tiếng Anh
|
|
1388
|
-
static FR = "fr"; // Tiếng Pháp
|
|
1389
|
-
static DE = "de"; // Tiếng Đức
|
|
1390
|
-
static ES = "es"; // Tiếng Tây Ban Nha
|
|
1391
|
-
static ZH = "zh"; // Tiếng Trung (Giản thể)
|
|
1392
|
-
static ZH_TW = "zh-TW"; // Tiếng Trung (Phồn thể)
|
|
1393
|
-
static JA = "ja"; // Tiếng Nhật
|
|
1394
|
-
static KO = "ko"; // Tiếng Hàn
|
|
1395
|
-
static RU = "ru"; // Tiếng Nga
|
|
1396
|
-
static IT = "it"; // Tiếng Ý
|
|
1397
|
-
static PT = "pt"; // Tiếng Bồ Đào Nha
|
|
1398
|
-
static TH = "th"; // Tiếng Thái
|
|
1399
|
-
static ID = "id"; // Tiếng Indonesia
|
|
1400
|
-
static MS = "ms"; // Tiếng Malaysia
|
|
1401
|
-
static AR = "ar"; // Tiếng Ả Rập
|
|
1402
|
-
static HI = "hi"; // Tiếng Hindi
|
|
1403
|
-
static BN = "bn"; // Tiếng Bengal
|
|
1404
|
-
static TR = "tr"; // Tiếng Thổ Nhĩ Kỳ
|
|
1405
|
-
static NL = "nl"; // Tiếng Hà Lan
|
|
1406
|
-
static KM = "km"; // Tiếng Khmer (Campuchia)
|
|
1407
|
-
static LO = "lo"; // Tiếng Lào
|
|
1408
|
-
static MY = "my"; // Tiếng Miến Điện (Myanmar)
|
|
1409
|
-
static TL = "tl"; // Tiếng Tagalog (Philippines)
|
|
1410
|
-
static CEB = "ceb"; // Tiếng Cebuano (Philippines)
|
|
1411
|
-
static JV = "jv"; // Tiếng Java (Indonesia)
|
|
1412
|
-
static SU = "su"; // Tiếng Sundanese (Indonesia)
|
|
1413
|
-
// Ngôn ngữ mặc định
|
|
1414
|
-
static defaultLang = UtilsLanguageConstants.VI;
|
|
1415
|
-
// Danh sách các ngôn ngữ được hỗ trợ
|
|
1416
|
-
static supportedLanguages = new Set([
|
|
1417
|
-
UtilsLanguageConstants.VI,
|
|
1418
|
-
UtilsLanguageConstants.EN,
|
|
1419
|
-
UtilsLanguageConstants.FR,
|
|
1420
|
-
UtilsLanguageConstants.DE,
|
|
1421
|
-
UtilsLanguageConstants.ES,
|
|
1422
|
-
UtilsLanguageConstants.ZH,
|
|
1423
|
-
UtilsLanguageConstants.ZH_TW,
|
|
1424
|
-
UtilsLanguageConstants.JA,
|
|
1425
|
-
UtilsLanguageConstants.KO,
|
|
1426
|
-
UtilsLanguageConstants.RU,
|
|
1427
|
-
UtilsLanguageConstants.IT,
|
|
1428
|
-
UtilsLanguageConstants.PT,
|
|
1429
|
-
UtilsLanguageConstants.TH,
|
|
1430
|
-
UtilsLanguageConstants.ID,
|
|
1431
|
-
UtilsLanguageConstants.MS,
|
|
1432
|
-
UtilsLanguageConstants.AR,
|
|
1433
|
-
UtilsLanguageConstants.HI,
|
|
1434
|
-
UtilsLanguageConstants.BN,
|
|
1435
|
-
UtilsLanguageConstants.TR,
|
|
1436
|
-
UtilsLanguageConstants.NL,
|
|
1437
|
-
UtilsLanguageConstants.KM,
|
|
1438
|
-
UtilsLanguageConstants.LO,
|
|
1439
|
-
UtilsLanguageConstants.MY,
|
|
1440
|
-
UtilsLanguageConstants.TL,
|
|
1441
|
-
UtilsLanguageConstants.CEB,
|
|
1442
|
-
UtilsLanguageConstants.JV,
|
|
1443
|
-
UtilsLanguageConstants.SU,
|
|
1444
|
-
]);
|
|
1445
|
-
/**
|
|
1446
|
-
* Kiểm tra xem ngôn ngữ đầu vào có được hỗ trợ không
|
|
1447
|
-
* @param lang Mã ngôn ngữ cần kiểm tra
|
|
1448
|
-
* @returns True nếu được hỗ trợ, False nếu không
|
|
1449
|
-
*/
|
|
1450
|
-
static isSupported(lang) {
|
|
1451
|
-
return UtilsLanguageConstants.supportedLanguages.has(lang);
|
|
1424
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1425
|
+
/**Các hàm tương tự thư viện lodash */
|
|
1426
|
+
/**
|
|
1427
|
+
* Kiểm tra xem một giá trị có phải là null hoặc undefined hay không
|
|
1428
|
+
* @param value Giá trị cần kiểm tra
|
|
1429
|
+
* @returns true nếu giá trị là null hoặc undefined, false nếu không
|
|
1430
|
+
* @example
|
|
1431
|
+
* isNil(null); // true
|
|
1432
|
+
* isNil(undefined); // true
|
|
1433
|
+
* isNil(0); // false
|
|
1434
|
+
* isNil('hello'); // false
|
|
1435
|
+
*/
|
|
1436
|
+
const isNil = (value) => {
|
|
1437
|
+
return value === null || value === undefined;
|
|
1438
|
+
};
|
|
1439
|
+
/**
|
|
1440
|
+
* Kiểm tra xem một giá trị có phải là rỗng hay không
|
|
1441
|
+
* @param value Giá trị cần kiểm tra
|
|
1442
|
+
* @returns true nếu giá trị là null, rỗng hoặc undefined, false nếu không
|
|
1443
|
+
* @example
|
|
1444
|
+
* isEmpty(null); // true
|
|
1445
|
+
* isEmpty(''); // true
|
|
1446
|
+
* isEmpty(undefined); // true
|
|
1447
|
+
* isEmpty({}); // true
|
|
1448
|
+
* isEmpty([]); // true
|
|
1449
|
+
* isEmpty([1, 2, 3]); // false
|
|
1450
|
+
* isEmpty({ a: 1 }); // false
|
|
1451
|
+
*/
|
|
1452
|
+
const isEmpty = (value) => {
|
|
1453
|
+
while (isSignal(value)) {
|
|
1454
|
+
value = value();
|
|
1455
|
+
}
|
|
1456
|
+
return value === null || value === '' || value === undefined || (typeof value === 'object' && (JSON.stringify(value) === '{}' || JSON.stringify(value) === '[]'));
|
|
1457
|
+
};
|
|
1458
|
+
/**
|
|
1459
|
+
* Loại bỏ các thuộc tính của đối tượng dựa trên một hàm điều kiện
|
|
1460
|
+
* @param objData Đối tượng cần xử lý
|
|
1461
|
+
* @param predicate Hàm điều kiện để kiểm tra giá trị của thuộc tính. Nếu hàm trả về true thì thuộc tính đó sẽ bị loại bỏ
|
|
1462
|
+
* @returns Đối tượng mới sau khi đã loại bỏ các thuộc tính thỏa mãn điều kiện
|
|
1463
|
+
* @example
|
|
1464
|
+
* const obj = { a: 1, b: null, c: 3, d: undefined };
|
|
1465
|
+
* omitBy(obj, isNil); // { a: 1, c: 3 }
|
|
1466
|
+
*/
|
|
1467
|
+
const omitBy = (objData, predicate) => {
|
|
1468
|
+
if (!objData || typeof objData !== 'object' || Array.isArray(objData)) {
|
|
1469
|
+
return objData;
|
|
1470
|
+
}
|
|
1471
|
+
const newObj = {};
|
|
1472
|
+
Object.keys(objData).forEach(key => {
|
|
1473
|
+
const valueOfKey = get(objData, key);
|
|
1474
|
+
if (!predicate(valueOfKey)) {
|
|
1475
|
+
set(newObj, key, valueOfKey);
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
return newObj;
|
|
1479
|
+
};
|
|
1480
|
+
/**
|
|
1481
|
+
* Lấy giá trị từ đối tượng theo đường dẫn chỉ định
|
|
1482
|
+
*
|
|
1483
|
+
* Hàm này giúp bạn truy cập vào các thuộc tính sâu bên trong một đối tượng một cách an toàn,
|
|
1484
|
+
* tránh lỗi khi thuộc tính không tồn tại.
|
|
1485
|
+
*
|
|
1486
|
+
* @param obj Đối tượng nguồn cần lấy giá trị
|
|
1487
|
+
* @param path Đường dẫn đến thuộc tính cần lấy. Có thể là:
|
|
1488
|
+
* - Chuỗi: 'user.profile.name' hoặc 'items[0].title'
|
|
1489
|
+
* - Mảng: ['user', 'profile', 'name'] hoặc ['items', '0', 'title']
|
|
1490
|
+
* - Chuỗi rỗng '': trả về chính đối tượng gốc
|
|
1491
|
+
* @param defaultValue Giá trị mặc định trả về khi không tìm thấy thuộc tính (mặc định: undefined)
|
|
1492
|
+
* @param keepLastValueIfSignal Có giữ nguyên signal cuối cùng hay không (mặc định: false - sẽ gọi signal())
|
|
1493
|
+
* @returns Giá trị tìm được hoặc giá trị mặc định
|
|
1494
|
+
*
|
|
1495
|
+
* @example
|
|
1496
|
+
* // Ví dụ cơ bản
|
|
1497
|
+
* const user = { name: 'John', age: 30 };
|
|
1498
|
+
* get(user, 'name'); // 'John'
|
|
1499
|
+
* get(user, 'email'); // undefined
|
|
1500
|
+
* get(user, 'email', 'no-email'); // 'no-email'
|
|
1501
|
+
*
|
|
1502
|
+
* @example
|
|
1503
|
+
* // Truyền path rỗng - trả về chính đối tượng gốc
|
|
1504
|
+
* const data = { name: 'Alice', age: 25 };
|
|
1505
|
+
* get(data, ''); // { name: 'Alice', age: 25 } (chính đối tượng data)
|
|
1506
|
+
* get(data, '', 'default'); // { name: 'Alice', age: 25 } (bỏ qua defaultValue)
|
|
1507
|
+
*
|
|
1508
|
+
* @example
|
|
1509
|
+
* // Truy cập thuộc tính sâu
|
|
1510
|
+
* const data = {
|
|
1511
|
+
* user: {
|
|
1512
|
+
* profile: {
|
|
1513
|
+
* name: 'Alice',
|
|
1514
|
+
* settings: { theme: 'dark' }
|
|
1515
|
+
* }
|
|
1516
|
+
* }
|
|
1517
|
+
* };
|
|
1518
|
+
* get(data, 'user.profile.name'); // 'Alice'
|
|
1519
|
+
* get(data, 'user.profile.settings.theme'); // 'dark'
|
|
1520
|
+
* get(data, 'user.profile.avatar', 'default.jpg'); // 'default.jpg'
|
|
1521
|
+
*
|
|
1522
|
+
* @example
|
|
1523
|
+
* // Truy cập mảng
|
|
1524
|
+
* const items = [
|
|
1525
|
+
* { name: 'Item 1', price: 100 },
|
|
1526
|
+
* { name: 'Item 2', price: 200 }
|
|
1527
|
+
* ];
|
|
1528
|
+
* get(items, '[0].name'); // 'Item 1'
|
|
1529
|
+
* get(items, '[1].name'); // 'Item 2'
|
|
1530
|
+
* get(items, '[2].name', 'Not found'); // 'Not found'
|
|
1531
|
+
*
|
|
1532
|
+
* @example
|
|
1533
|
+
* // Sử dụng với mảng path
|
|
1534
|
+
* const nested = { a: { b: { c: 'deep value' } } };
|
|
1535
|
+
* get(nested, ['a', 'b', 'c']); // 'deep value'
|
|
1536
|
+
* get(nested, ['a', 'b', 'd'], 'default'); // 'default'
|
|
1537
|
+
*
|
|
1538
|
+
* @example
|
|
1539
|
+
* // Trường hợp đặc biệt
|
|
1540
|
+
* get(null, 'any.path'); // undefined
|
|
1541
|
+
* get(undefined, 'any.path', 'fallback'); // 'fallback'
|
|
1542
|
+
*/
|
|
1543
|
+
const get = (obj, path, defaultValue = undefined, keepLastValueIfSignal) => {
|
|
1544
|
+
if (isNil(obj)) {
|
|
1545
|
+
return defaultValue;
|
|
1452
1546
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1456
|
-
const getKeyCacheByArrayObject = (keyCache, argumentsValue) => {
|
|
1457
|
-
if (!keyCache || !argumentsValue) {
|
|
1458
|
-
return '';
|
|
1547
|
+
while (isSignal(obj)) {
|
|
1548
|
+
obj = obj();
|
|
1459
1549
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1550
|
+
if (path === '') {
|
|
1551
|
+
return obj;
|
|
1552
|
+
}
|
|
1553
|
+
if (obj instanceof HttpParams) {
|
|
1554
|
+
return obj.get(`${path}`);
|
|
1555
|
+
}
|
|
1556
|
+
if (obj instanceof DOMRect) {
|
|
1557
|
+
return obj[path];
|
|
1558
|
+
}
|
|
1559
|
+
const paths = Array.isArray(path) ? path : path.replace(/\[(\d+)]/g, '.$1').split('.').filter(key => key);
|
|
1560
|
+
for (const index in paths) {
|
|
1561
|
+
const key = paths[index];
|
|
1562
|
+
if (obj instanceof CSSStyleDeclaration) {
|
|
1563
|
+
obj = obj[key];
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1566
|
+
if (obj instanceof HTMLElement) {
|
|
1567
|
+
obj = obj[key];
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
if (isNil(obj) || !Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1571
|
+
return defaultValue;
|
|
1572
|
+
}
|
|
1573
|
+
const val = isSignal(obj[key]) && !keepLastValueIfSignal ? obj[key]() : obj[key];
|
|
1574
|
+
obj = val;
|
|
1575
|
+
}
|
|
1576
|
+
return obj;
|
|
1577
|
+
};
|
|
1578
|
+
/**
|
|
1579
|
+
* Thiết lập giá trị cho một thuộc tính trong đối tượng theo đường dẫn chỉ định
|
|
1580
|
+
* @param obj Đối tượng cần thiết lập giá trị
|
|
1581
|
+
* @param path Đường dẫn đến thuộc tính, có thể là chuỗi (vd: 'a.b.c') hoặc mảng (vd: ['a', 'b', 'c'])
|
|
1582
|
+
* @param value Giá trị cần thiết lập
|
|
1583
|
+
* @returns Đối tượng sau khi đã thiết lập giá trị
|
|
1584
|
+
* @throws Error nếu tham số đầu tiên không phải là đối tượng
|
|
1585
|
+
* @example
|
|
1586
|
+
* const obj = { a: { b: 1 } };
|
|
1587
|
+
* set(obj, 'a.b', 2); // { a: { b: 2 } }
|
|
1588
|
+
*/
|
|
1589
|
+
const set = (obj, path, value) => {
|
|
1590
|
+
if (!obj || (typeof obj !== "object" && !isSignal(obj)) || (isSignal(obj) && typeof obj() !== "object")) {
|
|
1591
|
+
throw new Error("The first argument must be an object");
|
|
1592
|
+
}
|
|
1593
|
+
if (obj instanceof HttpParams) {
|
|
1594
|
+
return obj.set(`${path}`, value);
|
|
1595
|
+
}
|
|
1596
|
+
const pathArray = Array.isArray(path) ? path : path.replace(/\[(\d+)]/g, '.[$1]').split('.').filter(key => key);
|
|
1597
|
+
let currentObjectByKey = isSignal(obj) ? obj() : obj;
|
|
1598
|
+
let preObjectByKey = obj;
|
|
1599
|
+
pathArray.forEach((key, index) => {
|
|
1600
|
+
if (index < pathArray.length - 1) {
|
|
1601
|
+
if (!(key in currentObjectByKey) || (typeof currentObjectByKey[key] !== "object" && !isSignal(currentObjectByKey[key]))) {
|
|
1602
|
+
const nextKey = pathArray[index + 1];
|
|
1603
|
+
key = key.replace(/\[(\d+)]/g, '$1');
|
|
1604
|
+
currentObjectByKey[key] = /\[(\d+)]/g.test(nextKey) ? [] : {};
|
|
1466
1605
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
});
|
|
1606
|
+
currentObjectByKey = key ? currentObjectByKey[key] : currentObjectByKey;
|
|
1607
|
+
preObjectByKey = currentObjectByKey;
|
|
1608
|
+
currentObjectByKey = isSignal(currentObjectByKey) ? currentObjectByKey() : currentObjectByKey;
|
|
1471
1609
|
return;
|
|
1472
1610
|
}
|
|
1473
|
-
|
|
1474
|
-
});
|
|
1475
|
-
const keyCachePlus = md5(keyBuild);
|
|
1476
|
-
const keyCacheMD5 = md5(keyCache);
|
|
1477
|
-
return `${keyCacheMD5}-${md5(`${keyCacheMD5}-${keyCachePlus}`)}`;
|
|
1478
|
-
};
|
|
1479
|
-
|
|
1480
|
-
let functionCheck = () => {
|
|
1481
|
-
return window.parent !== window.top;
|
|
1482
|
-
};
|
|
1483
|
-
const updateFunctionCheckEmbedFrame = (functionCustom) => {
|
|
1484
|
-
functionCheck = functionCustom;
|
|
1485
|
-
};
|
|
1486
|
-
const isEmbedFrame = () => {
|
|
1487
|
-
return functionCheck();
|
|
1488
|
-
};
|
|
1489
|
-
|
|
1490
|
-
const ERROR_MESSAGE_EMPTY_VALID = 'i18n_valid_empty_message';
|
|
1491
|
-
const ERROR_MESSAGE_PATTEN_VALID = 'i18n_valid_pattern_message';
|
|
1492
|
-
const ERROR_MESSAGE_MIN_VALID = 'i18n_message_error_input_min_value';
|
|
1493
|
-
const ERROR_MESSAGE_MAX_VALID = 'i18n_message_error_input_max_value';
|
|
1494
|
-
const ERROR_MESSAGE_MIN_LENGTH = 'i18n_message_error_input_min_length';
|
|
1495
|
-
const ERROR_MESSAGE_MAX_LENGTH = 'i18n_message_error_input_max_length';
|
|
1496
|
-
const CHARACTER_DATA_EMPTY = '__';
|
|
1497
|
-
const DEFAULT_START_PAGE_0 = 'defaultStartPage0';
|
|
1498
|
-
const COMMUNICATE_MICRO_PREFIX_TYPE = '3RD_INTEGRATE_MICRO_SITE_';
|
|
1499
|
-
const COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE = 'MICRO_SITES_ALL_MESSAGE';
|
|
1500
|
-
|
|
1501
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1502
|
-
class UtilsCommunicateMicroKeyGlobal {
|
|
1503
|
-
static KEY_MESSAGE_MODAL = 'LIBS_UI_MODEL_EVENT';
|
|
1504
|
-
}
|
|
1505
|
-
class UtilsCommunicateMicro {
|
|
1506
|
-
static initdEvent;
|
|
1507
|
-
static subs = new Map();
|
|
1508
|
-
static allMessageSub = new Subject();
|
|
1509
|
-
static initEvent(currentWindow, onDestroy) {
|
|
1510
|
-
if (this.initdEvent) {
|
|
1611
|
+
if (typeof currentObjectByKey !== "object") {
|
|
1511
1612
|
return;
|
|
1512
1613
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1614
|
+
// Gán giá trị ở cuối đường dẫn
|
|
1615
|
+
key = key.replace(/\[(\d+)]/g, '$1');
|
|
1616
|
+
const valueOfKey = currentObjectByKey[key];
|
|
1617
|
+
const valueOfKeyIsSignal = isSignal(valueOfKey);
|
|
1618
|
+
if (valueOfKeyIsSignal && (typeof valueOfKey() !== 'object' || valueOfKey() === null)) {
|
|
1619
|
+
valueOfKey.set(isSignal(value) ? value() : value);
|
|
1620
|
+
return;
|
|
1516
1621
|
}
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
return this.allMessageSub.next(event);
|
|
1523
|
-
}
|
|
1524
|
-
const sub = UtilsCommunicateMicro.GetMessage(type);
|
|
1525
|
-
if (!type || !data.response) {
|
|
1526
|
-
return;
|
|
1527
|
-
}
|
|
1528
|
-
try {
|
|
1529
|
-
if (type.includes(COMMUNICATE_MICRO_PREFIX_TYPE)) {
|
|
1530
|
-
data.response = JSON.parse(decrypt3rd(data.response));
|
|
1531
|
-
sub.next(event);
|
|
1532
|
-
this.allMessageSub.next(event);
|
|
1533
|
-
return;
|
|
1622
|
+
if (isSignal(preObjectByKey)) {
|
|
1623
|
+
preObjectByKey.update((data) => {
|
|
1624
|
+
const dataOfKey = data[key];
|
|
1625
|
+
if (isNil(dataOfKey) || !valueOfKeyIsSignal) {
|
|
1626
|
+
data[key] = value;
|
|
1534
1627
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
});
|
|
1545
|
-
UtilsCommunicateMicro.GetMessage(UtilsCache.typeKeyClearLocalStorage).pipe(filter(e => e.data.response !== UtilsCache.idService), takeUntil(onDestroy)).subscribe(() => {
|
|
1546
|
-
console.log('clear all cache by event');
|
|
1547
|
-
UtilsCache.ClearAll();
|
|
1548
|
-
});
|
|
1549
|
-
}
|
|
1550
|
-
static PostMessageToParent(data) {
|
|
1551
|
-
data = this.convertData(data);
|
|
1552
|
-
try {
|
|
1553
|
-
if (isEmbedFrame()) {
|
|
1554
|
-
window?.parent?.postMessage(data, "*");
|
|
1555
|
-
return;
|
|
1556
|
-
}
|
|
1557
|
-
window?.top?.postMessage(data, "*");
|
|
1628
|
+
if (valueOfKeyIsSignal) {
|
|
1629
|
+
valueOfKey.set(isSignal(value) ? value() : value);
|
|
1630
|
+
}
|
|
1631
|
+
if (Array.isArray(data)) {
|
|
1632
|
+
return [...data];
|
|
1633
|
+
}
|
|
1634
|
+
return { ...data };
|
|
1635
|
+
});
|
|
1636
|
+
return;
|
|
1558
1637
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1638
|
+
if (valueOfKeyIsSignal) {
|
|
1639
|
+
valueOfKey.set(isSignal(value) ? value() : value);
|
|
1640
|
+
return;
|
|
1561
1641
|
}
|
|
1642
|
+
currentObjectByKey[key] = value;
|
|
1643
|
+
});
|
|
1644
|
+
return obj;
|
|
1645
|
+
};
|
|
1646
|
+
/**
|
|
1647
|
+
* Tạo một bản sao sâu của một đối tượng hoặc giá trị bất kỳ
|
|
1648
|
+
* @param data Dữ liệu cần sao chép
|
|
1649
|
+
* @param options Tùy chọn cấu hình
|
|
1650
|
+
* @param options.ignoreSignal Nếu true, sẽ không sao chép các signal mà trả về signal gốc
|
|
1651
|
+
* @param seen WeakMap để theo dõi các tham chiếu đã được sao chép, tránh lặp vô hạn với các tham chiếu vòng
|
|
1652
|
+
* @returns Bản sao sâu của dữ liệu đầu vào
|
|
1653
|
+
* @example
|
|
1654
|
+
* const obj = {
|
|
1655
|
+
* a: 1,
|
|
1656
|
+
* b: { c: 2 },
|
|
1657
|
+
* d: [1, 2, 3]
|
|
1658
|
+
* };
|
|
1659
|
+
* const clone = cloneDeep(obj);
|
|
1660
|
+
* // clone là một bản sao hoàn toàn độc lập của obj
|
|
1661
|
+
*/
|
|
1662
|
+
const cloneDeep = (data, options = { ignoreSignal: false }, seen = new WeakMap()) => {
|
|
1663
|
+
if (data === null || (typeof data !== 'object' && !isSignal(data))) {
|
|
1664
|
+
return data;
|
|
1562
1665
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1666
|
+
if (seen.has(data)) {
|
|
1667
|
+
return seen.get(data);
|
|
1668
|
+
}
|
|
1669
|
+
if (data instanceof HttpParams) {
|
|
1670
|
+
return new UtilsHttpParamsRequest(undefined, data);
|
|
1671
|
+
}
|
|
1672
|
+
if (data instanceof Date) {
|
|
1673
|
+
return new Date(data.getTime());
|
|
1674
|
+
}
|
|
1675
|
+
if (dayjs.isDayjs(data)) {
|
|
1676
|
+
return getDayjs({ date: data.valueOf() });
|
|
1677
|
+
}
|
|
1678
|
+
if (data instanceof RegExp) {
|
|
1679
|
+
return new RegExp(data.source, data.flags);
|
|
1680
|
+
}
|
|
1681
|
+
if (data instanceof Map) {
|
|
1682
|
+
const mapCopy = new Map();
|
|
1683
|
+
seen.set(data, mapCopy);
|
|
1684
|
+
data.forEach((val, key) => {
|
|
1685
|
+
mapCopy.set(cloneDeep(key, options, seen), cloneDeep(val, options, seen));
|
|
1568
1686
|
});
|
|
1687
|
+
return mapCopy;
|
|
1569
1688
|
}
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1689
|
+
if (data instanceof Set) {
|
|
1690
|
+
const setCopy = new Set();
|
|
1691
|
+
seen.set(data, setCopy);
|
|
1692
|
+
data.forEach(val => {
|
|
1693
|
+
setCopy.add(cloneDeep(val, options, seen));
|
|
1694
|
+
});
|
|
1695
|
+
return setCopy;
|
|
1696
|
+
}
|
|
1697
|
+
if (Array.isArray(data)) {
|
|
1698
|
+
seen.set(data, data.map(item => cloneDeep(item, options, seen)));
|
|
1699
|
+
return seen.get(data);
|
|
1700
|
+
}
|
|
1701
|
+
if (data instanceof File || data instanceof Blob || Object.prototype.toString.call(data) === '[object File]') {
|
|
1702
|
+
return data;
|
|
1576
1703
|
}
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
const type = data.type;
|
|
1583
|
-
if (type.includes(COMMUNICATE_MICRO_PREFIX_TYPE)) {
|
|
1584
|
-
try {
|
|
1585
|
-
JSON.parse(decrypt3rd(data.response));
|
|
1586
|
-
return data;
|
|
1587
|
-
}
|
|
1588
|
-
catch (_) {
|
|
1589
|
-
data.response = encrypt3rd(JSON.stringify(data.response));
|
|
1590
|
-
return data;
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
try {
|
|
1594
|
-
JSON.parse(decrypt(data.response));
|
|
1595
|
-
return data;
|
|
1596
|
-
}
|
|
1597
|
-
catch (_) {
|
|
1598
|
-
data.response = encrypt(JSON.stringify(data.response));
|
|
1704
|
+
if (data instanceof TemplateRef || data instanceof ElementRef || data instanceof Element || data instanceof Promise || data instanceof Observable) {
|
|
1705
|
+
return data;
|
|
1706
|
+
}
|
|
1707
|
+
if (isSignal(data)) {
|
|
1708
|
+
if (options?.ignoreSignal) {
|
|
1599
1709
|
return data;
|
|
1600
1710
|
}
|
|
1711
|
+
seen.set(data, signal(cloneDeep(data(), options, seen)));
|
|
1712
|
+
return seen.get(data);
|
|
1601
1713
|
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
if (
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
sub = new Subject();
|
|
1610
|
-
this.subs.set(messageType, sub);
|
|
1611
|
-
return sub;
|
|
1612
|
-
}
|
|
1613
|
-
return sub;
|
|
1714
|
+
const result = {};
|
|
1715
|
+
seen.set(data, result);
|
|
1716
|
+
for (const key in data) {
|
|
1717
|
+
const value = data[key];
|
|
1718
|
+
if (value instanceof HttpParams) {
|
|
1719
|
+
result[key] = new UtilsHttpParamsRequest(undefined, value);
|
|
1720
|
+
continue;
|
|
1614
1721
|
}
|
|
1615
|
-
if (
|
|
1616
|
-
|
|
1722
|
+
if (dayjs.isDayjs(value)) {
|
|
1723
|
+
result[key] = getDayjs({ date: value.valueOf() });
|
|
1724
|
+
continue;
|
|
1617
1725
|
}
|
|
1618
|
-
if (
|
|
1619
|
-
|
|
1726
|
+
if (value instanceof TemplateRef || value instanceof ElementRef || value instanceof Element || value instanceof Promise || value instanceof Observable) {
|
|
1727
|
+
result[key] = value;
|
|
1728
|
+
continue;
|
|
1620
1729
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
if (sub) {
|
|
1624
|
-
return sub;
|
|
1730
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
1731
|
+
result[key] = cloneDeep(value, options, seen);
|
|
1625
1732
|
}
|
|
1626
|
-
sub = new Subject();
|
|
1627
|
-
this.subs.set(types, sub);
|
|
1628
|
-
this.initSubject(sub, messageType);
|
|
1629
|
-
return sub;
|
|
1630
1733
|
}
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1734
|
+
return result;
|
|
1735
|
+
};
|
|
1736
|
+
/**
|
|
1737
|
+
* Chuyển đổi một mảng các đối tượng thành một đối tượng với khóa được chỉ định
|
|
1738
|
+
* @param data Mảng các đối tượng cần chuyển đổi
|
|
1739
|
+
* @param key Tên thuộc tính được sử dụng làm khóa trong đối tượng kết quả
|
|
1740
|
+
* @returns Đối tượng với các giá trị từ mảng được đánh key theo thuộc tính đã chỉ định
|
|
1741
|
+
* @example
|
|
1742
|
+
* const data = [
|
|
1743
|
+
* { id: 1, name: 'John' },
|
|
1744
|
+
* { id: 2, name: 'Jane' }
|
|
1745
|
+
* ];
|
|
1746
|
+
* keyBy(data, 'id');
|
|
1747
|
+
* // Kết quả: {
|
|
1748
|
+
* // '1': { id: 1, name: 'John' },
|
|
1749
|
+
* // '2': { id: 2, name: 'Jane' }
|
|
1750
|
+
* // }
|
|
1751
|
+
*/
|
|
1752
|
+
const keyBy = (data, key) => {
|
|
1753
|
+
if (!data || !data.length || !key) {
|
|
1754
|
+
return {};
|
|
1637
1755
|
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
class UtilsCache {
|
|
1643
|
-
static CACHE_EXPIRE_TIME_DEFAULT = 5 * 60;
|
|
1644
|
-
static CACHE_EXPIRE_NONE = -1;
|
|
1645
|
-
static idService = uuid();
|
|
1646
|
-
static typeKeyClearLocalStorage = 'LIBS_UI_CLEAR_LOCAL_STORAGE_EVENT';
|
|
1647
|
-
static languageKeyCache = 'SR3xQKxHgffiCevPQRralg';
|
|
1648
|
-
static listKeyKeepWhenClearALll = Array();
|
|
1649
|
-
static initdEvent;
|
|
1650
|
-
static storage;
|
|
1651
|
-
static dbName = 'libs-ui-cache';
|
|
1652
|
-
static itemIndexByKey = 'key';
|
|
1653
|
-
static dbVersion = 1;
|
|
1654
|
-
static db = null;
|
|
1655
|
-
static init(config) {
|
|
1656
|
-
if (this.initdEvent) {
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
this.initdEvent = true;
|
|
1660
|
-
if (config.indexedDBName) {
|
|
1661
|
-
this.dbName = config.indexedDBName;
|
|
1756
|
+
return data.reduce((dir, nextItem) => {
|
|
1757
|
+
const valueOfKey = get(nextItem, key);
|
|
1758
|
+
if (typeof valueOfKey !== 'string' && typeof valueOfKey !== 'number' && typeof valueOfKey !== 'boolean') {
|
|
1759
|
+
return dir;
|
|
1662
1760
|
}
|
|
1663
|
-
if (
|
|
1664
|
-
|
|
1761
|
+
if (!Object.keys(dir).includes(`${valueOfKey}`)) {
|
|
1762
|
+
dir[`${valueOfKey}`] = nextItem;
|
|
1665
1763
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1764
|
+
return dir;
|
|
1765
|
+
}, {});
|
|
1766
|
+
};
|
|
1767
|
+
/**
|
|
1768
|
+
* Nhóm các đối tượng trong một mảng thành các nhóm dựa trên một thuộc tính cụ thể
|
|
1769
|
+
* @param data Mảng các đối tượng cần nhóm
|
|
1770
|
+
* @param key Tên thuộc tính được sử dụng làm khóa nhóm
|
|
1771
|
+
* @returns Đối tượng với các giá trị từ mảng được nhóm theo thuộc tính đã chỉ định
|
|
1772
|
+
* @example
|
|
1773
|
+
* const data = [
|
|
1774
|
+
* { id: 1, name: 'John' },
|
|
1775
|
+
* { id: 2, name: 'Jane' },
|
|
1776
|
+
* { id: 1, name: 'John' }
|
|
1777
|
+
* ];
|
|
1778
|
+
* groupBy(data, 'id');
|
|
1779
|
+
* // Kết quả: {
|
|
1780
|
+
* // '1': [
|
|
1781
|
+
* // { id: 1, name: 'John' },
|
|
1782
|
+
* // { id: 1, name: 'John' }
|
|
1783
|
+
* // ],
|
|
1784
|
+
* // '2': [
|
|
1785
|
+
* // { id: 2, name: 'Jane' }
|
|
1786
|
+
* // }
|
|
1787
|
+
*/
|
|
1788
|
+
const groupBy = (data, key) => {
|
|
1789
|
+
if (!data || !data.length || !Object.keys(get(data, '0')).length || !key) {
|
|
1790
|
+
return {};
|
|
1791
|
+
}
|
|
1792
|
+
return data.reduce((dir, nextItem) => {
|
|
1793
|
+
const valueOfKey = get(nextItem, key);
|
|
1794
|
+
if (typeof valueOfKey !== 'string' && typeof valueOfKey !== 'number' && typeof valueOfKey !== 'boolean') {
|
|
1795
|
+
return dir;
|
|
1668
1796
|
}
|
|
1669
|
-
if (
|
|
1670
|
-
|
|
1797
|
+
if (!Object.keys(dir).includes(`${valueOfKey}`)) {
|
|
1798
|
+
dir[`${valueOfKey}`] = [];
|
|
1671
1799
|
}
|
|
1800
|
+
dir[`${valueOfKey}`].push(nextItem);
|
|
1801
|
+
return dir;
|
|
1802
|
+
}, {});
|
|
1803
|
+
};
|
|
1804
|
+
/**
|
|
1805
|
+
* Tạo một mảng các số từ giá trị bắt đầu đến giá trị kết thúc với bước nhảy tùy chọn
|
|
1806
|
+
* @param start Giá trị bắt đầu của dãy số. Nếu chỉ có một tham số, đây sẽ là giá trị kết thúc và giá trị bắt đầu sẽ là 0
|
|
1807
|
+
* @param end Giá trị kết thúc của dãy số (tùy chọn)
|
|
1808
|
+
* @param step Bước nhảy giữa các số trong dãy (tùy chọn). Mặc định là 1 nếu end > start, -1 nếu end < start
|
|
1809
|
+
* @returns Mảng các số từ start đến end với bước nhảy step
|
|
1810
|
+
* @example
|
|
1811
|
+
* range(4); // [0, 1, 2, 3]
|
|
1812
|
+
* range(1, 5); // [1, 2, 3, 4]
|
|
1813
|
+
* range(0, 20, 5); // [0, 5, 10, 15]
|
|
1814
|
+
* range(5, 2); // [5, 4, 3]
|
|
1815
|
+
*/
|
|
1816
|
+
const range = (start, end, step) => {
|
|
1817
|
+
if (end === undefined || end === null) {
|
|
1818
|
+
end = start;
|
|
1819
|
+
start = 0;
|
|
1672
1820
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1821
|
+
if (!step) {
|
|
1822
|
+
step = end < 0 ? -1 : 1;
|
|
1823
|
+
}
|
|
1824
|
+
if (end < start && step > 0) {
|
|
1825
|
+
step *= -1;
|
|
1826
|
+
}
|
|
1827
|
+
const valueStartByStep = step + start;
|
|
1828
|
+
const direction = start < end ? 'asc' : 'desc';
|
|
1829
|
+
if ((direction === 'asc' && (valueStartByStep < start || valueStartByStep > end)) || (direction === 'desc' && (valueStartByStep > start || valueStartByStep < end))) {
|
|
1830
|
+
return [start];
|
|
1831
|
+
}
|
|
1832
|
+
const arr = new Array();
|
|
1833
|
+
for (let index = 0; index < Math.abs(end - start); index++) {
|
|
1834
|
+
let value = start + index * step;
|
|
1835
|
+
if (index === 0) {
|
|
1836
|
+
value = start;
|
|
1676
1837
|
}
|
|
1677
|
-
|
|
1838
|
+
if ((direction === 'asc' && (value < start || value > end)) || (direction === 'desc' && (value > start || value < end))) {
|
|
1839
|
+
return arr;
|
|
1840
|
+
}
|
|
1841
|
+
arr.push(value);
|
|
1678
1842
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
1843
|
+
return arr;
|
|
1844
|
+
};
|
|
1845
|
+
/**
|
|
1846
|
+
* So sánh hai giá trị bất kỳ có bằng nhau hay không
|
|
1847
|
+
* @param value1 Giá trị thứ nhất cần so sánh
|
|
1848
|
+
* @param value2 Giá trị thứ hai cần so sánh
|
|
1849
|
+
* @param exactlyPosition Có so sánh chính xác vị trí các phần tử trong mảng hay không
|
|
1850
|
+
* @returns true nếu hai giá trị bằng nhau, false nếu không bằng nhau
|
|
1851
|
+
* @example
|
|
1852
|
+
* isEqual([1,2,3], [1,2,3]); // true
|
|
1853
|
+
* isEqual([1,2,3], [3,2,1]); // true khi exactlyPosition = false
|
|
1854
|
+
* isEqual([1,2,3], [3,2,1]); // false khi exactlyPosition = true
|
|
1855
|
+
* isEqual({a:1}, {a:1}); // true
|
|
1856
|
+
*/
|
|
1857
|
+
const isEqual = (value1, value2, options) => {
|
|
1858
|
+
const { exactlyPosition = false, ignoreExactlyDataType = false } = options || {};
|
|
1859
|
+
if (value1 === value2 || (value1 === null && value2 === null) || (value1 === undefined && value2 === undefined)) {
|
|
1860
|
+
return true;
|
|
1681
1861
|
}
|
|
1682
|
-
|
|
1683
|
-
return
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
};
|
|
1692
|
-
request.onsuccess = () => {
|
|
1693
|
-
this.db = request.result;
|
|
1694
|
-
resolve(true);
|
|
1695
|
-
};
|
|
1696
|
-
request.onerror = (event) => {
|
|
1697
|
-
console.trace('Error opening IndexedDB:', event);
|
|
1698
|
-
resolve(false);
|
|
1699
|
-
};
|
|
1700
|
-
});
|
|
1862
|
+
if (ignoreExactlyDataType) {
|
|
1863
|
+
return isEqual(isNil(value1) ? undefined : `${value1}`, isNil(value2) ? undefined : `${value2}`);
|
|
1864
|
+
}
|
|
1865
|
+
// Handle signals
|
|
1866
|
+
while (isSignal(value1)) {
|
|
1867
|
+
value1 = value1();
|
|
1868
|
+
}
|
|
1869
|
+
while (isSignal(value2)) {
|
|
1870
|
+
value2 = value2();
|
|
1701
1871
|
}
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1872
|
+
if (typeof value1 !== 'object' || typeof value2 !== 'object' || (Array.isArray(value1) && !Array.isArray(value2)) || (!Array.isArray(value1) && Array.isArray(value2))) {
|
|
1873
|
+
return false;
|
|
1874
|
+
}
|
|
1875
|
+
if (Array.isArray(value1)) {
|
|
1876
|
+
if (value1.length !== value2.length) {
|
|
1877
|
+
return false;
|
|
1705
1878
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
return null;
|
|
1879
|
+
if (!exactlyPosition) {
|
|
1880
|
+
return !value1.some(item => !value2.includes(item));
|
|
1709
1881
|
}
|
|
1710
|
-
return
|
|
1882
|
+
return !value1.some((item, index) => !isEqual(item, value2[index], options));
|
|
1711
1883
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1884
|
+
if (Object.keys(value1).length !== Object.keys(value2).length) {
|
|
1885
|
+
return false;
|
|
1886
|
+
}
|
|
1887
|
+
return !Object.keys(value1).some((key) => !isEqual(value1[key], value2[key], options));
|
|
1888
|
+
};
|
|
1889
|
+
/**
|
|
1890
|
+
* Loại bỏ các phần tử trùng lặp trong mảng dựa trên một thuộc tính chỉ định
|
|
1891
|
+
* @param data Mảng dữ liệu cần xử lý
|
|
1892
|
+
* @param key Tên thuộc tính dùng để so sánh trùng lặp. Nếu không có key thì so sánh trực tiếp giá trị
|
|
1893
|
+
* @returns Mảng mới chứa các phần tử không trùng lặp
|
|
1894
|
+
* @example
|
|
1895
|
+
* const arr = [
|
|
1896
|
+
* { id: 1, name: 'A' },
|
|
1897
|
+
* { id: 2, name: 'B' },
|
|
1898
|
+
* { id: 1, name: 'C' }
|
|
1899
|
+
* ];
|
|
1900
|
+
* uniqBy(arr, 'id'); // [{ id: 1, name: 'A' }, { id: 2, name: 'B' }]
|
|
1901
|
+
*
|
|
1902
|
+
* const numbers = [1, 2, 2, 3, 3];
|
|
1903
|
+
* uniqBy(numbers); // [1, 2, 3]
|
|
1904
|
+
*
|
|
1905
|
+
* const numbersSignal = [signal(1), signal(2), signal(3), signal(2), signal(5), signal(4), signal(1), signal(6), signal(7), signal(6)];
|
|
1906
|
+
* uniqBy(numbersSignal); // [signal(1), signal(2), signal(3), signal(5), signal(4), signal(6), signal(7)]
|
|
1907
|
+
*/
|
|
1908
|
+
const uniqBy = (data, key) => {
|
|
1909
|
+
if (!key || !data?.length || typeof get(data, '0') !== 'object') {
|
|
1910
|
+
// Xử lý mảng chứa signal values
|
|
1911
|
+
if (data[0] && isSignal(data[0])) {
|
|
1912
|
+
const seen = new Set();
|
|
1913
|
+
return data.filter(item => {
|
|
1914
|
+
const value = `${get(item, '')}`;
|
|
1915
|
+
if (seen.has(value)) {
|
|
1916
|
+
return false;
|
|
1718
1917
|
}
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
}
|
|
1723
|
-
catch (error) {
|
|
1724
|
-
console.trace(`LocalStorage `, error);
|
|
1725
|
-
return this.getLocalStorageFake();
|
|
1918
|
+
seen.add(value);
|
|
1919
|
+
return true;
|
|
1920
|
+
});
|
|
1726
1921
|
}
|
|
1922
|
+
// Xử lý mảng primitive values
|
|
1923
|
+
return Array.from(new Set(data));
|
|
1727
1924
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1925
|
+
const dataUnique = keyBy(data, key);
|
|
1926
|
+
return Object.keys(dataUnique).map(key => dataUnique[key]);
|
|
1927
|
+
};
|
|
1928
|
+
const generateInterface = (obj, interfaceName) => {
|
|
1929
|
+
const generateType = (value) => {
|
|
1930
|
+
if (value === null) {
|
|
1931
|
+
return 'null';
|
|
1731
1932
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
this.storage[key] = value;
|
|
1736
|
-
},
|
|
1737
|
-
getItem: (key) => {
|
|
1738
|
-
const value = localStorage.getItem(key);
|
|
1739
|
-
if (value) {
|
|
1740
|
-
return value;
|
|
1741
|
-
}
|
|
1742
|
-
if (!this.storage || isNil(this.storage[key])) {
|
|
1743
|
-
return null;
|
|
1744
|
-
}
|
|
1745
|
-
localStorage.setItem(key, this.storage[key]);
|
|
1746
|
-
return this.storage?.[key];
|
|
1747
|
-
},
|
|
1748
|
-
removeItem: (key) => {
|
|
1749
|
-
delete this.storage?.[key];
|
|
1750
|
-
localStorage.removeItem(key);
|
|
1751
|
-
},
|
|
1752
|
-
clear: () => {
|
|
1753
|
-
this.storage = {};
|
|
1754
|
-
localStorage.clear();
|
|
1755
|
-
}
|
|
1756
|
-
};
|
|
1757
|
-
}
|
|
1758
|
-
static getLocalStorageFake() {
|
|
1759
|
-
if (!this.storage) {
|
|
1760
|
-
this.storage = {};
|
|
1933
|
+
const type = typeof value;
|
|
1934
|
+
if (type === 'string') {
|
|
1935
|
+
return 'string';
|
|
1761
1936
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
this.storage[key] = value;
|
|
1765
|
-
},
|
|
1766
|
-
getItem: (key) => {
|
|
1767
|
-
return this.storage?.[key];
|
|
1768
|
-
},
|
|
1769
|
-
removeItem: (key) => {
|
|
1770
|
-
delete this.storage?.[key];
|
|
1771
|
-
},
|
|
1772
|
-
clear: () => {
|
|
1773
|
-
this.storage = {};
|
|
1774
|
-
}
|
|
1775
|
-
};
|
|
1776
|
-
}
|
|
1777
|
-
static async GetAsync(key, default_value, isKeyMD5 = false) {
|
|
1778
|
-
key = isKeyMD5 ? key : md5(key);
|
|
1779
|
-
return new Promise(async (resolve) => {
|
|
1780
|
-
const objectStore = await this.getObjectStore();
|
|
1781
|
-
if (!objectStore) {
|
|
1782
|
-
return resolve(default_value);
|
|
1783
|
-
}
|
|
1784
|
-
const request = objectStore.get(key);
|
|
1785
|
-
request.onsuccess = () => {
|
|
1786
|
-
if (!request.result) {
|
|
1787
|
-
return resolve(default_value);
|
|
1788
|
-
}
|
|
1789
|
-
const data = JSON.parse(decrypt(request.result.value));
|
|
1790
|
-
if (data.expire === this.CACHE_EXPIRE_NONE) {
|
|
1791
|
-
return resolve(data.json);
|
|
1792
|
-
}
|
|
1793
|
-
const currentMillisecond = (new Date().valueOf() / 1000);
|
|
1794
|
-
if (data.expire < currentMillisecond) {
|
|
1795
|
-
return resolve(default_value);
|
|
1796
|
-
}
|
|
1797
|
-
return resolve(data.json);
|
|
1798
|
-
};
|
|
1799
|
-
request.onerror = () => {
|
|
1800
|
-
console.trace(`Get key ${key} Error, return default value: ${default_value}`);
|
|
1801
|
-
return resolve(default_value);
|
|
1802
|
-
};
|
|
1803
|
-
});
|
|
1804
|
-
}
|
|
1805
|
-
static Get(key, default_value) {
|
|
1806
|
-
if (!key) {
|
|
1807
|
-
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
1937
|
+
if (type === 'number') {
|
|
1938
|
+
return 'number';
|
|
1808
1939
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
1940
|
+
if (type === 'boolean') {
|
|
1941
|
+
return 'boolean';
|
|
1812
1942
|
}
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
if (data.expire === this.CACHE_EXPIRE_NONE) {
|
|
1816
|
-
return data.value ?? default_value;
|
|
1817
|
-
}
|
|
1818
|
-
const currentMillisecond = (new Date().valueOf() / 1000);
|
|
1819
|
-
if (data.expire < currentMillisecond) {
|
|
1820
|
-
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
1821
|
-
}
|
|
1822
|
-
return data.value;
|
|
1943
|
+
if (type === 'undefined') {
|
|
1944
|
+
return 'any';
|
|
1823
1945
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
console.trace(`Get key ${key} Error, return default value: ${default_value}`, error);
|
|
1827
|
-
return this.GetDefaultValueBySpecificKey(key, default_value);
|
|
1946
|
+
if (value instanceof Date) {
|
|
1947
|
+
return 'Date';
|
|
1828
1948
|
}
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
const objectStore = await this.getObjectStore();
|
|
1836
|
-
key = isKeyMD5 ? key : md5(key);
|
|
1837
|
-
try {
|
|
1838
|
-
const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
|
|
1839
|
-
const data = {
|
|
1840
|
-
value: encrypt(JSON.stringify({ json: value, expire: currentMillisecond })),
|
|
1841
|
-
};
|
|
1842
|
-
data[this.itemIndexByKey] = key;
|
|
1843
|
-
if (!objectStore) {
|
|
1844
|
-
console.trace(`Can not open object store`);
|
|
1845
|
-
return resolve({ key, messageError: 'Can not open object store' });
|
|
1846
|
-
}
|
|
1847
|
-
const request = objectStore?.put(data);
|
|
1848
|
-
request.onsuccess = () => {
|
|
1849
|
-
console.log(`Set key ${key} Success`);
|
|
1850
|
-
resolve(request.result);
|
|
1851
|
-
};
|
|
1852
|
-
request.onerror = (error) => {
|
|
1853
|
-
console.trace(`Set key ${key} Error`);
|
|
1854
|
-
resolve({ key, messageError: get(error, 'message') });
|
|
1855
|
-
};
|
|
1949
|
+
if (value instanceof RegExp) {
|
|
1950
|
+
return 'RegExp';
|
|
1951
|
+
}
|
|
1952
|
+
if (Array.isArray(value)) {
|
|
1953
|
+
if (value.length === 0) {
|
|
1954
|
+
return 'Array<any>';
|
|
1856
1955
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1956
|
+
return `Array<${generateType(value[0])}>`;
|
|
1957
|
+
}
|
|
1958
|
+
if (type === 'object') {
|
|
1959
|
+
let interfaceStr = '{\n';
|
|
1960
|
+
for (const key in value) {
|
|
1961
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
1962
|
+
const valueType = generateType(value[key]);
|
|
1963
|
+
interfaceStr += ` ${key}: ${valueType};\n`;
|
|
1964
|
+
}
|
|
1860
1965
|
}
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1966
|
+
interfaceStr += '}';
|
|
1967
|
+
return interfaceStr;
|
|
1968
|
+
}
|
|
1969
|
+
return 'any';
|
|
1970
|
+
};
|
|
1971
|
+
const interfaceStr = `interface ${interfaceName} ${generateType(obj)}`;
|
|
1972
|
+
return interfaceStr;
|
|
1973
|
+
};
|
|
1974
|
+
|
|
1975
|
+
;
|
|
1976
|
+
const step = 20;
|
|
1977
|
+
const percent = 0.05;
|
|
1978
|
+
const colorStepContrastFromOrigin = (color, stepNumber) => {
|
|
1979
|
+
return colorContrastFromOrigin(color).find(item => item.step === stepNumber);
|
|
1980
|
+
};
|
|
1981
|
+
const colorContrastFromOrigin = (color) => {
|
|
1982
|
+
const parsedColorsArray = parseColorValues(color);
|
|
1983
|
+
const colors = [];
|
|
1984
|
+
let calculatedShades = [];
|
|
1985
|
+
let calculatedTints = [];
|
|
1986
|
+
if (parsedColorsArray !== null) {
|
|
1987
|
+
for (let i = 0; i < parsedColorsArray.length; i++) {
|
|
1988
|
+
calculatedShades = calculateShades(parsedColorsArray[i]);
|
|
1989
|
+
calculatedTints = calculateTints(parsedColorsArray[i]);
|
|
1872
1990
|
}
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
return false;
|
|
1991
|
+
for (let i = 0; i <= step; i++) {
|
|
1992
|
+
colors.push({ step: i * 5, label: `${i * 5}%`, dark: `#${calculatedShades[i]}`, light: `#${calculatedTints[i]}` });
|
|
1876
1993
|
}
|
|
1877
1994
|
}
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1995
|
+
return colors;
|
|
1996
|
+
};
|
|
1997
|
+
const parseColorValues = (colorValues) => {
|
|
1998
|
+
let colorValuesArray = colorValues.match(/\b[0-9A-Fa-f]{3}\b|[0-9A-Fa-f]{6}\b/g);
|
|
1999
|
+
if (colorValuesArray) {
|
|
2000
|
+
colorValuesArray = colorValuesArray.map((item) => {
|
|
2001
|
+
if (item.length === 3) {
|
|
2002
|
+
let newItem = item.toString().split('');
|
|
2003
|
+
newItem = newItem.reduce((acc, it) => {
|
|
2004
|
+
return acc + it + it;
|
|
2005
|
+
}, '');
|
|
2006
|
+
return newItem;
|
|
1883
2007
|
}
|
|
1884
|
-
|
|
1885
|
-
request.onsuccess = () => {
|
|
1886
|
-
resolve({ clearSuccess: true });
|
|
1887
|
-
};
|
|
1888
|
-
request.onerror = (event) => {
|
|
1889
|
-
console.trace('Error deleting Key:', get(event.target.error, 'message'));
|
|
1890
|
-
resolve({ messageError: get(event.target.error, 'message'), clearSuccess: false });
|
|
1891
|
-
};
|
|
2008
|
+
return item;
|
|
1892
2009
|
});
|
|
1893
2010
|
}
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
2011
|
+
return colorValuesArray;
|
|
2012
|
+
};
|
|
2013
|
+
const calculateShades = (colorValue) => {
|
|
2014
|
+
return calculate(colorValue, rgbShade).concat("000000");
|
|
2015
|
+
};
|
|
2016
|
+
const calculateTints = (colorValue) => {
|
|
2017
|
+
return calculate(colorValue, rgbTint).concat("ffffff");
|
|
2018
|
+
};
|
|
2019
|
+
const calculate = (colorValue, shadeOrTint) => {
|
|
2020
|
+
const color = hexToRGB(colorValue);
|
|
2021
|
+
const shadeValues = [];
|
|
2022
|
+
for (let i = 0; i < step; i++) {
|
|
2023
|
+
shadeValues[i] = rgbToHex(shadeOrTint(color, i));
|
|
1899
2024
|
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
request.onerror = (event) => {
|
|
1912
|
-
console.trace('Error deleting key:', get(event.target.error, 'message'));
|
|
1913
|
-
resolve({ messageError: get(event.target.error, 'message'), clearSuccess: false });
|
|
1914
|
-
};
|
|
1915
|
-
});
|
|
2025
|
+
return shadeValues;
|
|
2026
|
+
};
|
|
2027
|
+
const rgbShade = (rgb, i) => { return { red: rgb.red * (1 - percent * i), green: rgb.green * (1 - percent * i), blue: rgb.blue * (1 - percent * i) }; };
|
|
2028
|
+
const rgbTint = (rgb, i) => { return { red: rgb.red + (255 - rgb.red) * i * percent, green: rgb.green + (255 - rgb.green) * i * percent, blue: rgb.blue + (255 - rgb.blue) * i * percent }; };
|
|
2029
|
+
const rgbToHex = (rgb) => { return intToHex(rgb.red) + intToHex(rgb.green) + intToHex(rgb.blue); };
|
|
2030
|
+
const hexToRGB = (colorValue) => { return { red: parseInt(colorValue.substr(0, 2), 16), green: parseInt(colorValue.substr(2, 2), 16), blue: parseInt(colorValue.substr(4, 2), 16) }; };
|
|
2031
|
+
const intToHex = (rgbint) => { return pad(Math.min(Math.max(Math.round(rgbint), 0), 255).toString(16), 2); };
|
|
2032
|
+
const pad = (number, length) => {
|
|
2033
|
+
let str = '' + number;
|
|
2034
|
+
while (str.length < length) {
|
|
2035
|
+
str = '0' + str;
|
|
1916
2036
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
const keys = [...this.listKeyKeepWhenClearALll];
|
|
1928
|
-
Object.keys(this.LocalStorage).forEach(key => {
|
|
1929
|
-
if (key.includes('kc-callback-')) {
|
|
1930
|
-
keys.push(key);
|
|
1931
|
-
}
|
|
1932
|
-
});
|
|
1933
|
-
const stores = this.GetDataByKeys(Array.from(keys));
|
|
1934
|
-
this.LocalStorage.clear();
|
|
1935
|
-
this.SetDataByKey(stores);
|
|
2037
|
+
return str;
|
|
2038
|
+
};
|
|
2039
|
+
const listColorDefine = ['#E62222', '#B81B1B', '#EB4E4E', '#F97316', '#C75C12', '#FA8F45', '#FFB700', '#CC9200', '#FFC533', '#84CC16', '#6AA312', '#9dd645', '#00BC62', '#00A757', '#33DA8A', '#06B6D4', '#1B59C4', '#4E8CF7', '#0EA5E9',
|
|
2040
|
+
'#1B59C4', '#4E8CF7', '#226FF5', '#1B59C4', '#4E8CF7', '#6366F1', '#4F52C1', '#8285F4', '#5B04B3', '#49038F', '#7C36C2', '#D946EF', '#AE38BF', '#E16BF2', '#EC4899', '#BD3A7A', '#F06DAD', '#F43F5E', '#C3324B', '#F6657E', '#757380', '#5E5C66', '#918F99',
|
|
2041
|
+
'#202020', '#1A1A1A', '#4D4D4D'
|
|
2042
|
+
];
|
|
2043
|
+
const getColorById = (str) => {
|
|
2044
|
+
let hashString = 0;
|
|
2045
|
+
if (!str) {
|
|
2046
|
+
return '';
|
|
1936
2047
|
}
|
|
1937
|
-
|
|
1938
|
-
const
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
stores.set(key, this.LocalStorage.getItem(key));
|
|
1942
|
-
return;
|
|
1943
|
-
}
|
|
1944
|
-
stores.set(key, this.Get(key));
|
|
1945
|
-
});
|
|
1946
|
-
return stores;
|
|
2048
|
+
for (let i = 0; i < str.length; i++) {
|
|
2049
|
+
const char = str.charCodeAt(i);
|
|
2050
|
+
hashString = ((hashString << 5) - hashString) + char;
|
|
2051
|
+
hashString = hashString & hashString;
|
|
1947
2052
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
2053
|
+
return listColorDefine[Math.abs(hashString) % listColorDefine.length];
|
|
2054
|
+
};
|
|
2055
|
+
|
|
2056
|
+
class UtilsKeyCodeConstant {
|
|
2057
|
+
static MAC_ENTER = 3;
|
|
2058
|
+
static BACKSPACE = 8;
|
|
2059
|
+
static TAB = 9;
|
|
2060
|
+
static NUM_CENTER = 12;
|
|
2061
|
+
static ENTER = 13;
|
|
2062
|
+
static SHIFT = 16;
|
|
2063
|
+
static CONTROL = 17;
|
|
2064
|
+
static ALT = 18;
|
|
2065
|
+
static PAUSE = 19;
|
|
2066
|
+
static CAPS_LOCK = 20;
|
|
2067
|
+
static ESCAPE = 27;
|
|
2068
|
+
static SPACE = 32;
|
|
2069
|
+
static PAGE_UP = 33;
|
|
2070
|
+
static PAGE_DOWN = 34;
|
|
2071
|
+
static END = 35;
|
|
2072
|
+
static HOME = 36;
|
|
2073
|
+
static LEFT_ARROW = 37;
|
|
2074
|
+
static UP_ARROW = 38;
|
|
2075
|
+
static RIGHT_ARROW = 39;
|
|
2076
|
+
static DOWN_ARROW = 40;
|
|
2077
|
+
static PLUS_SIGN = 43;
|
|
2078
|
+
static PRINT_SCREEN = 44;
|
|
2079
|
+
static INSERT = 45;
|
|
2080
|
+
static DELETE = 46;
|
|
2081
|
+
static ZERO = 48;
|
|
2082
|
+
static ONE = 49;
|
|
2083
|
+
static TWO = 50;
|
|
2084
|
+
static THREE = 51;
|
|
2085
|
+
static FOUR = 52;
|
|
2086
|
+
static FIVE = 53;
|
|
2087
|
+
static SIX = 54;
|
|
2088
|
+
static SEVEN = 55;
|
|
2089
|
+
static EIGHT = 56;
|
|
2090
|
+
static NINE = 57;
|
|
2091
|
+
static FF_SEMICOLON = 59; // Firefox (Gecko) fires this for semicolon instead of 186
|
|
2092
|
+
static FF_EQUALS = 61; // Firefox (Gecko) fires this for equals instead of 187
|
|
2093
|
+
static QUESTION_MARK = 63;
|
|
2094
|
+
static AT_SIGN = 64;
|
|
2095
|
+
static A = 65;
|
|
2096
|
+
static B = 66;
|
|
2097
|
+
static C = 67;
|
|
2098
|
+
static D = 68;
|
|
2099
|
+
static E = 69;
|
|
2100
|
+
static F = 70;
|
|
2101
|
+
static G = 71;
|
|
2102
|
+
static H = 72;
|
|
2103
|
+
static I = 73;
|
|
2104
|
+
static J = 74;
|
|
2105
|
+
static K = 75;
|
|
2106
|
+
static L = 76;
|
|
2107
|
+
static M = 77;
|
|
2108
|
+
static N = 78;
|
|
2109
|
+
static O = 79;
|
|
2110
|
+
static P = 80;
|
|
2111
|
+
static Q = 81;
|
|
2112
|
+
static R = 82;
|
|
2113
|
+
static S = 83;
|
|
2114
|
+
static T = 84;
|
|
2115
|
+
static U = 85;
|
|
2116
|
+
static V = 86;
|
|
2117
|
+
static W = 87;
|
|
2118
|
+
static X = 88;
|
|
2119
|
+
static Y = 89;
|
|
2120
|
+
static Z = 90;
|
|
2121
|
+
static META = 91; // WIN_KEY_LEFT
|
|
2122
|
+
static MAC_WK_CMD_LEFT = 91;
|
|
2123
|
+
static MAC_WK_CMD_RIGHT = 93;
|
|
2124
|
+
static CONTEXT_MENU = 93;
|
|
2125
|
+
static NUMPAD_ZERO = 96;
|
|
2126
|
+
static NUMPAD_ONE = 97;
|
|
2127
|
+
static NUMPAD_TWO = 98;
|
|
2128
|
+
static NUMPAD_THREE = 99;
|
|
2129
|
+
static NUMPAD_FOUR = 100;
|
|
2130
|
+
static NUMPAD_FIVE = 101;
|
|
2131
|
+
static NUMPAD_SIX = 102;
|
|
2132
|
+
static NUMPAD_SEVEN = 103;
|
|
2133
|
+
static NUMPAD_EIGHT = 104;
|
|
2134
|
+
static NUMPAD_NINE = 105;
|
|
2135
|
+
static NUMPAD_MULTIPLY = 106;
|
|
2136
|
+
static NUMPAD_PLUS = 107;
|
|
2137
|
+
static NUMPAD_MINUS = 109;
|
|
2138
|
+
static NUMPAD_PERIOD = 110;
|
|
2139
|
+
static NUMPAD_DIVIDE = 111;
|
|
2140
|
+
static F1 = 112;
|
|
2141
|
+
static F2 = 113;
|
|
2142
|
+
static F3 = 114;
|
|
2143
|
+
static F4 = 115;
|
|
2144
|
+
static F5 = 116;
|
|
2145
|
+
static F6 = 117;
|
|
2146
|
+
static F7 = 118;
|
|
2147
|
+
static F8 = 119;
|
|
2148
|
+
static F9 = 120;
|
|
2149
|
+
static F10 = 121;
|
|
2150
|
+
static F11 = 122;
|
|
2151
|
+
static F12 = 123;
|
|
2152
|
+
static NUM_LOCK = 144;
|
|
2153
|
+
static SCROLL_LOCK = 145;
|
|
2154
|
+
static FIRST_MEDIA = 166;
|
|
2155
|
+
static FF_MINUS = 173;
|
|
2156
|
+
static MUTE = 173; // Firefox (Gecko) fires 181 for MUTE
|
|
2157
|
+
static VOLUME_DOWN = 174; // Firefox (Gecko) fires 182 for VOLUME_DOWN
|
|
2158
|
+
static VOLUME_UP = 175; // Firefox (Gecko) fires 183 for VOLUME_UP
|
|
2159
|
+
static FF_MUTE = 181;
|
|
2160
|
+
static FF_VOLUME_DOWN = 182;
|
|
2161
|
+
static LAST_MEDIA = 183;
|
|
2162
|
+
static FF_VOLUME_UP = 183;
|
|
2163
|
+
static SEMICOLON = 186; // Firefox (Gecko) fires 59 for SEMICOLON
|
|
2164
|
+
static EQUALS = 187; // Firefox (Gecko) fires 61 for EQUALS
|
|
2165
|
+
static COMMA = 188;
|
|
2166
|
+
static DASH = 189; // Firefox (Gecko) fires 173 for DASH/MINUS
|
|
2167
|
+
static PERIOD = 190;
|
|
2168
|
+
static SLASH = 191;
|
|
2169
|
+
static APOSTROPHE = 192;
|
|
2170
|
+
static TILDE = 192;
|
|
2171
|
+
static OPEN_SQUARE_BRACKET = 219;
|
|
2172
|
+
static BACKSLASH = 220;
|
|
2173
|
+
static CLOSE_SQUARE_BRACKET = 221;
|
|
2174
|
+
static SINGLE_QUOTE = 222;
|
|
2175
|
+
static MAC_META = 224;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2179
|
+
const getKeyCacheByArrayObject = (keyCache, argumentsValue) => {
|
|
2180
|
+
if (!keyCache || !argumentsValue) {
|
|
2181
|
+
return '';
|
|
1959
2182
|
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
if (
|
|
1964
|
-
|
|
2183
|
+
let keyBuild = `${JSON.stringify(argumentsValue.slice(1))}-key-cache-plus`;
|
|
2184
|
+
argumentsValue.forEach((item) => {
|
|
2185
|
+
if (typeof item === 'object') {
|
|
2186
|
+
if (Array.isArray(item)) {
|
|
2187
|
+
keyBuild = `${keyBuild}${JSON.stringify(item)}`;
|
|
2188
|
+
return;
|
|
1965
2189
|
}
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
const data = e.target.result;
|
|
1971
|
-
if (!Array.isArray(data)) {
|
|
1972
|
-
return resolve({});
|
|
1973
|
-
}
|
|
1974
|
-
data.forEach(obj => {
|
|
1975
|
-
if (obj[this.itemIndexByKey].startsWith(keyCacheStartWith)) {
|
|
1976
|
-
this.ClearAsync(obj[this.itemIndexByKey], true);
|
|
1977
|
-
}
|
|
1978
|
-
});
|
|
1979
|
-
return resolve({});
|
|
1980
|
-
};
|
|
1981
|
-
request.onerror = () => {
|
|
1982
|
-
return resolve({});
|
|
1983
|
-
};
|
|
1984
|
-
});
|
|
1985
|
-
}
|
|
1986
|
-
static DeleteKeyStartWith(keyCache, isMD5 = false) {
|
|
1987
|
-
keyCache = isMD5 ? md5(keyCache) : keyCache;
|
|
1988
|
-
const keys = Object.keys(this.LocalStorage);
|
|
1989
|
-
if (!keys || !keys.length) {
|
|
2190
|
+
const keys = (item instanceof HttpParams ? item.keys() : Object.keys(item)).sort(((str1, str2) => str1.localeCompare(str2)));
|
|
2191
|
+
keys.forEach(key => {
|
|
2192
|
+
keyBuild = `${keyBuild}${JSON.stringify(get(item, key))}`;
|
|
2193
|
+
});
|
|
1990
2194
|
return;
|
|
1991
2195
|
}
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
static DeleteDatabaseIndexDB(dbName) {
|
|
1999
|
-
return new Promise((resolve) => {
|
|
2000
|
-
dbName = (dbName || this.dbName);
|
|
2001
|
-
const request = indexedDB.deleteDatabase(dbName);
|
|
2002
|
-
request.onsuccess = () => {
|
|
2003
|
-
console.trace('Database deleted successfully');
|
|
2004
|
-
resolve({ deleteSuccess: true });
|
|
2005
|
-
};
|
|
2006
|
-
request.onerror = (event) => {
|
|
2007
|
-
console.trace('Error deleting database:', event.target.error);
|
|
2008
|
-
resolve({ messageError: get(event.target.error, 'message'), deleteSuccess: false });
|
|
2009
|
-
};
|
|
2010
|
-
request.onblocked = () => {
|
|
2011
|
-
console.trace('Delete request is blocked');
|
|
2012
|
-
resolve({ messageError: 'Delete request is blocked', deleteSuccess: false });
|
|
2013
|
-
};
|
|
2014
|
-
});
|
|
2015
|
-
}
|
|
2016
|
-
}
|
|
2196
|
+
keyBuild = `${keyBuild}${item}`;
|
|
2197
|
+
});
|
|
2198
|
+
const keyCachePlus = md5(keyBuild);
|
|
2199
|
+
const keyCacheMD5 = md5(keyCache);
|
|
2200
|
+
return `${keyCacheMD5}-${md5(`${keyCacheMD5}-${keyCachePlus}`)}`;
|
|
2201
|
+
};
|
|
2017
2202
|
|
|
2018
2203
|
const formatNumber = (value) => {
|
|
2019
2204
|
const lang = UtilsCache.getLang();
|
|
@@ -2194,185 +2379,6 @@ const convertSignalToObject = (data, isCloneDeep = true, seen = new WeakMap()) =
|
|
|
2194
2379
|
return result;
|
|
2195
2380
|
};
|
|
2196
2381
|
|
|
2197
|
-
dayjs.extend(localeData);
|
|
2198
|
-
dayjs.extend(updateLocale);
|
|
2199
|
-
dayjs.extend(utc);
|
|
2200
|
-
dayjs.extend(timezone);
|
|
2201
|
-
dayjs.extend(customParseFormat);
|
|
2202
|
-
let timeZoneSetup = "Asia/Ho_Chi_Minh";
|
|
2203
|
-
const setDefaultTimeZone = (localeZone = timeZoneSetup) => {
|
|
2204
|
-
timeZoneSetup = localeZone;
|
|
2205
|
-
dayjs.tz.setDefault(localeZone);
|
|
2206
|
-
};
|
|
2207
|
-
let functionFormatDate = undefined;
|
|
2208
|
-
const updateFunctionFormatDate = (functionCustom) => {
|
|
2209
|
-
functionFormatDate = functionCustom;
|
|
2210
|
-
};
|
|
2211
|
-
/**
|
|
2212
|
-
* @description Lấy đối tượng dayjs theo config
|
|
2213
|
-
* @param config nếu không có config sẽ trả về đối tượng dayjs là thời gian hiện tại
|
|
2214
|
-
* @param config.date thời gian cần lấy
|
|
2215
|
-
* @param config.returnDayjsIfConfigDateNotExist true nếu muốn trả về đối tượng dayjs nếu config.date không có
|
|
2216
|
-
* @param config.utc true nếu muốn lấy thời gian UTC
|
|
2217
|
-
* @param config.formatOfDate định dạng thời gian đang được truyền vào
|
|
2218
|
-
*/
|
|
2219
|
-
const getDayjs = (config) => {
|
|
2220
|
-
if (!config) {
|
|
2221
|
-
return dayjs().tz();
|
|
2222
|
-
}
|
|
2223
|
-
config.date = !config.date && config.returnDayjsIfConfigDateNotExist ? dayjs().tz() : config.date;
|
|
2224
|
-
if (typeof config.date === 'number') {
|
|
2225
|
-
config.date = dayjs.unix(config.date);
|
|
2226
|
-
}
|
|
2227
|
-
if (!config.date) {
|
|
2228
|
-
return undefined;
|
|
2229
|
-
}
|
|
2230
|
-
let { date, utc, formatOfDate } = config;
|
|
2231
|
-
while (isSignal(date)) {
|
|
2232
|
-
date = date();
|
|
2233
|
-
}
|
|
2234
|
-
while (isSignal(utc)) {
|
|
2235
|
-
utc = utc();
|
|
2236
|
-
}
|
|
2237
|
-
while (isSignal(formatOfDate)) {
|
|
2238
|
-
formatOfDate = formatOfDate();
|
|
2239
|
-
}
|
|
2240
|
-
if (utc) {
|
|
2241
|
-
if (formatOfDate) {
|
|
2242
|
-
return dayjs(date, formatOfDate).utc();
|
|
2243
|
-
}
|
|
2244
|
-
const dateInputIsUTC = (typeof date === 'object' && date.isUTC()) || (typeof date === 'string' && date.includes('Z'));
|
|
2245
|
-
if (dateInputIsUTC) {
|
|
2246
|
-
return dayjs(date);
|
|
2247
|
-
}
|
|
2248
|
-
return dayjs(date).utc();
|
|
2249
|
-
}
|
|
2250
|
-
if (typeof date === 'string' && !date.includes('Z') && !date.includes('+')) {
|
|
2251
|
-
return (formatOfDate ? dayjs.tz(date, formatOfDate, config.localeZone || timeZoneSetup) : dayjs.tz(date, config.localeZone || timeZoneSetup));
|
|
2252
|
-
}
|
|
2253
|
-
return (formatOfDate ? dayjs(date, formatOfDate) : dayjs(date)).tz();
|
|
2254
|
-
};
|
|
2255
|
-
/**
|
|
2256
|
-
* @description Kiểm tra xem hai ngày có khác nhau không (khác ngày trong tuần)
|
|
2257
|
-
* @param date1 ngày thứ nhất cần so sánh
|
|
2258
|
-
* @param date2 ngày thứ hai cần so sánh
|
|
2259
|
-
* @returns true nếu hai ngày khác nhau, false nếu giống nhau hoặc không thể so sánh
|
|
2260
|
-
*/
|
|
2261
|
-
const isDifferenceDay = (date1, date2) => {
|
|
2262
|
-
if (isDifferenceMonth(date1, date2)) {
|
|
2263
|
-
return true;
|
|
2264
|
-
}
|
|
2265
|
-
const day1 = getDayjs({ date: date1 })?.day();
|
|
2266
|
-
const day2 = getDayjs({ date: date2 })?.day();
|
|
2267
|
-
return day1 !== day2;
|
|
2268
|
-
};
|
|
2269
|
-
/**
|
|
2270
|
-
* @description Kiểm tra xem hai ngày có khác tháng không
|
|
2271
|
-
* @param date1 ngày thứ nhất cần so sánh
|
|
2272
|
-
* @param date2 ngày thứ hai cần so sánh
|
|
2273
|
-
* @returns true nếu hai ngày khác tháng, false nếu cùng tháng hoặc không thể so sánh
|
|
2274
|
-
*/
|
|
2275
|
-
const isDifferenceMonth = (date1, date2) => {
|
|
2276
|
-
if (isDifferenceYear(date1, date2)) {
|
|
2277
|
-
return true;
|
|
2278
|
-
}
|
|
2279
|
-
const month1 = getDayjs({ date: date1 })?.month();
|
|
2280
|
-
const month2 = getDayjs({ date: date2 })?.month();
|
|
2281
|
-
return month1 !== month2;
|
|
2282
|
-
};
|
|
2283
|
-
/**
|
|
2284
|
-
* @description Kiểm tra xem hai ngày có khác năm không
|
|
2285
|
-
* @param date1 ngày thứ nhất cần so sánh
|
|
2286
|
-
* @param date2 ngày thứ hai cần so sánh
|
|
2287
|
-
* @returns true nếu hai ngày khác năm, false nếu cùng năm hoặc không thể so sánh
|
|
2288
|
-
*/
|
|
2289
|
-
const isDifferenceYear = (date1, date2) => {
|
|
2290
|
-
const year1 = getDayjs({ date: date1 })?.year();
|
|
2291
|
-
const year2 = getDayjs({ date: date2 })?.year();
|
|
2292
|
-
return year1 !== year2;
|
|
2293
|
-
};
|
|
2294
|
-
/**
|
|
2295
|
-
* @description Lấy ra chuỗi thời gian hiển thị theo định dạng và ngôn ngữ
|
|
2296
|
-
* @param date thời gian cần định dạng
|
|
2297
|
-
* @param format định dạng thời gian muốn lấy ra
|
|
2298
|
-
* @param lang lấy theo ngôn ngữ
|
|
2299
|
-
*/
|
|
2300
|
-
const formatDate = (date, formatOutput = 'YYYY/MM/DD HH:mm', lang, formatInput) => {
|
|
2301
|
-
if (!date) {
|
|
2302
|
-
return '';
|
|
2303
|
-
}
|
|
2304
|
-
lang = lang || UtilsCache.getLang();
|
|
2305
|
-
if (functionFormatDate) {
|
|
2306
|
-
return functionFormatDate(date, formatOutput, lang);
|
|
2307
|
-
}
|
|
2308
|
-
date = getDayjs({ date, formatOfDate: formatInput }).locale(lang);
|
|
2309
|
-
if (lang === 'vi') {
|
|
2310
|
-
dayjs.updateLocale('vi', {
|
|
2311
|
-
monthsShort: 'Thg 1_Thg 2_Thg 3_Thg 4_Thg 5_Thg 6_Thg 7_Thg 8_Thg 9_Thg 10_Thg 11_Thg 12'.split('_')
|
|
2312
|
-
});
|
|
2313
|
-
}
|
|
2314
|
-
return date.format(getFormatData(getTypeByFormat(formatOutput), lang)) || '';
|
|
2315
|
-
};
|
|
2316
|
-
const getTypeByFormat = (format) => {
|
|
2317
|
-
if (format === 'dm' || format === 'dmy' || format === 'dmy hm' || format === 'my') {
|
|
2318
|
-
return format;
|
|
2319
|
-
}
|
|
2320
|
-
if (format === 'DD/MM/YYYY' || format === 'YYYY-MM-DD' || format === 'dd/MM/yyyy' || format === 'dd-MM-yyyy' || format === 'dd/mm/yyyy') {
|
|
2321
|
-
return 'dmy';
|
|
2322
|
-
}
|
|
2323
|
-
if (format === 'MM-DD' || format === 'dd/MM' || format === 'dd/mm') {
|
|
2324
|
-
return 'dm';
|
|
2325
|
-
}
|
|
2326
|
-
if (format === 'M/YYYY' || format === 'YYYY-MM' || format === 'MM/yyyy') {
|
|
2327
|
-
return 'my';
|
|
2328
|
-
}
|
|
2329
|
-
if (format === 'YYYY/MM/DD hh:mm:ss' || format === 'dmy hms' || format === 'dd/mm/yyyy hh:mm:ss') {
|
|
2330
|
-
return 'dmy hms';
|
|
2331
|
-
}
|
|
2332
|
-
if (format === 'hh:mm' || format === 'HH:mm') {
|
|
2333
|
-
return 'hh:mm';
|
|
2334
|
-
}
|
|
2335
|
-
if (format === 'hh:mm A' || format === 'HH:mm A') {
|
|
2336
|
-
return 'hh:mm A';
|
|
2337
|
-
}
|
|
2338
|
-
return 'dmy hm';
|
|
2339
|
-
};
|
|
2340
|
-
const getFormatData = (type, lang) => {
|
|
2341
|
-
switch (type) {
|
|
2342
|
-
case 'dm':
|
|
2343
|
-
if (lang === 'vi') {
|
|
2344
|
-
return 'D MMM';
|
|
2345
|
-
}
|
|
2346
|
-
return 'MMM D';
|
|
2347
|
-
case 'dmy':
|
|
2348
|
-
if (lang === 'vi') {
|
|
2349
|
-
return 'D MMM, YYYY';
|
|
2350
|
-
}
|
|
2351
|
-
return 'MMM D, YYYY';
|
|
2352
|
-
case 'dmy hm':
|
|
2353
|
-
if (lang === 'vi') {
|
|
2354
|
-
return 'D MMM, YYYY HH:mm';
|
|
2355
|
-
}
|
|
2356
|
-
return 'MMM D, YYYY HH:mm';
|
|
2357
|
-
case 'my':
|
|
2358
|
-
if (lang === 'vi') {
|
|
2359
|
-
return 'MMM, YYYY';
|
|
2360
|
-
}
|
|
2361
|
-
return 'MMM YYYY ';
|
|
2362
|
-
case 'dmy hms':
|
|
2363
|
-
if (lang === 'vi') {
|
|
2364
|
-
return 'D MMM, YYYY HH:mm:ss';
|
|
2365
|
-
}
|
|
2366
|
-
return 'MMM D, YYYY HH:mm:ss';
|
|
2367
|
-
case 'hh:mm':
|
|
2368
|
-
case 'HH:mm':
|
|
2369
|
-
return 'HH:mm';
|
|
2370
|
-
case 'hh:mm A':
|
|
2371
|
-
case 'HH:mm A':
|
|
2372
|
-
return 'HH:mm A';
|
|
2373
|
-
}
|
|
2374
|
-
};
|
|
2375
|
-
|
|
2376
2382
|
const ENCODE_URI_PATTERN = /%([0-9A-F]{2})/g;
|
|
2377
2383
|
const decodeURI = (value) => {
|
|
2378
2384
|
return decodeURIComponent(value.split('').map((c) => {
|
|
@@ -2531,7 +2537,7 @@ const convertBlobToFile = (blob, fileName) => {
|
|
|
2531
2537
|
return new File([blob], name, { type: blob.type, lastModified: Date.now() });
|
|
2532
2538
|
};
|
|
2533
2539
|
const convertUrlToFile = (url, fileName) => {
|
|
2534
|
-
return new Promise((resolve) => {
|
|
2540
|
+
return new Promise((resolve, reject) => {
|
|
2535
2541
|
const xhr = new XMLHttpRequest();
|
|
2536
2542
|
xhr.onload = function () {
|
|
2537
2543
|
const reader = new FileReader();
|
|
@@ -2541,6 +2547,9 @@ const convertUrlToFile = (url, fileName) => {
|
|
|
2541
2547
|
};
|
|
2542
2548
|
reader.readAsDataURL(xhr.response);
|
|
2543
2549
|
};
|
|
2550
|
+
xhr.onerror = (err) => {
|
|
2551
|
+
reject(err);
|
|
2552
|
+
};
|
|
2544
2553
|
xhr.open('GET', url);
|
|
2545
2554
|
xhr.responseType = 'blob';
|
|
2546
2555
|
xhr.send();
|