@ramathibodi/nuxt-commons 0.1.73 → 4.0.0
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/README.md +81 -55
- package/dist/module.json +4 -4
- package/dist/module.mjs +5 -4
- package/dist/runtime/bridges/authentication.d.ts +21 -0
- package/dist/runtime/bridges/authentication.js +20 -0
- package/dist/runtime/bridges/graphql.d.ts +17 -0
- package/dist/runtime/bridges/graphql.js +45 -0
- package/dist/runtime/components/Alert.d.vue.ts +3 -0
- package/dist/runtime/components/Alert.vue +17 -22
- package/dist/runtime/components/Alert.vue.d.ts +3 -0
- package/dist/runtime/components/BarcodeReader.d.vue.ts +9 -0
- package/dist/runtime/components/BarcodeReader.vue +56 -73
- package/dist/runtime/components/BarcodeReader.vue.d.ts +9 -0
- package/dist/runtime/components/ExportCSV.d.vue.ts +55 -0
- package/dist/runtime/components/ExportCSV.vue +39 -68
- package/dist/runtime/components/ExportCSV.vue.d.ts +55 -0
- package/dist/runtime/components/FileBtn.d.vue.ts +53 -0
- package/dist/runtime/components/FileBtn.vue +23 -38
- package/dist/runtime/components/FileBtn.vue.d.ts +53 -0
- package/dist/runtime/components/ImportCSV.d.vue.ts +52 -0
- package/dist/runtime/components/ImportCSV.vue +60 -99
- package/dist/runtime/components/ImportCSV.vue.d.ts +52 -0
- package/dist/runtime/components/MrzReader.d.vue.ts +19 -0
- package/dist/runtime/components/MrzReader.vue +128 -0
- package/dist/runtime/components/MrzReader.vue.d.ts +19 -0
- package/dist/runtime/components/SplitterPanel.d.vue.ts +15 -0
- package/dist/runtime/components/SplitterPanel.vue +18 -27
- package/dist/runtime/components/SplitterPanel.vue.d.ts +15 -0
- package/dist/runtime/components/TabsGroup.d.vue.ts +19 -0
- package/dist/runtime/components/TabsGroup.vue +8 -12
- package/dist/runtime/components/TabsGroup.vue.d.ts +19 -0
- package/dist/runtime/components/TextBarcode.d.vue.ts +12 -0
- package/dist/runtime/components/TextBarcode.vue +22 -33
- package/dist/runtime/components/TextBarcode.vue.d.ts +12 -0
- package/dist/runtime/components/device/IdCardButton.d.vue.ts +57 -0
- package/dist/runtime/components/device/IdCardButton.vue +30 -55
- package/dist/runtime/components/device/IdCardButton.vue.d.ts +57 -0
- package/dist/runtime/components/device/IdCardWebSocket.d.vue.ts +55 -0
- package/dist/runtime/components/device/IdCardWebSocket.vue +104 -153
- package/dist/runtime/components/device/IdCardWebSocket.vue.d.ts +55 -0
- package/dist/runtime/components/device/Scanner.d.vue.ts +66 -0
- package/dist/runtime/components/device/Scanner.vue +97 -166
- package/dist/runtime/components/device/Scanner.vue.d.ts +66 -0
- package/dist/runtime/components/dialog/Confirm.d.vue.ts +37 -0
- package/dist/runtime/components/dialog/Confirm.vue +30 -47
- package/dist/runtime/components/dialog/Confirm.vue.d.ts +37 -0
- package/dist/runtime/components/dialog/Host.d.vue.ts +9 -0
- package/dist/runtime/components/dialog/Host.vue +34 -53
- package/dist/runtime/components/dialog/Host.vue.d.ts +9 -0
- package/dist/runtime/components/dialog/Index.d.vue.ts +24 -0
- package/dist/runtime/components/dialog/Index.vue +20 -28
- package/dist/runtime/components/dialog/Index.vue.d.ts +24 -0
- package/dist/runtime/components/dialog/Loading.d.vue.ts +21 -0
- package/dist/runtime/components/dialog/Loading.vue +12 -17
- package/dist/runtime/components/dialog/Loading.vue.d.ts +21 -0
- package/dist/runtime/components/dialog/default/Confirm.d.vue.ts +40 -0
- package/dist/runtime/components/dialog/default/Confirm.vue +29 -50
- package/dist/runtime/components/dialog/default/Confirm.vue.d.ts +40 -0
- package/dist/runtime/components/dialog/default/Loading.d.vue.ts +23 -0
- package/dist/runtime/components/dialog/default/Loading.vue +12 -17
- package/dist/runtime/components/dialog/default/Loading.vue.d.ts +23 -0
- package/dist/runtime/components/dialog/default/Notify.d.vue.ts +23 -0
- package/dist/runtime/components/dialog/default/Notify.vue +19 -36
- package/dist/runtime/components/dialog/default/Notify.vue.d.ts +23 -0
- package/dist/runtime/components/dialog/default/Printing.d.vue.ts +21 -0
- package/dist/runtime/components/dialog/default/Printing.vue +13 -17
- package/dist/runtime/components/dialog/default/Printing.vue.d.ts +21 -0
- package/dist/runtime/components/dialog/default/VerifyUser.d.vue.ts +29 -0
- package/dist/runtime/components/dialog/default/VerifyUser.vue +44 -70
- package/dist/runtime/components/dialog/default/VerifyUser.vue.d.ts +29 -0
- package/dist/runtime/components/document/Form.d.vue.ts +9 -0
- package/dist/runtime/components/document/Form.vue +27 -34
- package/dist/runtime/components/document/Form.vue.d.ts +9 -0
- package/dist/runtime/components/document/TemplateBuilder.d.vue.ts +24 -0
- package/dist/runtime/components/document/TemplateBuilder.vue +154 -182
- package/dist/runtime/components/document/TemplateBuilder.vue.d.ts +24 -0
- package/dist/runtime/components/form/ActionPad.d.vue.ts +114 -0
- package/dist/runtime/components/form/ActionPad.vue +48 -73
- package/dist/runtime/components/form/ActionPad.vue.d.ts +114 -0
- package/dist/runtime/components/form/Birthdate.d.vue.ts +38 -0
- package/dist/runtime/components/form/Birthdate.vue +44 -64
- package/dist/runtime/components/form/Birthdate.vue.d.ts +38 -0
- package/dist/runtime/components/form/CheckboxGroup.d.vue.ts +41 -0
- package/dist/runtime/components/form/CheckboxGroup.vue +34 -52
- package/dist/runtime/components/form/CheckboxGroup.vue.d.ts +41 -0
- package/dist/runtime/components/form/CodeEditor.d.vue.ts +25 -0
- package/dist/runtime/components/form/CodeEditor.vue +18 -28
- package/dist/runtime/components/form/CodeEditor.vue.d.ts +25 -0
- package/dist/runtime/components/form/Date.d.vue.ts +86 -0
- package/dist/runtime/components/form/Date.vue +109 -150
- package/dist/runtime/components/form/Date.vue.d.ts +86 -0
- package/dist/runtime/components/form/DateTime.d.vue.ts +36 -0
- package/dist/runtime/components/form/DateTime.vue +94 -131
- package/dist/runtime/components/form/DateTime.vue.d.ts +36 -0
- package/dist/runtime/components/form/Dialog.d.vue.ts +69 -0
- package/dist/runtime/components/form/Dialog.vue +60 -84
- package/dist/runtime/components/form/Dialog.vue.d.ts +69 -0
- package/dist/runtime/components/form/EditPad.d.vue.ts +113 -0
- package/dist/runtime/components/form/EditPad.vue +49 -73
- package/dist/runtime/components/form/EditPad.vue.d.ts +113 -0
- package/dist/runtime/components/form/File.d.vue.ts +65 -0
- package/dist/runtime/components/form/File.vue +112 -174
- package/dist/runtime/components/form/File.vue.d.ts +65 -0
- package/dist/runtime/components/form/Hidden.d.vue.ts +12 -0
- package/dist/runtime/components/form/Hidden.vue +17 -22
- package/dist/runtime/components/form/Hidden.vue.d.ts +12 -0
- package/dist/runtime/components/form/Iterator.d.vue.ts +279 -0
- package/dist/runtime/components/form/Iterator.vue +162 -240
- package/dist/runtime/components/form/Iterator.vue.d.ts +279 -0
- package/dist/runtime/components/form/Login.d.vue.ts +32 -0
- package/dist/runtime/components/form/Login.vue +23 -43
- package/dist/runtime/components/form/Login.vue.d.ts +32 -0
- package/dist/runtime/components/form/Pad.d.vue.ts +674 -0
- package/dist/runtime/components/form/Pad.vue +166 -253
- package/dist/runtime/components/form/Pad.vue.d.ts +674 -0
- package/dist/runtime/components/form/SignPad.d.vue.ts +62 -0
- package/dist/runtime/components/form/SignPad.vue +80 -118
- package/dist/runtime/components/form/SignPad.vue.d.ts +62 -0
- package/dist/runtime/components/form/System.d.vue.ts +34 -0
- package/dist/runtime/components/form/System.vue +18 -24
- package/dist/runtime/components/form/System.vue.d.ts +34 -0
- package/dist/runtime/components/form/Table.d.vue.ts +221 -0
- package/dist/runtime/components/form/Table.vue +123 -170
- package/dist/runtime/components/form/Table.vue.d.ts +221 -0
- package/dist/runtime/components/form/TableData.d.vue.ts +102 -0
- package/dist/runtime/components/form/TableData.vue +109 -127
- package/dist/runtime/components/form/TableData.vue.d.ts +102 -0
- package/dist/runtime/components/form/Time.d.vue.ts +49 -0
- package/dist/runtime/components/form/Time.vue +64 -87
- package/dist/runtime/components/form/Time.vue.d.ts +49 -0
- package/dist/runtime/components/form/images/Capture.d.vue.ts +96 -0
- package/dist/runtime/components/form/images/Capture.vue +104 -139
- package/dist/runtime/components/form/images/Capture.vue.d.ts +96 -0
- package/dist/runtime/components/form/images/Edit.d.vue.ts +29 -0
- package/dist/runtime/components/form/images/Edit.vue +57 -69
- package/dist/runtime/components/form/images/Edit.vue.d.ts +29 -0
- package/dist/runtime/components/form/images/Field.d.vue.ts +27 -0
- package/dist/runtime/components/form/images/Field.vue +136 -194
- package/dist/runtime/components/form/images/Field.vue.d.ts +27 -0
- package/dist/runtime/components/form/images/Pad.d.vue.ts +13 -0
- package/dist/runtime/components/form/images/Pad.vue +23 -28
- package/dist/runtime/components/form/images/Pad.vue.d.ts +13 -0
- package/dist/runtime/components/label/Date.d.vue.ts +13 -0
- package/dist/runtime/components/label/Date.vue +13 -21
- package/dist/runtime/components/label/Date.vue.d.ts +13 -0
- package/dist/runtime/components/label/DateAgo.d.vue.ts +20 -0
- package/dist/runtime/components/label/DateAgo.vue +43 -67
- package/dist/runtime/components/label/DateAgo.vue.d.ts +20 -0
- package/dist/runtime/components/label/DateCount.d.vue.ts +22 -0
- package/dist/runtime/components/label/DateCount.vue +58 -97
- package/dist/runtime/components/label/DateCount.vue.d.ts +22 -0
- package/dist/runtime/components/label/Field.d.vue.ts +38 -0
- package/dist/runtime/components/label/Field.vue +18 -32
- package/dist/runtime/components/label/Field.vue.d.ts +38 -0
- package/dist/runtime/components/label/FormatMoney.d.vue.ts +12 -0
- package/dist/runtime/components/label/FormatMoney.vue +12 -20
- package/dist/runtime/components/label/FormatMoney.vue.d.ts +12 -0
- package/dist/runtime/components/label/Mask.d.vue.ts +10 -0
- package/dist/runtime/components/label/Mask.vue +21 -30
- package/dist/runtime/components/label/Mask.vue.d.ts +10 -0
- package/dist/runtime/components/label/Object.d.vue.ts +8 -0
- package/dist/runtime/components/label/Object.vue +10 -12
- package/dist/runtime/components/label/Object.vue.d.ts +8 -0
- package/dist/runtime/components/master/Autocomplete.d.vue.ts +70 -0
- package/dist/runtime/components/master/Autocomplete.vue +25 -26
- package/dist/runtime/components/master/Autocomplete.vue.d.ts +70 -0
- package/dist/runtime/components/master/Combobox.d.vue.ts +70 -0
- package/dist/runtime/components/master/Combobox.vue +26 -27
- package/dist/runtime/components/master/Combobox.vue.d.ts +70 -0
- package/dist/runtime/components/master/RadioGroup.d.vue.ts +51 -0
- package/dist/runtime/components/master/RadioGroup.vue +44 -47
- package/dist/runtime/components/master/RadioGroup.vue.d.ts +51 -0
- package/dist/runtime/components/master/Select.d.vue.ts +68 -0
- package/dist/runtime/components/master/Select.vue +25 -26
- package/dist/runtime/components/master/Select.vue.d.ts +68 -0
- package/dist/runtime/components/master/label.d.vue.ts +24 -0
- package/dist/runtime/components/master/label.vue +22 -34
- package/dist/runtime/components/master/label.vue.d.ts +24 -0
- package/dist/runtime/components/model/Autocomplete.d.vue.ts +82 -0
- package/dist/runtime/components/model/Autocomplete.vue +50 -37
- package/dist/runtime/components/model/Autocomplete.vue.d.ts +82 -0
- package/dist/runtime/components/model/Combobox.d.vue.ts +82 -0
- package/dist/runtime/components/model/Combobox.vue +51 -37
- package/dist/runtime/components/model/Combobox.vue.d.ts +82 -0
- package/dist/runtime/components/model/Pad.d.vue.ts +72 -0
- package/dist/runtime/components/model/Pad.vue +50 -53
- package/dist/runtime/components/model/Pad.vue.d.ts +72 -0
- package/dist/runtime/components/model/Select.d.vue.ts +72 -0
- package/dist/runtime/components/model/Select.vue +42 -32
- package/dist/runtime/components/model/Select.vue.d.ts +72 -0
- package/dist/runtime/components/model/Table.d.vue.ts +272 -0
- package/dist/runtime/components/model/Table.vue +121 -133
- package/dist/runtime/components/model/Table.vue.d.ts +272 -0
- package/dist/runtime/components/model/iterator.d.vue.ts +321 -0
- package/dist/runtime/components/model/iterator.vue +148 -175
- package/dist/runtime/components/model/iterator.vue.d.ts +321 -0
- package/dist/runtime/components/model/label.d.vue.ts +26 -0
- package/dist/runtime/components/model/label.vue +25 -35
- package/dist/runtime/components/model/label.vue.d.ts +26 -0
- package/dist/runtime/components/pdf/Print.d.vue.ts +17 -0
- package/dist/runtime/components/pdf/Print.vue +27 -38
- package/dist/runtime/components/pdf/Print.vue.d.ts +17 -0
- package/dist/runtime/components/pdf/View.d.vue.ts +52 -0
- package/dist/runtime/components/pdf/View.vue +58 -83
- package/dist/runtime/components/pdf/View.vue.d.ts +52 -0
- package/dist/runtime/composables/alert.d.ts +4 -0
- package/dist/runtime/composables/api.d.ts +4 -0
- package/dist/runtime/composables/api.js +4 -2
- package/dist/runtime/composables/assetFile.js +4 -2
- package/dist/runtime/composables/dialog.d.ts +1 -1
- package/dist/runtime/composables/document/template.js +3 -3
- package/dist/runtime/composables/document/templateFormHidden.d.ts +4 -0
- package/dist/runtime/composables/document/templateFormTable.js +1 -0
- package/dist/runtime/composables/graphql.d.ts +2 -2
- package/dist/runtime/composables/graphql.js +5 -5
- package/dist/runtime/composables/graphqlModel.d.ts +6 -6
- package/dist/runtime/composables/graphqlModelItem.d.ts +4 -4
- package/dist/runtime/composables/graphqlModelOperation.d.ts +6 -6
- package/dist/runtime/composables/graphqlModelOperation.js +2 -1
- package/dist/runtime/composables/graphqlOperation.js +5 -1
- package/dist/runtime/composables/hostAgentWs.d.ts +1 -1
- package/dist/runtime/composables/localStorageModel.d.ts +4 -0
- package/dist/runtime/composables/lookupList.d.ts +4 -0
- package/dist/runtime/composables/lookupListMaster.js +3 -3
- package/dist/runtime/composables/menu.d.ts +4 -0
- package/dist/runtime/composables/menu.js +2 -2
- package/dist/runtime/composables/useMrzReader.d.ts +48 -0
- package/dist/runtime/composables/useMrzReader.js +423 -0
- package/dist/runtime/composables/useTesseract.d.ts +16 -0
- package/dist/runtime/composables/useTesseract.js +45 -0
- package/dist/runtime/composables/userPermission.d.ts +1 -1
- package/dist/runtime/composables/utils/fuzzy.d.ts +2 -1
- package/dist/runtime/labs/Calendar.d.vue.ts +35 -0
- package/dist/runtime/labs/Calendar.vue +47 -75
- package/dist/runtime/labs/Calendar.vue.d.ts +35 -0
- package/dist/runtime/labs/form/EditMobile.d.vue.ts +12 -0
- package/dist/runtime/labs/form/EditMobile.vue +19 -36
- package/dist/runtime/labs/form/EditMobile.vue.d.ts +12 -0
- package/dist/runtime/labs/form/TextFieldMask.d.vue.ts +21 -0
- package/dist/runtime/labs/form/TextFieldMask.vue +19 -25
- package/dist/runtime/labs/form/TextFieldMask.vue.d.ts +21 -0
- package/dist/runtime/plugins/dialogManager.js +2 -2
- package/dist/runtime/plugins/permission.js +3 -3
- package/dist/runtime/types/bridge.d.ts +14 -0
- package/dist/runtime/utils/asset.d.ts +2 -0
- package/dist/runtime/utils/asset.js +49 -0
- package/dist/runtime/utils/datetime.js +1 -1
- package/dist/types.d.mts +2 -6
- package/package.json +79 -57
- package/scripts/ci-release.mjs +125 -0
- package/scripts/enrich-vue-docs-from-ai.mjs +197 -0
- package/scripts/generate-ai-summary.mjs +321 -0
- package/scripts/generate-composables-md.mjs +129 -0
- package/scripts/release-version.mjs +68 -0
- package/scripts/release.mjs +49 -0
- package/templates/public/tesseract/mrz.traineddata.gz +0 -0
- package/templates/public/tesseract/ocrb.traineddata.gz +0 -0
- package/dist/module.cjs +0 -5
- package/dist/module.d.ts +0 -8
- package/dist/types.d.ts +0 -7
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import { useTesseract } from "./useTesseract.js";
|
|
3
|
+
export function useMrzReader(options = {}) {
|
|
4
|
+
const scaleFactor = options.scaleFactor ?? 2;
|
|
5
|
+
const useOpenCv = options.useOpenCv ?? true;
|
|
6
|
+
const ocr = useTesseract({
|
|
7
|
+
lang: options.lang ?? "ocrb",
|
|
8
|
+
langPath: options.langPath ?? "/tesseract/"
|
|
9
|
+
});
|
|
10
|
+
const opencvReady = ref(false);
|
|
11
|
+
const opencvTried = ref(false);
|
|
12
|
+
let opencvInstance = null;
|
|
13
|
+
const MRZ_CHARS = /^[A-Z0-9<]+$/;
|
|
14
|
+
const WEIGHTS = [7, 3, 1];
|
|
15
|
+
async function ensureOpenCvReady() {
|
|
16
|
+
if (!useOpenCv || !import.meta.client) return false;
|
|
17
|
+
if (opencvReady.value && opencvInstance) return true;
|
|
18
|
+
if (opencvTried.value) return false;
|
|
19
|
+
opencvTried.value = true;
|
|
20
|
+
const resolveCv = async (mod) => {
|
|
21
|
+
let defaultExport = mod.default;
|
|
22
|
+
if (defaultExport && typeof defaultExport.then === "function") {
|
|
23
|
+
try {
|
|
24
|
+
defaultExport = await defaultExport;
|
|
25
|
+
} catch {
|
|
26
|
+
defaultExport = void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const first = defaultExport;
|
|
30
|
+
if (first && typeof first.Mat === "function")
|
|
31
|
+
return first;
|
|
32
|
+
const second = mod.cv;
|
|
33
|
+
if (second && typeof second.Mat === "function")
|
|
34
|
+
return second;
|
|
35
|
+
return void 0;
|
|
36
|
+
};
|
|
37
|
+
let importedCv;
|
|
38
|
+
try {
|
|
39
|
+
const mod = await import("@techstark/opencv-js");
|
|
40
|
+
importedCv = await resolveCv(mod);
|
|
41
|
+
} catch {
|
|
42
|
+
importedCv = void 0;
|
|
43
|
+
}
|
|
44
|
+
opencvInstance = importedCv;
|
|
45
|
+
opencvReady.value = !!opencvInstance;
|
|
46
|
+
return opencvReady.value;
|
|
47
|
+
}
|
|
48
|
+
function charValue(ch) {
|
|
49
|
+
if (ch === "<") return 0;
|
|
50
|
+
const code = ch.charCodeAt(0);
|
|
51
|
+
if (code >= 48 && code <= 57) return code - 48;
|
|
52
|
+
if (code >= 65 && code <= 90) return code - 55;
|
|
53
|
+
return -1;
|
|
54
|
+
}
|
|
55
|
+
function checksum(input) {
|
|
56
|
+
let sum = 0;
|
|
57
|
+
for (let i = 0; i < input.length; i++) {
|
|
58
|
+
const value = charValue(input[i]);
|
|
59
|
+
if (value < 0) return void 0;
|
|
60
|
+
sum += value * WEIGHTS[i % 3];
|
|
61
|
+
}
|
|
62
|
+
return String(sum % 10);
|
|
63
|
+
}
|
|
64
|
+
function normalizeMrzText(raw) {
|
|
65
|
+
return raw.toUpperCase().replace(/[^A-Z0-9<\r\n]/g, "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
66
|
+
}
|
|
67
|
+
function normalizeLine44(line) {
|
|
68
|
+
return line.replace(/[^A-Z0-9<]/g, "").padEnd(44, "<").slice(0, 44);
|
|
69
|
+
}
|
|
70
|
+
function asDigits(text) {
|
|
71
|
+
return text.replace(/[ODQ]/g, "0").replace(/[IL]/g, "1").replace(/Z/g, "2").replace(/S/g, "5").replace(/B/g, "8").replace(/G/g, "6");
|
|
72
|
+
}
|
|
73
|
+
function asLetters(text) {
|
|
74
|
+
return text.replace(/0/g, "O").replace(/1/g, "I").replace(/2/g, "Z").replace(/5/g, "S").replace(/8/g, "B");
|
|
75
|
+
}
|
|
76
|
+
function normalizeCountryCode(code) {
|
|
77
|
+
const clean = code.replace(/</g, "").trim();
|
|
78
|
+
if (!/^[A-Z]{3}$/.test(clean)) return void 0;
|
|
79
|
+
return clean;
|
|
80
|
+
}
|
|
81
|
+
function isValidDateYYMMDD(value) {
|
|
82
|
+
if (!/^\d{6}$/.test(value)) return false;
|
|
83
|
+
const mm = Number(value.slice(2, 4));
|
|
84
|
+
const dd = Number(value.slice(4, 6));
|
|
85
|
+
return mm >= 1 && mm <= 12 && dd >= 1 && dd <= 31;
|
|
86
|
+
}
|
|
87
|
+
function parseNameField(nameField) {
|
|
88
|
+
const clean = nameField.replace(/<+$/g, "");
|
|
89
|
+
const [rawSurname, rawGiven] = clean.split("<<");
|
|
90
|
+
return {
|
|
91
|
+
surname: rawSurname?.replace(/</g, " ").trim() || void 0,
|
|
92
|
+
givenNames: rawGiven?.replace(/</g, " ").trim() || void 0
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function validateTd3Passport(lines, raw) {
|
|
96
|
+
if (lines.length !== 2) return void 0;
|
|
97
|
+
const line1 = normalizeLine44(lines[0]);
|
|
98
|
+
const line2 = normalizeLine44(lines[1]);
|
|
99
|
+
if (!MRZ_CHARS.test(line1) || !MRZ_CHARS.test(line2)) return void 0;
|
|
100
|
+
const documentType = line1.slice(0, 2).replace(/</g, "").replace(/^F/, "P");
|
|
101
|
+
const issuingState = normalizeCountryCode(asLetters(line1.slice(2, 5)));
|
|
102
|
+
const { surname, givenNames } = parseNameField(line1.slice(5, 44));
|
|
103
|
+
const passportNumber = line2.slice(0, 9);
|
|
104
|
+
const passportCheck = asDigits(line2.slice(9, 10));
|
|
105
|
+
const nationality = normalizeCountryCode(asLetters(line2.slice(10, 13)));
|
|
106
|
+
const birthDate = asDigits(line2.slice(13, 19));
|
|
107
|
+
const birthCheck = asDigits(line2.slice(19, 20));
|
|
108
|
+
const sex = line2.slice(20, 21).replace(/</g, "X");
|
|
109
|
+
const expirationDate = asDigits(line2.slice(21, 27));
|
|
110
|
+
const expirationCheck = asDigits(line2.slice(27, 28));
|
|
111
|
+
const personalNumber = line2.slice(28, 42);
|
|
112
|
+
const personalCheck = asDigits(line2.slice(42, 43));
|
|
113
|
+
const compositeCheck = asDigits(line2.slice(43, 44));
|
|
114
|
+
if (!documentType.startsWith("P")) return void 0;
|
|
115
|
+
if (!/^[A-Z0-9<]{9}$/.test(passportNumber)) return void 0;
|
|
116
|
+
if (!/^[A-Z0-9<]{14}$/.test(personalNumber)) return void 0;
|
|
117
|
+
if (!/^\d$/.test(passportCheck) || !/^\d$/.test(birthCheck) || !/^\d$/.test(expirationCheck) || !/^\d$/.test(personalCheck) || !/^\d$/.test(compositeCheck)) return void 0;
|
|
118
|
+
if (!isValidDateYYMMDD(birthDate) || !isValidDateYYMMDD(expirationDate)) return void 0;
|
|
119
|
+
const numberCalc = checksum(passportNumber);
|
|
120
|
+
const birthCalc = checksum(birthDate);
|
|
121
|
+
const expirationCalc = checksum(expirationDate);
|
|
122
|
+
const personalCalc = checksum(personalNumber);
|
|
123
|
+
const compositeCalc = checksum(`${passportNumber}${passportCheck}${birthDate}${birthCheck}${expirationDate}${expirationCheck}${personalNumber}${personalCheck}`);
|
|
124
|
+
if (!numberCalc || !birthCalc || !expirationCalc || !personalCalc || !compositeCalc) return void 0;
|
|
125
|
+
if (numberCalc !== passportCheck) return void 0;
|
|
126
|
+
if (birthCalc !== birthCheck) return void 0;
|
|
127
|
+
if (expirationCalc !== expirationCheck) return void 0;
|
|
128
|
+
if (personalCalc !== personalCheck) return void 0;
|
|
129
|
+
if (compositeCalc !== compositeCheck) return void 0;
|
|
130
|
+
return {
|
|
131
|
+
raw,
|
|
132
|
+
lines: [line1, line2],
|
|
133
|
+
fields: {
|
|
134
|
+
documentType,
|
|
135
|
+
issuingState,
|
|
136
|
+
surname,
|
|
137
|
+
givenNames,
|
|
138
|
+
passportNumber: passportNumber.replace(/<+$/g, ""),
|
|
139
|
+
nationality,
|
|
140
|
+
birthDate,
|
|
141
|
+
sex,
|
|
142
|
+
expirationDate,
|
|
143
|
+
personalNumber: personalNumber.replace(/<+$/g, ""),
|
|
144
|
+
checkDigits: {
|
|
145
|
+
passportNumber: passportCheck,
|
|
146
|
+
birthDate: birthCheck,
|
|
147
|
+
expirationDate: expirationCheck,
|
|
148
|
+
personalNumber: personalCheck,
|
|
149
|
+
composite: compositeCheck
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function copyFrameToCanvas(source) {
|
|
155
|
+
const canvas = document.createElement("canvas");
|
|
156
|
+
const width = source.videoWidth || source.width;
|
|
157
|
+
const height = source.videoHeight || source.height;
|
|
158
|
+
canvas.width = width;
|
|
159
|
+
canvas.height = height;
|
|
160
|
+
canvas.getContext("2d")?.drawImage(source, 0, 0, width, height);
|
|
161
|
+
return canvas;
|
|
162
|
+
}
|
|
163
|
+
function scoreTwoLineTextBand(grayData, width, height) {
|
|
164
|
+
const totalPixels = width * height;
|
|
165
|
+
if (totalPixels < 2e3) return 0;
|
|
166
|
+
let sum = 0;
|
|
167
|
+
for (let i = 0; i < grayData.length; i += 4)
|
|
168
|
+
sum += grayData[i];
|
|
169
|
+
const mean = sum / totalPixels;
|
|
170
|
+
if (mean < 120) return 0;
|
|
171
|
+
const darkThreshold = Math.max(55, mean - 32);
|
|
172
|
+
const rowCounts = new Float32Array(height);
|
|
173
|
+
for (let y = 0; y < height; y++) {
|
|
174
|
+
let count = 0;
|
|
175
|
+
for (let x = 0; x < width; x++) {
|
|
176
|
+
const idx = (y * width + x) * 4;
|
|
177
|
+
if (grayData[idx] < darkThreshold)
|
|
178
|
+
count++;
|
|
179
|
+
}
|
|
180
|
+
rowCounts[y] = count;
|
|
181
|
+
}
|
|
182
|
+
const smooth = new Float32Array(height);
|
|
183
|
+
for (let y = 0; y < height; y++) {
|
|
184
|
+
const a = rowCounts[Math.max(0, y - 1)];
|
|
185
|
+
const b = rowCounts[y];
|
|
186
|
+
const c = rowCounts[Math.min(height - 1, y + 1)];
|
|
187
|
+
smooth[y] = (a + b + c) / 3;
|
|
188
|
+
}
|
|
189
|
+
let peak1 = 0;
|
|
190
|
+
let peak1Idx = -1;
|
|
191
|
+
for (let i = 0; i < height; i++) {
|
|
192
|
+
if (smooth[i] > peak1) {
|
|
193
|
+
peak1 = smooth[i];
|
|
194
|
+
peak1Idx = i;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
let peak2 = 0;
|
|
198
|
+
for (let i = 0; i < height; i++) {
|
|
199
|
+
if (Math.abs(i - peak1Idx) < Math.max(3, Math.floor(height * 0.14)))
|
|
200
|
+
continue;
|
|
201
|
+
if (smooth[i] > peak2)
|
|
202
|
+
peak2 = smooth[i];
|
|
203
|
+
}
|
|
204
|
+
const avg = smooth.reduce((acc, v) => acc + v, 0) / Math.max(1, smooth.length);
|
|
205
|
+
const prominence = peak1 + peak2 - avg * 2;
|
|
206
|
+
if (peak1 < width * 0.2 || peak2 < width * 0.2) return 0;
|
|
207
|
+
return prominence / Math.max(1, width);
|
|
208
|
+
}
|
|
209
|
+
function findMrzRegionCandidates(sourceCanvas) {
|
|
210
|
+
const srcW = sourceCanvas.width;
|
|
211
|
+
const srcH = sourceCanvas.height;
|
|
212
|
+
if (!srcW || !srcH) return [];
|
|
213
|
+
const probeW = Math.min(640, srcW);
|
|
214
|
+
const scale = probeW / srcW;
|
|
215
|
+
const probeH = Math.max(1, Math.floor(srcH * scale));
|
|
216
|
+
const probe = document.createElement("canvas");
|
|
217
|
+
probe.width = probeW;
|
|
218
|
+
probe.height = probeH;
|
|
219
|
+
const ctx = probe.getContext("2d");
|
|
220
|
+
if (!ctx) return [];
|
|
221
|
+
ctx.drawImage(sourceCanvas, 0, 0, srcW, srcH, 0, 0, probeW, probeH);
|
|
222
|
+
const widths = [0.58, 0.68, 0.78, 0.88, 0.94];
|
|
223
|
+
const heights = [0.14, 0.18, 0.22, 0.26];
|
|
224
|
+
const xCenters = [0.5, 0.42, 0.58, 0.34, 0.66];
|
|
225
|
+
const scored = [];
|
|
226
|
+
for (const wRatio of widths) {
|
|
227
|
+
for (const hRatio of heights) {
|
|
228
|
+
const w = Math.max(56, Math.floor(probeW * wRatio));
|
|
229
|
+
const h = Math.max(30, Math.floor(probeH * hRatio));
|
|
230
|
+
const yStart = Math.floor(probeH * 0.24);
|
|
231
|
+
const yEnd = Math.floor(probeH * 0.94);
|
|
232
|
+
const step = Math.max(10, Math.floor(h * 0.28));
|
|
233
|
+
for (const center of xCenters) {
|
|
234
|
+
const x = Math.max(0, Math.min(probeW - w, Math.floor(probeW * center - w / 2)));
|
|
235
|
+
for (let y = yStart; y + h < yEnd; y += step) {
|
|
236
|
+
const img = ctx.getImageData(x, y, w, h);
|
|
237
|
+
const score = scoreTwoLineTextBand(img.data, w, h);
|
|
238
|
+
if (score <= 0) continue;
|
|
239
|
+
scored.push({ x: Math.round(x / scale), y: Math.round(y / scale), w: Math.round(w / scale), h: Math.round(h / scale), score });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
scored.sort((a, b) => b.score - a.score);
|
|
245
|
+
return scored.slice(0, 4);
|
|
246
|
+
}
|
|
247
|
+
function findMrzCandidatesWithOpenCv(sourceCanvas) {
|
|
248
|
+
if (!opencvReady.value || !opencvInstance) return [];
|
|
249
|
+
const cv = opencvInstance;
|
|
250
|
+
let src;
|
|
251
|
+
let gray;
|
|
252
|
+
let blur;
|
|
253
|
+
let edges;
|
|
254
|
+
let kernel;
|
|
255
|
+
let closed;
|
|
256
|
+
let contours;
|
|
257
|
+
let hierarchy;
|
|
258
|
+
try {
|
|
259
|
+
src = cv.imread(sourceCanvas);
|
|
260
|
+
gray = new cv.Mat();
|
|
261
|
+
blur = new cv.Mat();
|
|
262
|
+
edges = new cv.Mat();
|
|
263
|
+
kernel = cv.getStructuringElement(cv.MORPH_RECT, new cv.Size(9, 3));
|
|
264
|
+
closed = new cv.Mat();
|
|
265
|
+
contours = new cv.MatVector();
|
|
266
|
+
hierarchy = new cv.Mat();
|
|
267
|
+
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
|
|
268
|
+
cv.GaussianBlur(gray, blur, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);
|
|
269
|
+
cv.Canny(blur, edges, 50, 140, 3, false);
|
|
270
|
+
cv.morphologyEx(edges, closed, cv.MORPH_CLOSE, kernel);
|
|
271
|
+
cv.findContours(closed, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
|
|
272
|
+
const output = [];
|
|
273
|
+
for (let i = 0; i < contours.size(); i++) {
|
|
274
|
+
const contour = contours.get(i);
|
|
275
|
+
const rect = cv.boundingRect(contour);
|
|
276
|
+
contour.delete?.();
|
|
277
|
+
const ratio = rect.width / Math.max(1, rect.height);
|
|
278
|
+
if (rect.width < sourceCanvas.width * 0.45 || rect.height < sourceCanvas.height * 0.1) continue;
|
|
279
|
+
if (ratio < 2.2 || ratio > 10) continue;
|
|
280
|
+
output.push({
|
|
281
|
+
x: rect.x,
|
|
282
|
+
y: rect.y,
|
|
283
|
+
w: rect.width,
|
|
284
|
+
h: rect.height,
|
|
285
|
+
score: rect.width * rect.height / (sourceCanvas.width * sourceCanvas.height)
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
output.sort((a, b) => b.score - a.score);
|
|
289
|
+
return output.slice(0, 4);
|
|
290
|
+
} catch {
|
|
291
|
+
return [];
|
|
292
|
+
} finally {
|
|
293
|
+
src?.delete?.();
|
|
294
|
+
gray?.delete?.();
|
|
295
|
+
blur?.delete?.();
|
|
296
|
+
edges?.delete?.();
|
|
297
|
+
kernel?.delete?.();
|
|
298
|
+
closed?.delete?.();
|
|
299
|
+
contours?.delete?.();
|
|
300
|
+
hierarchy?.delete?.();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function applyBinarize(canvas) {
|
|
304
|
+
const ctx = canvas.getContext("2d");
|
|
305
|
+
if (!ctx) return;
|
|
306
|
+
const img = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
307
|
+
const data = img.data;
|
|
308
|
+
let min = 255;
|
|
309
|
+
let max = 0;
|
|
310
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
311
|
+
const g = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
|
|
312
|
+
if (g < min) min = g;
|
|
313
|
+
if (g > max) max = g;
|
|
314
|
+
}
|
|
315
|
+
const range = Math.max(1, max - min);
|
|
316
|
+
const threshold = 0.58 * 255;
|
|
317
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
318
|
+
const g = (0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2] - min) * (255 / range);
|
|
319
|
+
const v = g > threshold ? 255 : 0;
|
|
320
|
+
data[i] = v;
|
|
321
|
+
data[i + 1] = v;
|
|
322
|
+
data[i + 2] = v;
|
|
323
|
+
data[i + 3] = 255;
|
|
324
|
+
}
|
|
325
|
+
ctx.putImageData(img, 0, 0);
|
|
326
|
+
}
|
|
327
|
+
function renderCandidate(outputCanvas, sourceCanvas, candidate, angleDeg = 0, zoom = 1, binarize = true) {
|
|
328
|
+
outputCanvas.width = Math.max(1, Math.floor(candidate.w * zoom));
|
|
329
|
+
outputCanvas.height = Math.max(1, Math.floor(candidate.h * zoom));
|
|
330
|
+
const ctx = outputCanvas.getContext("2d");
|
|
331
|
+
if (!ctx) return;
|
|
332
|
+
ctx.save();
|
|
333
|
+
ctx.translate(outputCanvas.width / 2, outputCanvas.height / 2);
|
|
334
|
+
ctx.rotate(angleDeg * Math.PI / 180);
|
|
335
|
+
ctx.drawImage(
|
|
336
|
+
sourceCanvas,
|
|
337
|
+
candidate.x,
|
|
338
|
+
candidate.y,
|
|
339
|
+
candidate.w,
|
|
340
|
+
candidate.h,
|
|
341
|
+
-outputCanvas.width / 2,
|
|
342
|
+
-outputCanvas.height / 2,
|
|
343
|
+
outputCanvas.width,
|
|
344
|
+
outputCanvas.height
|
|
345
|
+
);
|
|
346
|
+
ctx.restore();
|
|
347
|
+
if (binarize)
|
|
348
|
+
applyBinarize(outputCanvas);
|
|
349
|
+
}
|
|
350
|
+
function pickPassportCandidates(lines) {
|
|
351
|
+
const candidates = [];
|
|
352
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
353
|
+
if (lines[i].length < 30 || lines[i + 1].length < 30) continue;
|
|
354
|
+
candidates.push([normalizeLine44(lines[i]), normalizeLine44(lines[i + 1])]);
|
|
355
|
+
}
|
|
356
|
+
if (!candidates.length) {
|
|
357
|
+
const sorted = [...lines].sort((a, b) => b.length - a.length);
|
|
358
|
+
if (sorted.length >= 2)
|
|
359
|
+
candidates.push([normalizeLine44(sorted[0]), normalizeLine44(sorted[1])]);
|
|
360
|
+
}
|
|
361
|
+
return candidates;
|
|
362
|
+
}
|
|
363
|
+
async function decodeFromCanvas(sourceCanvas) {
|
|
364
|
+
await ocr.ensureReady();
|
|
365
|
+
if (useOpenCv)
|
|
366
|
+
await ensureOpenCvReady();
|
|
367
|
+
const candidates = opencvReady.value ? findMrzCandidatesWithOpenCv(sourceCanvas) : findMrzRegionCandidates(sourceCanvas);
|
|
368
|
+
const fallback = {
|
|
369
|
+
x: Math.floor(sourceCanvas.width * 0.05),
|
|
370
|
+
y: Math.floor(sourceCanvas.height * 0.64),
|
|
371
|
+
w: Math.floor(sourceCanvas.width * 0.9),
|
|
372
|
+
h: Math.floor(sourceCanvas.height * 0.24),
|
|
373
|
+
score: 0
|
|
374
|
+
};
|
|
375
|
+
const selected = (candidates.length ? candidates : [fallback]).slice(0, 3);
|
|
376
|
+
const probe = document.createElement("canvas");
|
|
377
|
+
for (const candidate of selected) {
|
|
378
|
+
for (const angle of [0, -6, 6]) {
|
|
379
|
+
for (const binarize of [true, false]) {
|
|
380
|
+
renderCandidate(probe, sourceCanvas, candidate, angle, scaleFactor, binarize);
|
|
381
|
+
const raw = await ocr.recognize(probe);
|
|
382
|
+
const lines = normalizeMrzText(raw);
|
|
383
|
+
const mrzCandidates = pickPassportCandidates(lines);
|
|
384
|
+
for (const mrz of mrzCandidates) {
|
|
385
|
+
const parsed = validateTd3Passport(mrz, raw);
|
|
386
|
+
if (parsed) return parsed;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return void 0;
|
|
392
|
+
}
|
|
393
|
+
async function decodeFromVideoElement(video) {
|
|
394
|
+
const canvas = copyFrameToCanvas(video);
|
|
395
|
+
return decodeFromCanvas(canvas);
|
|
396
|
+
}
|
|
397
|
+
async function decodeFromImageFile(file) {
|
|
398
|
+
const image = await new Promise((resolve, reject) => {
|
|
399
|
+
const reader = new FileReader();
|
|
400
|
+
reader.onload = () => {
|
|
401
|
+
const img = new Image();
|
|
402
|
+
img.onload = () => resolve(img);
|
|
403
|
+
img.onerror = () => reject(new Error("Failed to load image"));
|
|
404
|
+
img.src = reader.result;
|
|
405
|
+
};
|
|
406
|
+
reader.onerror = () => reject(new Error("Failed to read file"));
|
|
407
|
+
reader.readAsDataURL(file);
|
|
408
|
+
});
|
|
409
|
+
const canvas = document.createElement("canvas");
|
|
410
|
+
canvas.width = image.naturalWidth;
|
|
411
|
+
canvas.height = image.naturalHeight;
|
|
412
|
+
canvas.getContext("2d")?.drawImage(image, 0, 0);
|
|
413
|
+
return decodeFromCanvas(canvas);
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
ensureOpenCvReady,
|
|
417
|
+
opencvReady,
|
|
418
|
+
ocrProgress: ocr.progress,
|
|
419
|
+
ocrStatus: ocr.status,
|
|
420
|
+
decodeFromVideoElement,
|
|
421
|
+
decodeFromImageFile
|
|
422
|
+
};
|
|
423
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring client-side Tesseract OCR behavior.
|
|
3
|
+
*/
|
|
4
|
+
export interface UseTesseractOptions {
|
|
5
|
+
lang?: string;
|
|
6
|
+
langPath?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Provides lazy-loaded Tesseract OCR helpers with reactive status/progress state.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useTesseract(options?: UseTesseractOptions): {
|
|
12
|
+
progress: import("vue").Ref<number, number>;
|
|
13
|
+
status: import("vue").Ref<string, string>;
|
|
14
|
+
ensureReady: () => Promise<typeof import("tesseract.js")>;
|
|
15
|
+
recognize: (canvas: HTMLCanvasElement) => Promise<string>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
export function useTesseract(options = {}) {
|
|
3
|
+
const progress = ref(0);
|
|
4
|
+
const status = ref("idle");
|
|
5
|
+
const lang = options.lang ?? "ocrb";
|
|
6
|
+
const langPath = options.langPath ?? "/tesseract/";
|
|
7
|
+
let lib = null;
|
|
8
|
+
function resolvedLangPath() {
|
|
9
|
+
if (!import.meta.client)
|
|
10
|
+
return langPath;
|
|
11
|
+
return new URL(langPath, window.location.origin).toString();
|
|
12
|
+
}
|
|
13
|
+
async function ensureReady() {
|
|
14
|
+
if (!import.meta.client)
|
|
15
|
+
throw new Error("Tesseract OCR is client-only.");
|
|
16
|
+
if (!lib) {
|
|
17
|
+
lib = await import("tesseract.js");
|
|
18
|
+
}
|
|
19
|
+
return lib;
|
|
20
|
+
}
|
|
21
|
+
async function recognize(canvas) {
|
|
22
|
+
const tesseract = await ensureReady();
|
|
23
|
+
progress.value = 0;
|
|
24
|
+
status.value = "starting";
|
|
25
|
+
const result = await tesseract.recognize(canvas, lang, {
|
|
26
|
+
gzip: true,
|
|
27
|
+
cacheMethod: "refresh",
|
|
28
|
+
langPath: resolvedLangPath(),
|
|
29
|
+
logger: (m) => {
|
|
30
|
+
if (m?.status)
|
|
31
|
+
status.value = m.status;
|
|
32
|
+
if (m?.status === "recognizing text" && typeof m?.progress === "number")
|
|
33
|
+
progress.value = Math.round(m.progress * 100);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
status.value = "idle";
|
|
37
|
+
return result?.data?.text || "";
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
progress,
|
|
41
|
+
status,
|
|
42
|
+
ensureReady,
|
|
43
|
+
recognize
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useUserPermission: () =>
|
|
1
|
+
export declare const useUserPermission: () => unknown;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { MaybeRefOrGetter } from 'vue';
|
|
2
|
-
|
|
2
|
+
import type { UseFuseReturn } from '@vueuse/integrations/useFuse';
|
|
3
|
+
export declare function useFuzzy(searchTerm: MaybeRefOrGetter<string>, items: MaybeRefOrGetter<any[]>, fieldName: MaybeRefOrGetter<string[]>, options?: MaybeRefOrGetter<Record<string, any>>): UseFuseReturn<any>['results'];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type Event = {
|
|
2
|
+
id: string | undefined;
|
|
3
|
+
title: string;
|
|
4
|
+
start: string;
|
|
5
|
+
end: string;
|
|
6
|
+
color: string;
|
|
7
|
+
detail?: string;
|
|
8
|
+
props: Record<string, any> | any[];
|
|
9
|
+
};
|
|
10
|
+
interface CalendarProps {
|
|
11
|
+
modelValue: Event[];
|
|
12
|
+
locale?: 'th' | 'en';
|
|
13
|
+
toolBarLeft?: string;
|
|
14
|
+
toolBarCenter?: string;
|
|
15
|
+
toolBarRight?: string;
|
|
16
|
+
height?: string | number;
|
|
17
|
+
selectViewDay?: string;
|
|
18
|
+
mode: 'dayGridMonth' | 'timeGridDay';
|
|
19
|
+
}
|
|
20
|
+
declare const __VLS_export: import("vue").DefineComponent<CalendarProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
21
|
+
dialog: (...args: any[]) => void;
|
|
22
|
+
select: (...args: any[]) => void;
|
|
23
|
+
}, string, import("vue").PublicProps, Readonly<CalendarProps> & Readonly<{
|
|
24
|
+
onDialog?: ((...args: any[]) => any) | undefined;
|
|
25
|
+
onSelect?: ((...args: any[]) => any) | undefined;
|
|
26
|
+
}>, {
|
|
27
|
+
height: string | number;
|
|
28
|
+
mode: "dayGridMonth" | "timeGridDay";
|
|
29
|
+
locale: "th" | "en";
|
|
30
|
+
toolBarLeft: string;
|
|
31
|
+
toolBarCenter: string;
|
|
32
|
+
toolBarRight: string;
|
|
33
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
34
|
+
declare const _default: typeof __VLS_export;
|
|
35
|
+
export default _default;
|
|
@@ -1,84 +1,56 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import FullCalendar from
|
|
3
|
-
import dayGridPlugin from
|
|
4
|
-
import timeGridPlugin from
|
|
5
|
-
import listPlugin from
|
|
6
|
-
import interactionPlugin from
|
|
7
|
-
import { ref, computed
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface CalendarProps {
|
|
21
|
-
modelValue: Event[]
|
|
22
|
-
locale?: 'th' | 'en'
|
|
23
|
-
toolBarLeft?: string
|
|
24
|
-
toolBarCenter?: string
|
|
25
|
-
toolBarRight?: string
|
|
26
|
-
height?: string | number
|
|
27
|
-
selectViewDay?: string
|
|
28
|
-
mode: 'dayGridMonth' | 'timeGridDay'
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const props = withDefaults(defineProps<CalendarProps>(), {
|
|
32
|
-
locale: 'th',
|
|
33
|
-
height: 1200,
|
|
34
|
-
toolBarLeft: 'today prev,next',
|
|
35
|
-
toolBarCenter: 'title',
|
|
36
|
-
toolBarRight: 'timeGridDay,timeGridWeek,dayGridMonth',
|
|
37
|
-
mode: 'dayGridMonth',
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
const emit = defineEmits(['select', 'dialog'])
|
|
41
|
-
|
|
1
|
+
<script setup>
|
|
2
|
+
import FullCalendar from "@fullcalendar/vue3";
|
|
3
|
+
import dayGridPlugin from "@fullcalendar/daygrid";
|
|
4
|
+
import timeGridPlugin from "@fullcalendar/timegrid";
|
|
5
|
+
import listPlugin from "@fullcalendar/list";
|
|
6
|
+
import interactionPlugin from "@fullcalendar/interaction";
|
|
7
|
+
import { ref, computed } from "vue";
|
|
8
|
+
import {} from "@fullcalendar/core";
|
|
9
|
+
const props = defineProps({
|
|
10
|
+
modelValue: { type: Array, required: true },
|
|
11
|
+
locale: { type: String, required: false, default: "th" },
|
|
12
|
+
toolBarLeft: { type: String, required: false, default: "today prev,next" },
|
|
13
|
+
toolBarCenter: { type: String, required: false, default: "title" },
|
|
14
|
+
toolBarRight: { type: String, required: false, default: "timeGridDay,timeGridWeek,dayGridMonth" },
|
|
15
|
+
height: { type: [String, Number], required: false, default: 1200 },
|
|
16
|
+
selectViewDay: { type: String, required: false },
|
|
17
|
+
mode: { type: String, required: true, default: "dayGridMonth" }
|
|
18
|
+
});
|
|
19
|
+
const emit = defineEmits(["select", "dialog"]);
|
|
42
20
|
const buttonText = computed(() => {
|
|
43
21
|
return {
|
|
44
|
-
today: props.locale ===
|
|
45
|
-
month: props.locale ===
|
|
46
|
-
week: props.locale ===
|
|
47
|
-
day: props.locale ===
|
|
48
|
-
list: props.locale ===
|
|
49
|
-
year: props.locale ===
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
list.innerHTML = document.getElementById(arg.event.id.toString())?.innerHTML || ''
|
|
68
|
-
return { domNodes: [list] }
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// @ts-expect-error
|
|
72
|
-
const calendarOptions = ref<CalendarOptions>({
|
|
22
|
+
today: props.locale === "th" ? "\u0E27\u0E31\u0E19\u0E19\u0E35\u0E49" : "today",
|
|
23
|
+
month: props.locale === "th" ? "\u0E40\u0E14\u0E37\u0E2D\u0E19" : "month",
|
|
24
|
+
week: props.locale === "th" ? "\u0E2A\u0E31\u0E1B\u0E14\u0E32\u0E2B\u0E4C" : "week",
|
|
25
|
+
day: props.locale === "th" ? "\u0E27\u0E31\u0E19" : "day",
|
|
26
|
+
list: props.locale === "th" ? "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23" : "list",
|
|
27
|
+
year: props.locale === "th" ? "\u0E1B\u0E35" : "year"
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
const calendarRef = ref();
|
|
31
|
+
const dateViewDay = ref({ date: "", props: {} });
|
|
32
|
+
const handleDateClick = (info) => {
|
|
33
|
+
emit("select", info.event);
|
|
34
|
+
};
|
|
35
|
+
const handleEventClick = (info) => {
|
|
36
|
+
emit("dialog", true);
|
|
37
|
+
emit("select", info.event);
|
|
38
|
+
};
|
|
39
|
+
const eventContentDay = (arg) => {
|
|
40
|
+
const list = document.createElement("div");
|
|
41
|
+
list.innerHTML = document.getElementById(arg.event.id.toString())?.innerHTML || "";
|
|
42
|
+
return { domNodes: [list] };
|
|
43
|
+
};
|
|
44
|
+
const calendarOptions = ref({
|
|
73
45
|
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
|
|
74
46
|
initialView: props.mode,
|
|
75
47
|
locale: props.locale,
|
|
76
48
|
dayMaxEvents: true,
|
|
77
|
-
timeZone:
|
|
49
|
+
timeZone: "UTC",
|
|
78
50
|
headerToolbar: {
|
|
79
51
|
left: props.toolBarLeft,
|
|
80
52
|
center: props.toolBarCenter,
|
|
81
|
-
right: props.toolBarRight
|
|
53
|
+
right: props.toolBarRight
|
|
82
54
|
},
|
|
83
55
|
buttonText: buttonText.value,
|
|
84
56
|
events: props.modelValue,
|
|
@@ -87,13 +59,13 @@ const calendarOptions = ref<CalendarOptions>({
|
|
|
87
59
|
eventClick: handleEventClick,
|
|
88
60
|
nowIndicator: true,
|
|
89
61
|
height: props.height,
|
|
90
|
-
eventColor:
|
|
91
|
-
})
|
|
62
|
+
eventColor: "#378006"
|
|
63
|
+
});
|
|
92
64
|
</script>
|
|
93
65
|
|
|
94
66
|
<template>
|
|
95
67
|
<FullCalendar
|
|
96
68
|
ref="calendarRef"
|
|
97
|
-
:options="calendarOptions
|
|
69
|
+
:options="calendarOptions"
|
|
98
70
|
/>
|
|
99
71
|
</template>
|