first commit
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
3
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
||||
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>mahjong-web</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "mahjong-web",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.5.25",
|
||||
"vue-router": "4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.10.1",
|
||||
"@vitejs/plugin-vue": "^6.0.2",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vue-tsc": "^3.1.5"
|
||||
}
|
||||
}
|
||||
970
pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,970 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
vue:
|
||||
specifier: ^3.5.25
|
||||
version: 3.5.28(typescript@5.9.3)
|
||||
vue-router:
|
||||
specifier: '4'
|
||||
version: 4.6.4(vue@3.5.28(typescript@5.9.3))
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^24.10.1
|
||||
version: 24.10.13
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^6.0.2
|
||||
version: 6.0.4(vite@7.3.1(@types/node@24.10.13))(vue@3.5.28(typescript@5.9.3))
|
||||
'@vue/tsconfig':
|
||||
specifier: ^0.8.1
|
||||
version: 0.8.1(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3))
|
||||
typescript:
|
||||
specifier: ~5.9.3
|
||||
version: 5.9.3
|
||||
vite:
|
||||
specifier: ^7.3.1
|
||||
version: 7.3.1(@types/node@24.10.13)
|
||||
vue-tsc:
|
||||
specifier: ^3.1.5
|
||||
version: 3.2.4(typescript@5.9.3)
|
||||
|
||||
packages:
|
||||
|
||||
'@babel/helper-string-parser@7.27.1':
|
||||
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5':
|
||||
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/parser@7.29.0':
|
||||
resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/types@7.29.0':
|
||||
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.3':
|
||||
resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.3':
|
||||
resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.3':
|
||||
resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.3':
|
||||
resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.3':
|
||||
resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.3':
|
||||
resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.3':
|
||||
resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.3':
|
||||
resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.3':
|
||||
resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.3':
|
||||
resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.3':
|
||||
resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.3':
|
||||
resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.3':
|
||||
resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.3':
|
||||
resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.3':
|
||||
resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.3':
|
||||
resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.3':
|
||||
resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.3':
|
||||
resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.3':
|
||||
resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-rc.2':
|
||||
resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==}
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.57.1':
|
||||
resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.57.1':
|
||||
resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.57.1':
|
||||
resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.57.1':
|
||||
resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.57.1':
|
||||
resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.57.1':
|
||||
resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.57.1':
|
||||
resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.57.1':
|
||||
resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.57.1':
|
||||
resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.57.1':
|
||||
resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.57.1':
|
||||
resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.57.1':
|
||||
resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.57.1':
|
||||
resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.57.1':
|
||||
resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.57.1':
|
||||
resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.57.1':
|
||||
resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.57.1':
|
||||
resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.57.1':
|
||||
resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.57.1':
|
||||
resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.57.1':
|
||||
resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.57.1':
|
||||
resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.57.1':
|
||||
resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.57.1':
|
||||
resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.57.1':
|
||||
resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.57.1':
|
||||
resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
'@types/node@24.10.13':
|
||||
resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==}
|
||||
|
||||
'@vitejs/plugin-vue@6.0.4':
|
||||
resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
|
||||
vue: ^3.2.25
|
||||
|
||||
'@volar/language-core@2.4.27':
|
||||
resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==}
|
||||
|
||||
'@volar/source-map@2.4.27':
|
||||
resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==}
|
||||
|
||||
'@volar/typescript@2.4.27':
|
||||
resolution: {integrity: sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==}
|
||||
|
||||
'@vue/compiler-core@3.5.28':
|
||||
resolution: {integrity: sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==}
|
||||
|
||||
'@vue/compiler-dom@3.5.28':
|
||||
resolution: {integrity: sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.28':
|
||||
resolution: {integrity: sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.28':
|
||||
resolution: {integrity: sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==}
|
||||
|
||||
'@vue/devtools-api@6.6.4':
|
||||
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
|
||||
|
||||
'@vue/language-core@3.2.4':
|
||||
resolution: {integrity: sha512-bqBGuSG4KZM45KKTXzGtoCl9cWju5jsaBKaJJe3h5hRAAWpZUuj5G+L+eI01sPIkm4H6setKRlw7E85wLdDNew==}
|
||||
|
||||
'@vue/reactivity@3.5.28':
|
||||
resolution: {integrity: sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==}
|
||||
|
||||
'@vue/runtime-core@3.5.28':
|
||||
resolution: {integrity: sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==}
|
||||
|
||||
'@vue/runtime-dom@3.5.28':
|
||||
resolution: {integrity: sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==}
|
||||
|
||||
'@vue/server-renderer@3.5.28':
|
||||
resolution: {integrity: sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==}
|
||||
peerDependencies:
|
||||
vue: 3.5.28
|
||||
|
||||
'@vue/shared@3.5.28':
|
||||
resolution: {integrity: sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==}
|
||||
|
||||
'@vue/tsconfig@0.8.1':
|
||||
resolution: {integrity: sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==}
|
||||
peerDependencies:
|
||||
typescript: 5.x
|
||||
vue: ^3.4.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
|
||||
alien-signals@3.1.2:
|
||||
resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==}
|
||||
|
||||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
entities@7.0.1:
|
||||
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
esbuild@0.27.3:
|
||||
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
estree-walker@2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
|
||||
fdir@6.5.0:
|
||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
picomatch: ^3 || ^4
|
||||
peerDependenciesMeta:
|
||||
picomatch:
|
||||
optional: true
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
muggle-string@0.4.1:
|
||||
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
path-browserify@1.0.1:
|
||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
picomatch@4.0.3:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
rollup@4.57.1:
|
||||
resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
tinyglobby@0.2.15:
|
||||
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
typescript@5.9.3:
|
||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
|
||||
vite@7.3.1:
|
||||
resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^20.19.0 || >=22.12.0
|
||||
jiti: '>=1.21.0'
|
||||
less: ^4.0.0
|
||||
lightningcss: ^1.21.0
|
||||
sass: ^1.70.0
|
||||
sass-embedded: ^1.70.0
|
||||
stylus: '>=0.54.8'
|
||||
sugarss: ^5.0.0
|
||||
terser: ^5.16.0
|
||||
tsx: ^4.8.1
|
||||
yaml: ^2.4.2
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
jiti:
|
||||
optional: true
|
||||
less:
|
||||
optional: true
|
||||
lightningcss:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
sass-embedded:
|
||||
optional: true
|
||||
stylus:
|
||||
optional: true
|
||||
sugarss:
|
||||
optional: true
|
||||
terser:
|
||||
optional: true
|
||||
tsx:
|
||||
optional: true
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
vscode-uri@3.1.0:
|
||||
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
|
||||
|
||||
vue-router@4.6.4:
|
||||
resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
vue-tsc@3.2.4:
|
||||
resolution: {integrity: sha512-xj3YCvSLNDKt1iF9OcImWHhmYcihVu9p4b9s4PGR/qp6yhW+tZJaypGxHScRyOrdnHvaOeF+YkZOdKwbgGvp5g==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: '>=5.0.0'
|
||||
|
||||
vue@3.5.28:
|
||||
resolution: {integrity: sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@babel/helper-string-parser@7.27.1': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5': {}
|
||||
|
||||
'@babel/parser@7.29.0':
|
||||
dependencies:
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@babel/types@7.29.0':
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.3':
|
||||
optional: true
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-rc.2': {}
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.57.1':
|
||||
optional: true
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/node@24.10.13':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
'@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.10.13))(vue@3.5.28(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-rc.2
|
||||
vite: 7.3.1(@types/node@24.10.13)
|
||||
vue: 3.5.28(typescript@5.9.3)
|
||||
|
||||
'@volar/language-core@2.4.27':
|
||||
dependencies:
|
||||
'@volar/source-map': 2.4.27
|
||||
|
||||
'@volar/source-map@2.4.27': {}
|
||||
|
||||
'@volar/typescript@2.4.27':
|
||||
dependencies:
|
||||
'@volar/language-core': 2.4.27
|
||||
path-browserify: 1.0.1
|
||||
vscode-uri: 3.1.0
|
||||
|
||||
'@vue/compiler-core@3.5.28':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
'@vue/shared': 3.5.28
|
||||
entities: 7.0.1
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-dom@3.5.28':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.28
|
||||
'@vue/shared': 3.5.28
|
||||
|
||||
'@vue/compiler-sfc@3.5.28':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
'@vue/compiler-core': 3.5.28
|
||||
'@vue/compiler-dom': 3.5.28
|
||||
'@vue/compiler-ssr': 3.5.28
|
||||
'@vue/shared': 3.5.28
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.21
|
||||
postcss: 8.5.6
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-ssr@3.5.28':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.28
|
||||
'@vue/shared': 3.5.28
|
||||
|
||||
'@vue/devtools-api@6.6.4': {}
|
||||
|
||||
'@vue/language-core@3.2.4':
|
||||
dependencies:
|
||||
'@volar/language-core': 2.4.27
|
||||
'@vue/compiler-dom': 3.5.28
|
||||
'@vue/shared': 3.5.28
|
||||
alien-signals: 3.1.2
|
||||
muggle-string: 0.4.1
|
||||
path-browserify: 1.0.1
|
||||
picomatch: 4.0.3
|
||||
|
||||
'@vue/reactivity@3.5.28':
|
||||
dependencies:
|
||||
'@vue/shared': 3.5.28
|
||||
|
||||
'@vue/runtime-core@3.5.28':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.28
|
||||
'@vue/shared': 3.5.28
|
||||
|
||||
'@vue/runtime-dom@3.5.28':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.28
|
||||
'@vue/runtime-core': 3.5.28
|
||||
'@vue/shared': 3.5.28
|
||||
csstype: 3.2.3
|
||||
|
||||
'@vue/server-renderer@3.5.28(vue@3.5.28(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.5.28
|
||||
'@vue/shared': 3.5.28
|
||||
vue: 3.5.28(typescript@5.9.3)
|
||||
|
||||
'@vue/shared@3.5.28': {}
|
||||
|
||||
'@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3))':
|
||||
optionalDependencies:
|
||||
typescript: 5.9.3
|
||||
vue: 3.5.28(typescript@5.9.3)
|
||||
|
||||
alien-signals@3.1.2: {}
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
entities@7.0.1: {}
|
||||
|
||||
esbuild@0.27.3:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.3
|
||||
'@esbuild/android-arm': 0.27.3
|
||||
'@esbuild/android-arm64': 0.27.3
|
||||
'@esbuild/android-x64': 0.27.3
|
||||
'@esbuild/darwin-arm64': 0.27.3
|
||||
'@esbuild/darwin-x64': 0.27.3
|
||||
'@esbuild/freebsd-arm64': 0.27.3
|
||||
'@esbuild/freebsd-x64': 0.27.3
|
||||
'@esbuild/linux-arm': 0.27.3
|
||||
'@esbuild/linux-arm64': 0.27.3
|
||||
'@esbuild/linux-ia32': 0.27.3
|
||||
'@esbuild/linux-loong64': 0.27.3
|
||||
'@esbuild/linux-mips64el': 0.27.3
|
||||
'@esbuild/linux-ppc64': 0.27.3
|
||||
'@esbuild/linux-riscv64': 0.27.3
|
||||
'@esbuild/linux-s390x': 0.27.3
|
||||
'@esbuild/linux-x64': 0.27.3
|
||||
'@esbuild/netbsd-arm64': 0.27.3
|
||||
'@esbuild/netbsd-x64': 0.27.3
|
||||
'@esbuild/openbsd-arm64': 0.27.3
|
||||
'@esbuild/openbsd-x64': 0.27.3
|
||||
'@esbuild/openharmony-arm64': 0.27.3
|
||||
'@esbuild/sunos-x64': 0.27.3
|
||||
'@esbuild/win32-arm64': 0.27.3
|
||||
'@esbuild/win32-ia32': 0.27.3
|
||||
'@esbuild/win32-x64': 0.27.3
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.3):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.3
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
magic-string@0.30.21:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
muggle-string@0.4.1: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
path-browserify@1.0.1: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
postcss@8.5.6:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
rollup@4.57.1:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.57.1
|
||||
'@rollup/rollup-android-arm64': 4.57.1
|
||||
'@rollup/rollup-darwin-arm64': 4.57.1
|
||||
'@rollup/rollup-darwin-x64': 4.57.1
|
||||
'@rollup/rollup-freebsd-arm64': 4.57.1
|
||||
'@rollup/rollup-freebsd-x64': 4.57.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.57.1
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.57.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.57.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.57.1
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.57.1
|
||||
'@rollup/rollup-linux-loong64-musl': 4.57.1
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.57.1
|
||||
'@rollup/rollup-linux-ppc64-musl': 4.57.1
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.57.1
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.57.1
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.57.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.57.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.57.1
|
||||
'@rollup/rollup-openbsd-x64': 4.57.1
|
||||
'@rollup/rollup-openharmony-arm64': 4.57.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.57.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.57.1
|
||||
'@rollup/rollup-win32-x64-gnu': 4.57.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.57.1
|
||||
fsevents: 2.3.3
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
tinyglobby@0.2.15:
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
|
||||
typescript@5.9.3: {}
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
|
||||
vite@7.3.1(@types/node@24.10.13):
|
||||
dependencies:
|
||||
esbuild: 0.27.3
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
postcss: 8.5.6
|
||||
rollup: 4.57.1
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 24.10.13
|
||||
fsevents: 2.3.3
|
||||
|
||||
vscode-uri@3.1.0: {}
|
||||
|
||||
vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.28(typescript@5.9.3)
|
||||
|
||||
vue-tsc@3.2.4(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@volar/typescript': 2.4.27
|
||||
'@vue/language-core': 3.2.4
|
||||
typescript: 5.9.3
|
||||
|
||||
vue@3.5.28(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.28
|
||||
'@vue/compiler-sfc': 3.5.28
|
||||
'@vue/runtime-dom': 3.5.28
|
||||
'@vue/server-renderer': 3.5.28(vue@3.5.28(typescript@5.9.3))
|
||||
'@vue/shared': 3.5.28
|
||||
optionalDependencies:
|
||||
typescript: 5.9.3
|
||||
1
public/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
3
src/App.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<RouterView />
|
||||
</template>
|
||||
185
src/api/auth.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
export interface AuthUser {
|
||||
id?: string | number
|
||||
username?: string
|
||||
nickname?: string
|
||||
}
|
||||
|
||||
export interface AuthSessionInput {
|
||||
token: string
|
||||
tokenType?: string
|
||||
refreshToken?: string
|
||||
}
|
||||
|
||||
export interface AuthResult {
|
||||
token: string
|
||||
tokenType?: string
|
||||
refreshToken?: string
|
||||
expiresIn?: number
|
||||
user?: AuthUser
|
||||
}
|
||||
|
||||
interface ApiErrorPayload {
|
||||
message?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
const API_BASE_URL = (import.meta.env.VITE_API_BASE_URL ?? '').trim().replace(/\/$/, '')
|
||||
const LOGIN_PATH = import.meta.env.VITE_LOGIN_PATH ?? '/api/v1/auth/login'
|
||||
const REGISTER_PATH = import.meta.env.VITE_REGISTER_PATH ?? '/api/v1/auth/register'
|
||||
const REFRESH_PATH = import.meta.env.VITE_REFRESH_PATH ?? '/api/v1/auth/refresh'
|
||||
const LOGIN_BEARER_TOKEN = (import.meta.env.VITE_LOGIN_BEARER_TOKEN ?? '').trim()
|
||||
|
||||
function buildUrl(path: string): string {
|
||||
if (/^https?:\/\//.test(path)) {
|
||||
return path
|
||||
}
|
||||
|
||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`
|
||||
if (!API_BASE_URL) {
|
||||
return normalizedPath
|
||||
}
|
||||
|
||||
// Avoid duplicated API prefix, e.g. base: /api/v1 + path: /api/v1/auth/login
|
||||
try {
|
||||
const baseUrl = new URL(API_BASE_URL)
|
||||
const basePath = baseUrl.pathname.replace(/\/$/, '')
|
||||
if (basePath && normalizedPath.startsWith(`${basePath}/`)) {
|
||||
return `${API_BASE_URL}${normalizedPath.slice(basePath.length)}`
|
||||
}
|
||||
} catch {
|
||||
// API_BASE_URL may be a relative path; fallback to direct join.
|
||||
}
|
||||
|
||||
return `${API_BASE_URL}${normalizedPath}`
|
||||
}
|
||||
|
||||
async function request<T>(
|
||||
url: string,
|
||||
body: Record<string, unknown>,
|
||||
extraHeaders?: Record<string, string>,
|
||||
): Promise<T> {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...extraHeaders,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
|
||||
const payload = (await response.json().catch(() => ({}))) as T & ApiErrorPayload
|
||||
if (!response.ok) {
|
||||
throw new Error(payload.message ?? payload.error ?? '请求失败,请稍后再试')
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
function createAuthHeader(token: string, tokenType = 'Bearer'): string {
|
||||
const normalizedToken = token.trim()
|
||||
if (/^\S+\s+\S+/.test(normalizedToken)) {
|
||||
return normalizedToken
|
||||
}
|
||||
|
||||
return `${tokenType || 'Bearer'} ${normalizedToken}`
|
||||
}
|
||||
|
||||
function extractToken(payload: Record<string, unknown>): string {
|
||||
const candidate =
|
||||
payload.token ??
|
||||
payload.accessToken ??
|
||||
payload.access_token ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.token ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.accessToken ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.access_token
|
||||
|
||||
if (typeof candidate !== 'string' || candidate.length === 0) {
|
||||
throw new Error('登录成功,但后端未返回 token 字段')
|
||||
}
|
||||
|
||||
return candidate
|
||||
}
|
||||
|
||||
function extractTokenType(payload: Record<string, unknown>): string | undefined {
|
||||
const candidate =
|
||||
payload.token_type ??
|
||||
payload.tokenType ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.token_type ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.tokenType
|
||||
|
||||
return typeof candidate === 'string' && candidate.length > 0 ? candidate : undefined
|
||||
}
|
||||
|
||||
function extractRefreshToken(payload: Record<string, unknown>): string | undefined {
|
||||
const candidate =
|
||||
payload.refresh_token ??
|
||||
payload.refreshToken ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.refresh_token ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.refreshToken
|
||||
|
||||
return typeof candidate === 'string' && candidate.length > 0 ? candidate : undefined
|
||||
}
|
||||
|
||||
function extractExpiresIn(payload: Record<string, unknown>): number | undefined {
|
||||
const candidate =
|
||||
payload.expires_in ??
|
||||
payload.expiresIn ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.expires_in ??
|
||||
(payload.data as Record<string, unknown> | undefined)?.expiresIn
|
||||
|
||||
return typeof candidate === 'number' && Number.isFinite(candidate) ? candidate : undefined
|
||||
}
|
||||
|
||||
function extractUser(payload: Record<string, unknown>): AuthUser | undefined {
|
||||
const user = payload.user ?? (payload.data as Record<string, unknown> | undefined)?.user
|
||||
return typeof user === 'object' && user !== null ? (user as AuthUser) : undefined
|
||||
}
|
||||
|
||||
function parseAuthResult(payload: Record<string, unknown>): AuthResult {
|
||||
return {
|
||||
token: extractToken(payload),
|
||||
tokenType: extractTokenType(payload),
|
||||
refreshToken: extractRefreshToken(payload),
|
||||
expiresIn: extractExpiresIn(payload),
|
||||
user: extractUser(payload),
|
||||
}
|
||||
}
|
||||
|
||||
export async function register(input: {
|
||||
username: string
|
||||
phone: string
|
||||
email: string
|
||||
password: string
|
||||
}): Promise<void> {
|
||||
await request<Record<string, unknown>>(buildUrl(REGISTER_PATH), input)
|
||||
}
|
||||
|
||||
export async function login(input: { loginId: string; password: string }): Promise<AuthResult> {
|
||||
const payload = await request<Record<string, unknown>>(
|
||||
buildUrl(LOGIN_PATH),
|
||||
{
|
||||
login_id: input.loginId,
|
||||
password: input.password,
|
||||
},
|
||||
LOGIN_BEARER_TOKEN ? { Authorization: `Bearer ${LOGIN_BEARER_TOKEN}` } : undefined,
|
||||
)
|
||||
return parseAuthResult(payload)
|
||||
}
|
||||
|
||||
export async function refreshAccessToken(input: AuthSessionInput): Promise<AuthResult> {
|
||||
if (!input.refreshToken) {
|
||||
throw new Error('缺少 refresh_token,无法刷新登录状态')
|
||||
}
|
||||
|
||||
const payload = await request<Record<string, unknown>>(
|
||||
buildUrl(REFRESH_PATH),
|
||||
{
|
||||
refreshToken: input.refreshToken,
|
||||
},
|
||||
{
|
||||
Authorization: createAuthHeader(input.token, input.tokenType),
|
||||
},
|
||||
)
|
||||
|
||||
return parseAuthResult(payload)
|
||||
}
|
||||
146
src/api/authed-request.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { refreshAccessToken } from './auth'
|
||||
|
||||
export interface AuthSession {
|
||||
token: string
|
||||
tokenType?: string
|
||||
refreshToken?: string
|
||||
expiresIn?: number
|
||||
}
|
||||
|
||||
export interface AuthedRequestOptions {
|
||||
method: 'GET' | 'POST'
|
||||
path: string
|
||||
auth: AuthSession
|
||||
body?: Record<string, unknown>
|
||||
onAuthUpdated?: (next: AuthSession) => void
|
||||
}
|
||||
|
||||
export interface ApiEnvelope<T> {
|
||||
code: number
|
||||
msg: string
|
||||
data: T
|
||||
}
|
||||
|
||||
interface ApiErrorPayload {
|
||||
code?: number
|
||||
msg?: string
|
||||
message?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export class AuthExpiredError extends Error {
|
||||
constructor(message = '登录状态已过期,请重新登录') {
|
||||
super(message)
|
||||
this.name = 'AuthExpiredError'
|
||||
}
|
||||
}
|
||||
|
||||
const API_BASE_URL = (import.meta.env.VITE_API_BASE_URL ?? '').trim().replace(/\/$/, '')
|
||||
|
||||
function buildUrl(path: string): string {
|
||||
if (/^https?:\/\//.test(path)) {
|
||||
return path
|
||||
}
|
||||
|
||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`
|
||||
if (!API_BASE_URL) {
|
||||
return normalizedPath
|
||||
}
|
||||
|
||||
try {
|
||||
const baseUrl = new URL(API_BASE_URL)
|
||||
const basePath = baseUrl.pathname.replace(/\/$/, '')
|
||||
if (basePath && normalizedPath.startsWith(`${basePath}/`)) {
|
||||
return `${API_BASE_URL}${normalizedPath.slice(basePath.length)}`
|
||||
}
|
||||
} catch {
|
||||
// API_BASE_URL may be a relative path.
|
||||
}
|
||||
|
||||
return `${API_BASE_URL}${normalizedPath}`
|
||||
}
|
||||
|
||||
function createAuthHeader(token: string, tokenType = 'Bearer'): string {
|
||||
const normalizedToken = token.trim()
|
||||
if (/^\S+\s+\S+/.test(normalizedToken)) {
|
||||
return normalizedToken
|
||||
}
|
||||
|
||||
return `${tokenType || 'Bearer'} ${normalizedToken}`
|
||||
}
|
||||
|
||||
async function parseEnvelope<T>(response: Response): Promise<ApiEnvelope<T>> {
|
||||
const payload = (await response.json().catch(() => ({}))) as ApiEnvelope<T> & ApiErrorPayload
|
||||
if (!response.ok) {
|
||||
throw new Error(payload.msg ?? payload.message ?? payload.error ?? '请求失败,请稍后再试')
|
||||
}
|
||||
|
||||
if (typeof payload.code === 'number' && payload.code !== 0) {
|
||||
throw new Error(payload.msg ?? '接口返回失败')
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
async function runRequest<T>(
|
||||
options: Omit<AuthedRequestOptions, 'auth'> & { session: AuthSession },
|
||||
): Promise<{ response: Response; parsed: ApiEnvelope<T> }> {
|
||||
const response = await fetch(buildUrl(options.path), {
|
||||
method: options.method,
|
||||
headers: {
|
||||
...(options.body ? { 'Content-Type': 'application/json' } : undefined),
|
||||
Authorization: createAuthHeader(options.session.token, options.session.tokenType),
|
||||
},
|
||||
body: options.body ? JSON.stringify(options.body) : undefined,
|
||||
})
|
||||
|
||||
if (response.status === 401) {
|
||||
return {
|
||||
response,
|
||||
parsed: { code: 401, msg: 'unauthorized', data: {} as T },
|
||||
}
|
||||
}
|
||||
|
||||
const parsed = await parseEnvelope<T>(response)
|
||||
return { response, parsed }
|
||||
}
|
||||
|
||||
export async function authedRequest<T>(options: AuthedRequestOptions): Promise<T> {
|
||||
const first = await runRequest<T>({ ...options, session: options.auth })
|
||||
if (first.response.status !== 401) {
|
||||
return first.parsed.data
|
||||
}
|
||||
|
||||
if (!options.auth.refreshToken) {
|
||||
throw new AuthExpiredError()
|
||||
}
|
||||
|
||||
try {
|
||||
const refreshed = await refreshAccessToken({
|
||||
token: options.auth.token,
|
||||
tokenType: options.auth.tokenType,
|
||||
refreshToken: options.auth.refreshToken,
|
||||
})
|
||||
|
||||
const nextAuth: AuthSession = {
|
||||
token: refreshed.token,
|
||||
tokenType: refreshed.tokenType ?? options.auth.tokenType,
|
||||
refreshToken: refreshed.refreshToken ?? options.auth.refreshToken,
|
||||
expiresIn: refreshed.expiresIn,
|
||||
}
|
||||
options.onAuthUpdated?.(nextAuth)
|
||||
|
||||
const second = await runRequest<T>({ ...options, session: nextAuth })
|
||||
if (second.response.status === 401) {
|
||||
throw new AuthExpiredError()
|
||||
}
|
||||
|
||||
return second.parsed.data
|
||||
} catch (error) {
|
||||
if (error instanceof AuthExpiredError) {
|
||||
throw error
|
||||
}
|
||||
|
||||
throw new AuthExpiredError()
|
||||
}
|
||||
}
|
||||
71
src/api/mahjong.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { authedRequest, type AuthSession } from './authed-request'
|
||||
|
||||
export interface RoomItem {
|
||||
room_id: string
|
||||
name: string
|
||||
game_type: string
|
||||
owner_id: string
|
||||
max_players: number
|
||||
player_count: number
|
||||
status: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface RoomListResult {
|
||||
items: RoomItem[]
|
||||
page: number
|
||||
size: number
|
||||
total: number
|
||||
}
|
||||
|
||||
const ROOM_CREATE_PATH =
|
||||
import.meta.env.VITE_ROOM_CREATE_PATH ?? '/api/v1/game/mahjong/room/create'
|
||||
const ROOM_LIST_PATH = import.meta.env.VITE_ROOM_LIST_PATH ?? '/api/v1/game/mahjong/room/list'
|
||||
const ROOM_JOIN_PATH = import.meta.env.VITE_ROOM_JOIN_PATH ?? '/api/v1/game/mahjong/room/join'
|
||||
|
||||
export async function createRoom(
|
||||
auth: AuthSession,
|
||||
input: { name: string; gameType: string; maxPlayers: number },
|
||||
onAuthUpdated?: (next: AuthSession) => void,
|
||||
): Promise<RoomItem> {
|
||||
return authedRequest<RoomItem>({
|
||||
method: 'POST',
|
||||
path: ROOM_CREATE_PATH,
|
||||
auth,
|
||||
onAuthUpdated,
|
||||
body: {
|
||||
name: input.name,
|
||||
game_type: input.gameType,
|
||||
max_players: input.maxPlayers,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function listRooms(
|
||||
auth: AuthSession,
|
||||
onAuthUpdated?: (next: AuthSession) => void,
|
||||
): Promise<RoomListResult> {
|
||||
return authedRequest<RoomListResult>({
|
||||
method: 'GET',
|
||||
path: ROOM_LIST_PATH,
|
||||
auth,
|
||||
onAuthUpdated,
|
||||
})
|
||||
}
|
||||
|
||||
export async function joinRoom(
|
||||
auth: AuthSession,
|
||||
input: { roomId: string },
|
||||
onAuthUpdated?: (next: AuthSession) => void,
|
||||
): Promise<void> {
|
||||
await authedRequest<Record<string, never> | RoomItem>({
|
||||
method: 'POST',
|
||||
path: ROOM_JOIN_PATH,
|
||||
auth,
|
||||
onAuthUpdated,
|
||||
body: {
|
||||
room_id: input.roomId,
|
||||
},
|
||||
})
|
||||
}
|
||||
24
src/api/user.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { authedRequest, type AuthSession } from './authed-request'
|
||||
|
||||
export interface UserInfo {
|
||||
userID?: string
|
||||
username?: string
|
||||
phone?: string
|
||||
email?: string
|
||||
nickname?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const USER_INFO_PATH = import.meta.env.VITE_USER_INFO_PATH ?? '/api/v1/user/info'
|
||||
|
||||
export async function getUserInfo(
|
||||
auth: AuthSession,
|
||||
onAuthUpdated?: (next: AuthSession) => void,
|
||||
): Promise<UserInfo> {
|
||||
return authedRequest<UserInfo>({
|
||||
method: 'GET',
|
||||
path: USER_INFO_PATH,
|
||||
auth,
|
||||
onAuthUpdated,
|
||||
})
|
||||
}
|
||||
BIN
src/assets/images/desk/desk_01.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
src/assets/images/flowerClolor/tiao.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/images/flowerClolor/tong.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/assets/images/flowerClolor/wan.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_1.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_2.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_3.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_4.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_5.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_6.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_7.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_8.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b1_9.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_1.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_2.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_3.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_4.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_5.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_6.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_7.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_8.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b2_9.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_1.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_2.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_3.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_4.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_5.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_6.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_7.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_8.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b3_9.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/tiles/bottom/p4b4_1.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/tiles/bottom/p4b4_2.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/images/tiles/bottom/p4b4_3.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/images/tiles/bottom/p4b4_4.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/images/tiles/bottom/p4b4_5.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/images/tiles/bottom/p4b4_6.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/tiles/bottom/p4b4_7.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_1.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_2.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_3.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_4.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_5.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_6.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_7.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_8.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
src/assets/images/tiles/bottom/p4s1_9.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_1.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_2.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_3.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_4.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_5.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_6.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_7.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_8.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/assets/images/tiles/bottom/p4s2_9.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_1.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_2.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_3.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_4.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_5.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_6.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_7.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_8.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
src/assets/images/tiles/bottom/p4s3_9.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/assets/images/tiles/bottom/p4s4_1.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src/assets/images/tiles/bottom/p4s4_2.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src/assets/images/tiles/bottom/p4s4_3.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s4_4.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
src/assets/images/tiles/bottom/p4s4_5.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/images/tiles/bottom/p4s4_6.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/assets/images/tiles/bottom/p4s4_7.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
src/assets/images/tiles/bottom/tdbgs_4.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/assets/images/tiles/left/p3s1_1.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/images/tiles/left/p3s1_2.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/images/tiles/left/p3s1_3.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s1_4.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s1_5.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s1_6.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s1_7.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s1_8.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/images/tiles/left/p3s1_9.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s2_1.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
src/assets/images/tiles/left/p3s2_2.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s2_3.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s2_4.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/tiles/left/p3s2_5.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |