diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..9a3bf8a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,41 @@ +name: Bug Report +description: 报告bug +labels: [bug] +body: + - type: markdown + attributes: + value: | + 感谢反馈问题,请填写下方的表单完成本次问题的反馈 + - type: input + id: log-lottery-version + attributes: + label: log-lottery版本 + description: | + 你所使用的 log-lottery 的准确版本。 + placeholder: eg. v0.5.0 + validations: + required: true + - type: input + id: browser + attributes: + label: 浏览器及其版本 + description: | + 你是在哪个浏览器中发现的这个问题?最好可以提供浏览器的版本号。 + placeholder: eg. Google Chrome 111.0.5563.110 + validations: + required: false + - type: textarea + id: what-happened + attributes: + label: 具体问题 + description: | + 出现了什么问题? + validations: + required: false + - type: textarea + id: logs + attributes: + label: 报错信息 + description: | + 如果有的话,请粘贴你遇到的报错信息或日志。下面输入框中的内容在 issue 提交后会被自动格式化成代码块。 + render: shell diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000..5184d2d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,24 @@ +name: Feature Request +description: 建议添加新功能 +labels: [enhancement] +body: + - type: markdown + attributes: + value: | + 感谢你抽时间提出优化建议,请填写下方的表单完成本次问题的反馈 + - type: input + id: log-lottery-version + attributes: + label: log-lottery版本 + description: | + 你所使用的 log-lottery 的准确版本。 + placeholder: eg. v0.5.0 + validations: + required: false + - type: textarea + id: feature-description + attributes: + label: 你的想法是什么? + placeholder: 请尽可能详细地告诉我你期望实现一个什么样的功能或者哪里需要进行优化 + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/general.yml b/.github/ISSUE_TEMPLATE/general.yml new file mode 100644 index 0000000..aed95ad --- /dev/null +++ b/.github/ISSUE_TEMPLATE/general.yml @@ -0,0 +1,19 @@ +name: General Issue +description: 新开空白issue模板 +body: + - type: input + id: log-lottery-version + attributes: + label: log-lottery版本 + description: | + 你所使用的 log-lottery 的准确版本。 + placeholder: eg. v0.5.0 + validations: + required: false + - type: textarea + id: description + attributes: + label: 问题描述 + placeholder: 请尽可能详细地告诉我你所遇到的问题 + validations: + required: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 969dd5e..0e38abf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,6 +113,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Download web build artifact uses: actions/download-artifact@v4 @@ -127,4 +129,4 @@ jobs: name: 'Release ${{ github.ref_name }}' draft: true prerelease: false - generate_release_notes: true + generate_release_notes: true \ No newline at end of file diff --git a/README.md b/README.md index a5746ce..affec36 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ log-lottery是一个可配置可定制化的抽奖应用,炫酷3D球体,可 > 如果进入网站遇到图片无法显示或有报错的情况,请先到【全局配置】-【界面配置】菜单中点击【重置所有数据】按钮清除数据后进行更新。 +> 不支持内定功能 + ## 要求 使用PC端最新版Chrome或Edge浏览器。 diff --git a/package.json b/package.json index 700bd84..a16a945 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,11 @@ "prepare": "husky" }, "dependencies": { + "@fingerprintjs/fingerprintjs": "^5.0.1", + "@headlessui/vue": "^1.7.23", "@tweenjs/tween.js": "23.1.2", "@vueuse/core": "^14.1.0", + "@vueuse/integrations": "^14.1.0", "axios": "^1.13.2", "canvas-confetti": "^1.9.4", "class-variance-authority": "^0.7.1", @@ -36,6 +39,7 @@ "masonry-layout": "^4.2.2", "pinia": "^3.0.4", "pinia-plugin-persist": "^1.0.0", + "qrcode": "^1.5.4", "reka-ui": "^2.7.0", "sparticles": "^1.3.1", "tailwind-merge": "^3.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d99527..be01ef4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,21 @@ importers: .: dependencies: + '@fingerprintjs/fingerprintjs': + specifier: ^5.0.1 + version: 5.0.1 + '@headlessui/vue': + specifier: ^1.7.23 + version: 1.7.23(vue@3.5.26(typescript@5.9.3)) '@tweenjs/tween.js': specifier: 23.1.2 version: 23.1.2 '@vueuse/core': specifier: ^14.1.0 version: 14.1.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/integrations': + specifier: ^14.1.0 + version: 14.1.0(axios@1.13.2)(change-case@5.4.4)(qrcode@1.5.4)(vue@3.5.26(typescript@5.9.3)) axios: specifier: ^1.13.2 version: 1.13.2 @@ -59,6 +68,9 @@ importers: pinia-plugin-persist: specifier: ^1.0.0 version: 1.0.0(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3)) + qrcode: + specifier: ^1.5.4 + version: 1.5.4 reka-ui: specifier: ^2.7.0 version: 2.7.0(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) @@ -1133,6 +1145,9 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@fingerprintjs/fingerprintjs@5.0.1': + resolution: {integrity: sha512-KbaeE/rk2WL8MfpRP6jTI4lSr42SJPjvkyrjP3QU6uUDkOMWWYC2Ts1sNSYcegHC8avzOoYTHBj+2fTqvZWQBA==} + '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -1145,6 +1160,12 @@ packages: '@floating-ui/vue@1.1.9': resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} + '@headlessui/vue@1.7.23': + resolution: {integrity: sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==} + engines: {node: '>=10'} + peerDependencies: + vue: ^3.2.0 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -1955,6 +1976,48 @@ packages: peerDependencies: vue: ^3.5.0 + '@vueuse/integrations@14.1.0': + resolution: {integrity: sha512-eNQPdisnO9SvdydTIXnTE7c29yOsJBD/xkwEyQLdhDC/LKbqrFpXHb3uS//7NcIrQO3fWVuvMGp8dbK6mNEMCA==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 || ^8 + vue: ^3.5.0 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + '@vueuse/metadata@12.8.2': resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} @@ -2203,6 +2266,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + caniuse-lite@1.0.30001761: resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} @@ -2256,6 +2323,9 @@ packages: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2417,6 +2487,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -2503,6 +2577,9 @@ packages: resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -2916,6 +2993,10 @@ packages: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -3610,6 +3691,10 @@ packages: localforage@1.10.0: resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -3975,14 +4060,26 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -4083,6 +4180,10 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + pnpm-workspace-yaml@1.4.3: resolution: {integrity: sha512-Q8B3SWuuISy/Ciag4DFP7MCrJX07wfaekcqD2o/msdIj4x8Ql3bZ/NEKOXV7mTVh7m1YdiFWiMi9xH+0zuEGHw==} @@ -4161,6 +4262,11 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -4248,6 +4354,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + reserved-identifiers@1.2.0: resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} engines: {node: '>=18'} @@ -4371,6 +4480,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -5140,6 +5252,9 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which-typed-array@1.1.19: resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} engines: {node: '>= 0.4'} @@ -5166,6 +5281,10 @@ packages: resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} engines: {node: '>=0.8'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -5206,6 +5325,9 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5222,10 +5344,18 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -6210,6 +6340,8 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@fingerprintjs/fingerprintjs@5.0.1': {} + '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -6230,6 +6362,11 @@ snapshots: - '@vue/composition-api' - vue + '@headlessui/vue@1.7.23(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@tanstack/vue-virtual': 3.13.13(vue@3.5.26(typescript@5.9.3)) + vue: 3.5.26(typescript@5.9.3) + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -7070,6 +7207,16 @@ snapshots: '@vueuse/shared': 14.1.0(vue@3.5.26(typescript@5.9.3)) vue: 3.5.26(typescript@5.9.3) + '@vueuse/integrations@14.1.0(axios@1.13.2)(change-case@5.4.4)(qrcode@1.5.4)(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@vueuse/core': 14.1.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/shared': 14.1.0(vue@3.5.26(typescript@5.9.3)) + vue: 3.5.26(typescript@5.9.3) + optionalDependencies: + axios: 1.13.2 + change-case: 5.4.4 + qrcode: 1.5.4 + '@vueuse/metadata@12.8.2': {} '@vueuse/metadata@14.1.0': {} @@ -7321,6 +7468,8 @@ snapshots: callsites@3.1.0: {} + camelcase@5.3.1: {} + caniuse-lite@1.0.30001761: {} canvas-confetti@1.9.4: {} @@ -7374,6 +7523,12 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -7518,6 +7673,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decimal.js@10.6.0: {} decode-named-character-reference@1.2.0: @@ -7606,6 +7763,8 @@ snapshots: diff-sequences@27.5.1: {} + dijkstrajs@1.0.3: {} + dom-accessibility-api@0.5.16: {} dom-serializer@0.2.2: @@ -8188,6 +8347,11 @@ snapshots: find-up-simple@1.0.1: {} + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -8837,6 +9001,10 @@ snapshots: dependencies: lie: 3.1.1 + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -9400,14 +9568,24 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} package-manager-detector@1.6.0: {} @@ -9489,6 +9667,8 @@ snapshots: pluralize@8.0.0: {} + pngjs@5.0.0: {} + pnpm-workspace-yaml@1.4.3: dependencies: yaml: 2.8.2 @@ -9567,6 +9747,12 @@ snapshots: punycode@2.3.1: {} + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + quansync@0.2.11: {} query-string@4.3.4: @@ -9670,6 +9856,8 @@ snapshots: require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + reserved-identifiers@1.2.0: {} resolve-from@4.0.0: {} @@ -9790,6 +9978,8 @@ snapshots: semver@7.7.3: {} + set-blocking@2.0.0: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -10627,6 +10817,8 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 + which-module@2.0.1: {} + which-typed-array@1.1.19: dependencies: available-typed-arrays: 1.0.7 @@ -10652,6 +10844,12 @@ snapshots: word@0.3.0: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -10686,6 +10884,8 @@ snapshots: xmlchars@2.2.0: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -10697,8 +10897,27 @@ snapshots: yaml@2.8.2: {} + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@17.7.2: dependencies: cliui: 8.0.1 diff --git a/public/sw.js b/public/sw.js new file mode 100644 index 0000000..f27843a --- /dev/null +++ b/public/sw.js @@ -0,0 +1,153 @@ +/* eslint-disable no-restricted-globals */ +// Service Worker 最小示例 + +// 安装事件 +self.addEventListener('install', (event) => { + console.log('Service Worker: Installed', event) + // 跳过等待,立即激活 + self.skipWaiting() +}) + +// 激活事件 +self.addEventListener('activate', (event) => { + console.log('Service Worker: Activated') + // 立即控制所有页面 + event.waitUntil(self.clients.claim()) +}) + +self.currentClient = null +// 监听页面消息 +self.addEventListener('message', async (event) => { + // 处理来自页面的消息 + self.currentClient = event.source + if (event.data && event.data.type) { + console.log('处理来自页面的消息:', event.data) + switch (event.data.type) { + case 'CONNECT_WS': + console.log('连接的URL:', event.data.payload.url, self.webSocketConnection) + if (!self.webSocketConnection || self.webSocketConnection.readyState !== WebSocket.OPEN) { + self.webSocketConnection = new WebSocket(event.data.payload.url) + } + console.log('新连接:', self.webSocketConnection) + self.webSocketConnection.onopen = () => { + console.log('连接成功了,可以发消息') + if (self.currentClient) { + self.currentClient.postMessage({ + type: 'WS_OPEN', + success: true, + payload: { + message: '连接成功', + data: null + } + }) + } + } + // 接收到消息推送给客户端 + self.webSocketConnection.onmessage = (message) => { + const formatMsg = JSON.parse(message.data) + + console.log('服务器的消息', formatMsg) + if (self.currentClient) { + self.currentClient.postMessage({ + type: 'WS_MESSAGE', + success: true, + payload: formatMsg, + }) + } + // else { + // event.source.postMessage({ + // type: 'WS_MESSAGE', + // success: true, + // payload: { + // data: message.data, + // }, + // }) + // } + + } + // 连接错误 + self.webSocketConnection.onerror = (error) => { + console.error('WebSocket error:', error) + if (self.currentClient) { + self.currentClient.postMessage({ + type: 'WS_ERROR', + success: true, + payload: { + message: '连接错误', + data: error, + } + }) + } + } + // 连接关闭 + self.webSocketConnection.onclose = () => { + console.log('WebSocket connection closed') + if (self.currentClient) { + self.currentClient.postMessage({ + type: 'WS_CLOSE', + success: true, + payload: { + message: '已断开连接', + data: null + } + }) + } + } + break + case 'SEND_WS_MESSAGE': + const user_msg = event.data.payload.message + console.log('发送信号改哦西:', user_msg, self.webSocketConnection) + self.webSocketConnection.send(user_msg) + break + case 'DISCONNECT_WS': + console.log('Disconnecting from WebSocket') + self.webSocketConnection.close() + event.source.postMessage({ + type: 'WS_CLOSE', + success: true, + payload: { + message: '已断开连接', + data: null + } + }) + break + case 'PING': + console.log('Ping from page') + self.webSocketConnection.send('PING') + event.source.postMessage({ + type: 'PONG', + success: true, + payload: { + message: 'Service Worker is alive', + }, + }) + break + case 'GET_WS_STATUS': + // 返回WebSocket连接状态(如果有的话) + event.source.postMessage({ + type: 'WS_STATUS', + success: true, + payload: { + status: self.webSocketConnection ? self.webSocketConnection.readyState : null, + connected: self.webSocketConnection && self.webSocketConnection.readyState === WebSocket.OPEN, + } + }) + break + default: + console.log('Unknown message type:', event.data.type) + break + } + } +}) + +// 监听通知点击事件 +self.addEventListener('notificationclick', (event) => { + console.log('Notification clicked:', event.notification.title) + + event.notification.close() + + // 打开或聚焦到页面 + event.waitUntil( + clients.openWindow(event.notification.data.url || '/'), + ) +}) diff --git a/src/api/msg/index.ts b/src/api/msg/index.ts new file mode 100644 index 0000000..bf7eeaf --- /dev/null +++ b/src/api/msg/index.ts @@ -0,0 +1,12 @@ +import request from '../request' + +export function api_sendMsg(userSignature: string, data: any) { + return request<{ status: string }>({ + url: '/user-msg', + method: 'POST', + headers: { + userSignature, + }, + data, + }) +} diff --git a/src/api/request.ts b/src/api/request.ts index 1f0e1c5..38bd5bc 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -1,5 +1,6 @@ import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios' import axios from 'axios' +import openModal from '@/components/ErrorModal' class Request { private instance: AxiosInstance @@ -15,14 +16,10 @@ class Request { this.instance.interceptors.request.use( (config: InternalAxiosRequestConfig) => { // 在发送请求之前做些什么 - console.log('请求拦截器被触发') - return config }, (error: any) => { // 对请求错误做些什么 - console.error('请求拦截器发生错误:', error) - return Promise.reject(error) }, ) @@ -31,15 +28,16 @@ class Request { this.instance.interceptors.response.use( (response: AxiosResponse) => { // 对响应数据做些什么 - console.log('响应拦截器被触发') - const responseData = response.data - - return responseData + return response }, (error: any) => { // 对响应错误做些什么 - console.error('响应拦截器发生错误:', error) - + if (error.response && error.response.data) { + const { code, msg } = error.response.data + openModal({ title: code, desc: msg }) + return Promise.reject(error.response.data) + } + openModal({ title: '请求错误', desc: error.message }) return Promise.reject(error) }, ) diff --git a/src/components/Dialog/index.vue b/src/components/Dialog/index.vue index 419d507..1830f14 100644 --- a/src/components/Dialog/index.vue +++ b/src/components/Dialog/index.vue @@ -9,11 +9,15 @@ interface Props { submitText?: string submitFunc?: () => void cancelFunc?: () => void + footer?: null | 'center' | 'left' | 'right' + dialogClass?: string // 添加动态class属性 } const props = withDefaults(defineProps(), { cancelText: i18n.global.t('button.cancel'), submitText: i18n.global.t('button.confirm'), cancelFunc: () => {}, + footer: 'right', + dialogClass: '', }) const visible = defineModel('visible', { type: Boolean, @@ -43,7 +47,7 @@ const { title, desc, cancelText, submitText, submitFunc, cancelFunc = defaultCan