diff --git a/components.d.ts b/components.d.ts index a17b220..28f4ecd 100644 --- a/components.d.ts +++ b/components.d.ts @@ -58,7 +58,6 @@ declare module 'vue' { IonTabs: typeof import('@ionic/vue')['IonTabs'] IonText: typeof import('@ionic/vue')['IonText'] IonTitle: typeof import('@ionic/vue')['IonTitle'] - IonToggle: typeof import('@ionic/vue')['IonToggle'] IonToolbar: typeof import('@ionic/vue')['IonToolbar'] LayoutDefault: typeof import('./src/components/layout/default.vue')['default'] PwaInstallButton: typeof import('./src/components/pwa-install-button/index.vue')['default'] @@ -118,7 +117,6 @@ declare global { const IonTabs: typeof import('@ionic/vue')['IonTabs'] const IonText: typeof import('@ionic/vue')['IonText'] const IonTitle: typeof import('@ionic/vue')['IonTitle'] - const IonToggle: typeof import('@ionic/vue')['IonToggle'] const IonToolbar: typeof import('@ionic/vue')['IonToolbar'] const LayoutDefault: typeof import('./src/components/layout/default.vue')['default'] const PwaInstallButton: typeof import('./src/components/pwa-install-button/index.vue')['default'] diff --git a/eslint.config.mjs b/eslint.config.mjs index 595f232..3e7f453 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -32,5 +32,6 @@ export default antfu({ "vue/no-deprecated-slot-attribute": "off", "@typescript-eslint/no-explicit-any": "off", "prefer-promise-reject-errors": "off", + "no-async-promise-executor": "off", }, }); diff --git a/package.json b/package.json index f702c4a..bdd6b70 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@elysiajs/eden": "^1.4.5", "@ionic/vue": "^8.7.11", "@ionic/vue-router": "^8.7.11", - "@riwa/api-types": "http://192.168.1.7:9527/api/riwa-eden-0.0.121.tgz", + "@riwa/api-types": "http://192.168.1.7:9527/api/riwa-eden-0.0.123.tgz", "@tailwindcss/vite": "^4.1.18", "@vee-validate/zod": "^4.15.1", "@vueuse/core": "^14.1.0", @@ -44,10 +44,12 @@ "dayjs": "^1.11.19", "ethers": "^6.16.0", "ionicons": "^8.0.13", + "jsqr": "^1.4.0", "lightweight-charts": "^5.1.0", "lodash-es": "^4.17.21", "markdown-it": "^14.1.0", "pinia": "^3.0.4", + "qr-scanner-wechat": "^0.1.3", "qrcode": "^1.5.4", "tailwindcss": "^4.1.18", "vconsole": "^3.15.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a395231..f079608 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,8 +57,8 @@ importers: specifier: ^8.7.11 version: 8.7.11(@stencil/core@4.39.0)(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) '@riwa/api-types': - specifier: http://192.168.1.7:9527/api/riwa-eden-0.0.121.tgz - version: '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.121.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))' + specifier: http://192.168.1.7:9527/api/riwa-eden-0.0.123.tgz + version: '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.123.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))' '@tailwindcss/vite': specifier: ^4.1.18 version: 4.1.18(vite@7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) @@ -86,6 +86,9 @@ importers: ionicons: specifier: ^8.0.13 version: 8.0.13 + jsqr: + specifier: ^1.4.0 + version: 1.4.0 lightweight-charts: specifier: ^5.1.0 version: 5.1.0 @@ -98,6 +101,9 @@ importers: pinia: specifier: ^3.0.4 version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + qr-scanner-wechat: + specifier: ^0.1.3 + version: 0.1.3 qrcode: specifier: ^1.5.4 version: 1.5.4 @@ -2826,9 +2832,9 @@ packages: '@remirror/core-constants@3.0.0': resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} - '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.121.tgz': - resolution: {tarball: http://192.168.1.7:9527/api/riwa-eden-0.0.121.tgz} - version: 0.0.121 + '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.123.tgz': + resolution: {tarball: http://192.168.1.7:9527/api/riwa-eden-0.0.123.tgz} + version: 0.0.123 peerDependencies: '@elysiajs/eden': ^1.4.5 @@ -6333,6 +6339,9 @@ packages: resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} engines: {'0': node >=0.6.0} + jsqr@1.4.0: + resolution: {integrity: sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -7653,6 +7662,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qr-scanner-wechat@0.1.3: + resolution: {integrity: sha512-d2dfaXjcgNDxaSweEljvJl6cOIMbXeyW8YijZDbRFUvVpJ672zt5i64lQSBgjvKVZZSSHE2KiRf2SAuiQa286A==} + qrcode@1.5.4: resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} engines: {node: '>=10.13.0'} @@ -12187,7 +12199,7 @@ snapshots: '@remirror/core-constants@3.0.0': {} - '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.121.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))': + '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.123.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))': dependencies: '@elysiajs/eden': 1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)) @@ -15932,6 +15944,8 @@ snapshots: json-schema: 0.4.0 verror: 1.10.0 + jsqr@1.4.0: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -17694,6 +17708,8 @@ snapshots: punycode@2.3.1: {} + qr-scanner-wechat@0.1.3: {} + qrcode@1.5.4: dependencies: dijkstrajs: 1.0.3 diff --git a/src/components/qr-scanner/index.vue b/src/components/qr-scanner/index.vue index 8f81598..c9ba475 100644 --- a/src/components/qr-scanner/index.vue +++ b/src/components/qr-scanner/index.vue @@ -1,33 +1,233 @@ - + diff --git a/src/composables/useQRScanner.ts b/src/composables/useQRScanner.ts index 506001a..8388d48 100644 --- a/src/composables/useQRScanner.ts +++ b/src/composables/useQRScanner.ts @@ -1,11 +1,10 @@ import { CapacitorBarcodeScanner, CapacitorBarcodeScannerCameraDirection, CapacitorBarcodeScannerScanOrientation, CapacitorBarcodeScannerTypeHint } from "@capacitor/barcode-scanner"; -import { toastController } from "@ionic/vue"; +import { modalController, toastController } from "@ionic/vue"; +import QRCode from "@/components/qr-scanner/index.vue"; export interface QRScanResult { text: string; format: string; - rawValue: string; - displayValue: string; } export interface ScannerOptions { @@ -15,36 +14,71 @@ export interface ScannerOptions { export function useQRScanner() { const { t } = useI18n(); const { vibrate } = useHaptics(); + const platform = usePlatform(); async function open(options?: ScannerOptions) { - try { - vibrate(); + return new Promise(async (resolve, reject) => { + try { + vibrate(); + if (platform === "browser") { + const modal = await modalController.create({ + component: QRCode, + componentProps: { + onClose: () => modal.dismiss(), + onError: (error) => { + toastController.create({ + message: String(error), + duration: 2000, + position: "bottom", + color: "danger", + }).then(toast => toast.present()); + }, + onSuccess: (result: string) => { + toastController.create({ + message: String(result), + duration: 2000, + position: "bottom", + color: "success", + }).then(toast => toast.present()); + modal.dismiss(result); + }, + }, + animated: false, + }); + await modal.present(); + modal.onDidDismiss().then((res) => { + if (res.data) + resolve(res.data); - const result = await CapacitorBarcodeScanner.scanBarcode({ - hint: CapacitorBarcodeScannerTypeHint.QR_CODE, - scanInstructions: options?.title || t("scanner.hint"), - cameraDirection: CapacitorBarcodeScannerCameraDirection.BACK, - scanOrientation: CapacitorBarcodeScannerScanOrientation.PORTRAIT, - }); + reject(); + }); + } + else { + const result = await CapacitorBarcodeScanner.scanBarcode({ + hint: CapacitorBarcodeScannerTypeHint.QR_CODE, + scanInstructions: options?.title || t("scanner.hint"), + cameraDirection: CapacitorBarcodeScannerCameraDirection.BACK, + scanOrientation: CapacitorBarcodeScannerScanOrientation.PORTRAIT, + }); - vibrate(); - return { - text: result.ScanResult, - format: result.format, - }; - } - catch (error: any) { - console.log("error.message", error.message); - if (error.code !== "OS-PLUG-BARC-0006") { - const toast = await toastController.create({ - message: t("scanner.openError"), - duration: 2000, - position: "bottom", - color: "danger", - }); - await toast.present(); + vibrate(); + resolve(result.ScanResult); + } } - } + catch (error: any) { + console.log("error.message", error.message); + if (error.code !== "OS-PLUG-BARC-0006") { + const toast = await toastController.create({ + message: t("scanner.openError"), + duration: 2000, + position: "bottom", + color: "danger", + }); + await toast.present(); + reject(); + } + } + }); } function close() { }