feat: ✨ 新增路由守卫
This commit is contained in:
parent
16b59d6ab2
commit
f4d078ca07
14
.env.development
Normal file
14
.env.development
Normal file
@ -0,0 +1,14 @@
|
||||
# 页面标题
|
||||
VITE_WEB_TITLE = elx-template
|
||||
|
||||
# 页面英文标题
|
||||
VITE_WEB_TITLE_EN = elx-template
|
||||
|
||||
# 本地环境配置
|
||||
VITE_WEB_ENV = 'development'
|
||||
|
||||
# 本地环境
|
||||
VITE_WEB_BASE_API = '/dev-api'
|
||||
|
||||
# 本地接口
|
||||
VITE_API_URL = http://122.51.75.95:6039
|
||||
@ -1,11 +1,14 @@
|
||||
# 页面标题
|
||||
VITE_APP_TITLE = elx-template
|
||||
|
||||
# 生产环境配置
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
# 生产环境
|
||||
VITE_APP_BASE_API = '/prod-api'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
# 页面标题
|
||||
VITE_WEB_TITLE = elx-template
|
||||
|
||||
# 页面英文标题
|
||||
VITE_WEB_TITLE_EN = elx-template
|
||||
|
||||
# 生产环境配置
|
||||
VITE_WEB_ENV = 'production'
|
||||
|
||||
# 生产环境
|
||||
VITE_WEB_BASE_API = '/prod-api'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
24
index.html
24
index.html
@ -1,13 +1,17 @@
|
||||
<!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>Vite + Vue + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
<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>%VITE_WEB_TITLE%</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@ -15,10 +15,13 @@
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@jsonlee_12138/enum": "^1.0.4",
|
||||
"@vueuse/core": "^13.2.0",
|
||||
"@vueuse/integrations": "^13.2.0",
|
||||
"element-plus": "^2.9.10",
|
||||
"hook-fetch": "^1.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.2",
|
||||
"pinia-plugin-persistedstate": "^4.3.0",
|
||||
"qrcode": "^1.5.4",
|
||||
"radash": "^12.1.0",
|
||||
"reset-css": "^5.0.2",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
|
||||
185
pnpm-lock.yaml
generated
185
pnpm-lock.yaml
generated
@ -17,18 +17,27 @@ importers:
|
||||
'@vueuse/core':
|
||||
specifier: ^13.2.0
|
||||
version: 13.2.0(vue@3.5.14(typescript@5.8.3))
|
||||
'@vueuse/integrations':
|
||||
specifier: ^13.2.0
|
||||
version: 13.2.0(async-validator@4.2.5)(nprogress@0.2.0)(qrcode@1.5.4)(vue@3.5.14(typescript@5.8.3))
|
||||
element-plus:
|
||||
specifier: ^2.9.10
|
||||
version: 2.9.10(vue@3.5.14(typescript@5.8.3))
|
||||
hook-fetch:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1(typescript-api-pro@0.0.6)
|
||||
nprogress:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
pinia:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2(typescript@5.8.3)(vue@3.5.14(typescript@5.8.3))
|
||||
pinia-plugin-persistedstate:
|
||||
specifier: ^4.3.0
|
||||
version: 4.3.0(pinia@3.0.2(typescript@5.8.3)(vue@3.5.14(typescript@5.8.3)))
|
||||
qrcode:
|
||||
specifier: ^1.5.4
|
||||
version: 1.5.4
|
||||
radash:
|
||||
specifier: ^12.1.0
|
||||
version: 12.1.0
|
||||
@ -716,56 +725,67 @@ packages:
|
||||
resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.41.0':
|
||||
resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.41.0':
|
||||
resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.41.0':
|
||||
resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loongarch64-gnu@4.41.0':
|
||||
resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.41.0':
|
||||
resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.41.0':
|
||||
resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.41.0':
|
||||
resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.41.0':
|
||||
resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.41.0':
|
||||
resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.41.0':
|
||||
resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.41.0':
|
||||
resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==}
|
||||
@ -1104,41 +1124,49 @@ packages:
|
||||
resolution: {integrity: sha512-jon9M7DKRLGZ9VYSkFMflvNqu9hDtOCEnO2QAryFWgT6o6AXU8du56V7YqnaLKr6rAbZBWYsYpikF226v423QA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-arm64-musl@1.7.2':
|
||||
resolution: {integrity: sha512-c8Cg4/h+kQ63pL43wBNaVMmOjXI/X62wQmru51qjfTvI7kmCy5uHTJvK/9LrF0G8Jdx8r34d019P1DVJmhXQpA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-ppc64-gnu@1.7.2':
|
||||
resolution: {integrity: sha512-A+lcwRFyrjeJmv3JJvhz5NbcCkLQL6Mk16kHTNm6/aGNc4FwPHPE4DR9DwuCvCnVHvF5IAd9U4VIs/VvVir5lg==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-gnu@1.7.2':
|
||||
resolution: {integrity: sha512-hQQ4TJQrSQW8JlPm7tRpXN8OCNP9ez7PajJNjRD1ZTHQAy685OYqPrKjfaMw/8LiHCt8AZ74rfUVHP9vn0N69Q==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-musl@1.7.2':
|
||||
resolution: {integrity: sha512-NoAGbiqrxtY8kVooZ24i70CjLDlUFI7nDj3I9y54U94p+3kPxwd2L692YsdLa+cqQ0VoqMWoehDFp21PKRUoIQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-s390x-gnu@1.7.2':
|
||||
resolution: {integrity: sha512-KaZByo8xuQZbUhhreBTW+yUnOIHUsv04P8lKjQ5otiGoSJ17ISGYArc+4vKdLEpGaLbemGzr4ZeUbYQQsLWFjA==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-gnu@1.7.2':
|
||||
resolution: {integrity: sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-musl@1.7.2':
|
||||
resolution: {integrity: sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-wasm32-wasi@1.7.2':
|
||||
resolution: {integrity: sha512-y797JBmO9IsvXVRCKDXOxjyAE4+CcZpla2GSoBQ33TVb3ILXuFnMrbR/QQZoauBYeOFuu4w3ifWLw52sdHGz6g==}
|
||||
@ -1259,6 +1287,48 @@ packages:
|
||||
'@vueuse/core@9.13.0':
|
||||
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
|
||||
|
||||
'@vueuse/integrations@13.2.0':
|
||||
resolution: {integrity: sha512-tnwdzUYadAiewvMtBcjH/ZPgRCoQBvuVzbFA/VSysPDaIuG41Jp/Z1Sn/rYoFMOLJfcOEcVh+tN3mkrVIyumig==}
|
||||
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
|
||||
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@13.2.0':
|
||||
resolution: {integrity: sha512-kPpzuQCU0+D8DZCzK0iPpIcXI+6ufWSgwnjJ6//GNpEn+SHViaCtR+XurzORChSgvpHO9YC8gGM97Y1kB+UabA==}
|
||||
|
||||
@ -1482,6 +1552,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.30001718:
|
||||
resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==}
|
||||
|
||||
@ -1549,6 +1623,9 @@ packages:
|
||||
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
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'}
|
||||
@ -1903,6 +1980,10 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
decamelize@1.2.0:
|
||||
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
decode-named-character-reference@1.1.0:
|
||||
resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==}
|
||||
|
||||
@ -1956,6 +2037,9 @@ packages:
|
||||
devlop@1.1.0:
|
||||
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
||||
|
||||
dijkstrajs@1.0.3:
|
||||
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
engines: {node: '>=8'}
|
||||
@ -3331,6 +3415,9 @@ packages:
|
||||
normalize-wheel-es@1.2.0:
|
||||
resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
|
||||
|
||||
nprogress@0.2.0:
|
||||
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
|
||||
|
||||
nth-check@2.1.1:
|
||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||
|
||||
@ -3540,6 +3627,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@0.3.1:
|
||||
resolution: {integrity: sha512-3nW5RLmREmZ8Pm8MbPsO2RM+99RRjYd25ynj3NV0cFsN7CcEl4sDFzgoFmSyduFwxFQ2Qbu3y2UdCh6HlyUOeA==}
|
||||
|
||||
@ -3617,6 +3708,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
|
||||
|
||||
qs@6.14.0:
|
||||
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
|
||||
engines: {node: '>=0.6'}
|
||||
@ -3698,6 +3794,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==}
|
||||
|
||||
reset-css@5.0.2:
|
||||
resolution: {integrity: sha512-YtgUGSq5z5W0NPSjsBW7ys7rtWa8P8AiE7S6Fg3d1TQCPpAodgYyLuZYlU0AOsLtprk/fC9ormHN/0pAavVIDw==}
|
||||
|
||||
@ -3914,6 +4013,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'}
|
||||
@ -4528,6 +4630,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'}
|
||||
@ -4541,6 +4646,10 @@ packages:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
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'}
|
||||
@ -4553,6 +4662,9 @@ packages:
|
||||
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
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'}
|
||||
@ -4566,10 +4678,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'}
|
||||
@ -5943,6 +6063,16 @@ snapshots:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/integrations@13.2.0(async-validator@4.2.5)(nprogress@0.2.0)(qrcode@1.5.4)(vue@3.5.14(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@vueuse/core': 13.2.0(vue@3.5.14(typescript@5.8.3))
|
||||
'@vueuse/shared': 13.2.0(vue@3.5.14(typescript@5.8.3))
|
||||
vue: 3.5.14(typescript@5.8.3)
|
||||
optionalDependencies:
|
||||
async-validator: 4.2.5
|
||||
nprogress: 0.2.0
|
||||
qrcode: 1.5.4
|
||||
|
||||
'@vueuse/metadata@13.2.0': {}
|
||||
|
||||
'@vueuse/metadata@9.13.0': {}
|
||||
@ -6172,6 +6302,8 @@ snapshots:
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
camelcase@5.3.1: {}
|
||||
|
||||
caniuse-lite@1.0.30001718: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
@ -6253,6 +6385,12 @@ snapshots:
|
||||
slice-ansi: 5.0.0
|
||||
string-width: 7.2.0
|
||||
|
||||
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
|
||||
@ -6617,6 +6755,8 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
decamelize@1.2.0: {}
|
||||
|
||||
decode-named-character-reference@1.1.0:
|
||||
dependencies:
|
||||
character-entities: 2.0.2
|
||||
@ -6668,6 +6808,8 @@ snapshots:
|
||||
dependencies:
|
||||
dequal: 2.0.3
|
||||
|
||||
dijkstrajs@1.0.3: {}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
dependencies:
|
||||
path-type: 4.0.0
|
||||
@ -8409,6 +8551,8 @@ snapshots:
|
||||
|
||||
normalize-wheel-es@1.2.0: {}
|
||||
|
||||
nprogress@0.2.0: {}
|
||||
|
||||
nth-check@2.1.1:
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
@ -8602,6 +8746,8 @@ snapshots:
|
||||
|
||||
pluralize@8.0.0: {}
|
||||
|
||||
pngjs@5.0.0: {}
|
||||
|
||||
pnpm-workspace-yaml@0.3.1:
|
||||
dependencies:
|
||||
yaml: 2.8.0
|
||||
@ -8674,6 +8820,12 @@ snapshots:
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
qrcode@1.5.4:
|
||||
dependencies:
|
||||
dijkstrajs: 1.0.3
|
||||
pngjs: 5.0.0
|
||||
yargs: 15.4.1
|
||||
|
||||
qs@6.14.0:
|
||||
dependencies:
|
||||
side-channel: 1.1.0
|
||||
@ -8761,6 +8913,8 @@ snapshots:
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
require-main-filename@2.0.0: {}
|
||||
|
||||
reset-css@5.0.2: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
@ -8962,6 +9116,8 @@ snapshots:
|
||||
|
||||
semver@7.7.2: {}
|
||||
|
||||
set-blocking@2.0.0: {}
|
||||
|
||||
set-function-length@1.2.2:
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
@ -9720,6 +9876,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
|
||||
@ -9736,6 +9894,12 @@ snapshots:
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
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
|
||||
@ -9750,6 +9914,8 @@ snapshots:
|
||||
|
||||
xml-name-validator@4.0.0: {}
|
||||
|
||||
y18n@4.0.3: {}
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
yaml-eslint-parser@1.3.0:
|
||||
@ -9759,8 +9925,27 @@ snapshots:
|
||||
|
||||
yaml@2.8.0: {}
|
||||
|
||||
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
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type {
|
||||
ChatSessionVo,
|
||||
CreateSessionDTO,
|
||||
CreateSessionVO,
|
||||
// CreateSessionVO,
|
||||
GetSessionListParams,
|
||||
} from './types';
|
||||
import { get, post } from '@/utils/request';
|
||||
@ -11,5 +11,5 @@ export function getSessionList(params: GetSessionListParams) {
|
||||
}
|
||||
|
||||
export function createSession(data: CreateSessionDTO) {
|
||||
return post<CreateSessionVO>('/system/session', data);
|
||||
return post('/system/session', data);
|
||||
}
|
||||
|
||||
@ -137,6 +137,6 @@ export interface CreateSessionDTO {
|
||||
userId: number;
|
||||
}
|
||||
|
||||
export interface CreateSessionVO {
|
||||
id: number;
|
||||
}
|
||||
// export interface CreateSessionVO {
|
||||
// id: number;
|
||||
// }
|
||||
|
||||
1
src/assets/icons/svg/qs-403.svg
Normal file
1
src/assets/icons/svg/qs-403.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
1
src/assets/icons/svg/qs-404.svg
Normal file
1
src/assets/icons/svg/qs-404.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 24 KiB |
1
src/assets/icons/svg/qs-500.svg
Normal file
1
src/assets/icons/svg/qs-500.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 22 KiB |
BIN
src/assets/images/error/403.png
Normal file
BIN
src/assets/images/error/403.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 103 KiB |
BIN
src/assets/images/error/404.png
Normal file
BIN
src/assets/images/error/404.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
BIN
src/assets/images/error/500.png
Normal file
BIN
src/assets/images/error/500.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
@ -5,7 +5,7 @@ import type { LoginDTO } from '@/api/auth/types';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { login } from '@/api';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@ -29,7 +29,9 @@ async function handleSubmit() {
|
||||
console.log(res, 'res');
|
||||
res.data.token && userStore.setToken(res.data.token);
|
||||
res.data.userInfo && userStore.setUserInfo(res.data.userInfo);
|
||||
ElMessage.success('登录成功');
|
||||
router.replace('/');
|
||||
userStore.closeLoginDialog();
|
||||
}
|
||||
catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
@ -39,7 +41,7 @@ async function handleSubmit() {
|
||||
|
||||
<template>
|
||||
<div class="custom-form">
|
||||
<el-form ref="formRef" :model="formModel" :rules="rules">
|
||||
<el-form ref="formRef" :model="formModel" :rules="rules" style="width: 230px">
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="formModel.username" placeholder="请输入用户名" clearable>
|
||||
<template #prefix>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { ref, watch } from 'vue';
|
||||
import logoPng from '@/assets/images/logo.png';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
import AccountPassword from './components/FormLogin/AccountPassword.vue';
|
||||
import QrCodeLogin from './components/QrCodeLogin/index.vue';
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<!-- 欢迎提示词 -->
|
||||
<script setup lang="ts">
|
||||
import { useTimeGreeting } from '@/hooks/useTimeGreeting';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const greeting = useTimeGreeting();
|
||||
const userStore = useUserStore();
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
export const HOME_URL: string = '/chat';
|
||||
|
||||
// 登录页地址[默认]
|
||||
export const LOGIN_URL: string = '/login';
|
||||
// export const LOGIN_URL: string = '/login';
|
||||
|
||||
// 默认主题颜色
|
||||
export const DEFAULT_THEME_COLOR: string = '#2992FF';
|
||||
@ -15,4 +15,4 @@ export const COLLAPSE_THRESHOLD: number = 600;
|
||||
export const SIDE_BAR_WIDTH: number = 280;
|
||||
|
||||
// 路由白名单地址[本地存在的路由 staticRouter.ts 中]
|
||||
export const ROUTER_WHITE_LIST: string[] = ['/500'];
|
||||
export const ROUTER_WHITE_LIST: string[] = ['/chat', '/500', '/403', '/404'];
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { COLLAPSE_THRESHOLD } from '@/config/index';
|
||||
import { useWindowWidthObserver } from '@/hooks/useWindowWidthObserver';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
/**
|
||||
* 侧边栏折叠切换逻辑组合式函数 方便多个页面调用
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { MaybeRef } from 'vue';
|
||||
import { onBeforeUnmount, ref, unref, watch } from 'vue';
|
||||
import { COLLAPSE_THRESHOLD, SIDE_BAR_WIDTH } from '@/config/index';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
/**
|
||||
* 这里逻辑是研究豆包的折叠逻辑后,设计的折叠方法
|
||||
|
||||
@ -5,7 +5,7 @@ import { useWindowWidthObserver } from '@/hooks/useWindowWidthObserver';
|
||||
import Aside from '@/layouts/components/Aside/index.vue';
|
||||
import Header from '@/layouts/components/Header/index.vue';
|
||||
import Main from '@/layouts/components/Main/index.vue';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
const designStore = useDesignStore();
|
||||
|
||||
|
||||
@ -1,27 +1,31 @@
|
||||
<!-- Aside 侧边栏 -->
|
||||
<script setup lang="ts">
|
||||
import type { GroupableOptions } from 'vue-element-plus-x/types/Conversations';
|
||||
import { useRoute } from 'vue-router';
|
||||
import type { ConversationItem, GroupableOptions } from 'vue-element-plus-x/types/Conversations';
|
||||
import type { ChatSessionVo } from '@/api/session/types';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import logo from '@/assets/images/logo.png';
|
||||
import Collapse from '@/layouts/components/Header/components/Collapse.vue';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useChatStore } from '@/store/modules/chat';
|
||||
import { useDesignStore } from '@/stores';
|
||||
import { useSessionStore } from '@/stores/modules/session';
|
||||
|
||||
const route = useRoute();
|
||||
const chatStore = useChatStore();
|
||||
const router = useRouter();
|
||||
const designStore = useDesignStore();
|
||||
const sessionStore = useSessionStore();
|
||||
|
||||
const chatId = computed(() => Number(route.params?.id));
|
||||
const conversationsList = computed(() => chatStore.chatMap[chatId.value] ?? []);
|
||||
// const sessionId = computed(() => Number(route.params?.id));
|
||||
const conversationsList = computed(() => sessionStore.sessionList);
|
||||
|
||||
/* 创建会话 开始 */
|
||||
function handleCreatChat() {
|
||||
console.log('创建新会话');
|
||||
// 创建会话, 跳转到默认聊天
|
||||
sessionStore.createSessionBtn();
|
||||
}
|
||||
/* 创建会话 结束 */
|
||||
|
||||
/* 会话组件 开始 */
|
||||
const active = ref('m1');
|
||||
const active = computed<string>(() => (route.params?.id as string) ?? '');
|
||||
|
||||
// 自定义分组选项
|
||||
const customGroupOptions: GroupableOptions = {
|
||||
@ -34,10 +38,20 @@ const customGroupOptions: GroupableOptions = {
|
||||
},
|
||||
};
|
||||
|
||||
function handleChange() {
|
||||
console.log('点击了会话');
|
||||
function handleChange(item: ConversationItem<ChatSessionVo>) {
|
||||
console.log('点击了会话 item', item);
|
||||
router.replace({
|
||||
name: 'chatWithId',
|
||||
params: {
|
||||
id: item.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
/* 会话组件 结束 */
|
||||
|
||||
watchEffect(() => {
|
||||
console.log('active', active.value, '>>>');
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -2,8 +2,12 @@
|
||||
<script setup lang="ts">
|
||||
import Popover from '@/components/Popover/index.vue';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const src = ref('https://avatars.githubusercontent.com/u/76239030');
|
||||
const userStore = useUserStore();
|
||||
const src = computed(
|
||||
() => userStore.userInfo?.avatar ?? 'https://avatars.githubusercontent.com/u/76239030',
|
||||
);
|
||||
|
||||
/* 弹出面板 开始 */
|
||||
const popoverStyle = ref({
|
||||
@ -40,9 +44,11 @@ const popoverList = ref([
|
||||
function handleClick(item: any) {
|
||||
switch (item.key) {
|
||||
case '1':
|
||||
ElMessage.warning('暂未开放');
|
||||
console.log('点击了收藏夹');
|
||||
break;
|
||||
case '2':
|
||||
ElMessage.warning('暂未开放');
|
||||
console.log('点击了设置');
|
||||
break;
|
||||
case '4':
|
||||
@ -57,7 +63,7 @@ function handleClick(item: any) {
|
||||
})
|
||||
.then(() => {
|
||||
// 在这里执行退出方法
|
||||
|
||||
userStore.logout();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '退出成功',
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { SIDE_BAR_WIDTH } from '@/config/index';
|
||||
import { useCollapseToggle } from '@/hooks/useCollapseToggle';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
const { changeCollapse } = useCollapseToggle();
|
||||
const designStore = useDesignStore();
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
<!-- LoginBtn 登录按钮 -->
|
||||
<script setup lang="ts">
|
||||
import LoginDialog from '@/components/LoginDialog/index.vue';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const isLoginDialogVisible = computed(() => userStore.isLoginDialogVisible);
|
||||
|
||||
// 点击登录按钮时调用Store方法打开弹框
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<!-- Header 头部 -->
|
||||
<script setup lang="ts">
|
||||
import { SIDE_BAR_WIDTH } from '@/config/index';
|
||||
import { useDesignStore, useUserStore } from '@/store';
|
||||
import { useDesignStore, useUserStore } from '@/stores';
|
||||
import Avatar from './components/Avatar.vue';
|
||||
import Collapse from './components/Collapse.vue';
|
||||
import CreateChat from './components/CreateChat.vue';
|
||||
@ -54,10 +54,8 @@ onMounted(() => {
|
||||
|
||||
<!-- 右边 -->
|
||||
<div class="right-box flex h-full items-center pr-20px flex-shrink-0 mr-auto flex-row">
|
||||
<Avatar v-if="userStore.token" />
|
||||
<LoginBtn v-else />
|
||||
<!-- <Avatar />
|
||||
<LoginBtn /> -->
|
||||
<Avatar v-show="userStore.token" />
|
||||
<LoginBtn v-show="!userStore.token" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<!-- Main -->
|
||||
<script setup lang="ts">
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useKeepAliveStore } from '@/store/modules/keepAlive';
|
||||
import { useDesignStore } from '@/stores';
|
||||
import { useKeepAliveStore } from '@/stores/modules/keepAlive';
|
||||
|
||||
const designStore = useDesignStore();
|
||||
const keepAliveStore = useKeepAliveStore();
|
||||
@ -16,7 +16,7 @@ provide('refresh', refreshMainPage);
|
||||
<el-main class="layout-main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition :name="designStore.pageAnimateType" mode="out-in" appear>
|
||||
<keep-alive :max="16" :include="keepAliveStore.keepAliveName">
|
||||
<keep-alive :max="10" :include="keepAliveStore.keepAliveName">
|
||||
<component :is="Component" v-if="isRouterShow" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ConversationItem } from 'vue-element-plus-x/types/Conversations';
|
||||
import type { ChatSessionVo } from '@/api/session/types';
|
||||
// import { useUserStore } from '@/store';
|
||||
// import { useUserStore } from '@/stores';
|
||||
import { Conversations } from 'vue-element-plus-x';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
// import { getSessionList } from '@/api';
|
||||
@ -43,13 +43,13 @@ function handleChange(item: ConversationItem<ChatSessionVo>) {
|
||||
const sessionId = computed<string>(() => route.params?.id as string);
|
||||
function handleNewSession() {
|
||||
if (sessionId.value) {
|
||||
router.replace({ name: 'chatWithoutId' });
|
||||
router.replace({ name: 'chatWithId' });
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
console.log('active', active.value, '>>>');
|
||||
});
|
||||
// watchEffect(() => {
|
||||
// console.log('active', active.value, '>>>');
|
||||
// });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import type { LayoutType } from '@/config/design';
|
||||
// import { useScreenStore } from '@/hooks/useScreen';
|
||||
import LayoutVertical from '@/layouts/LayoutVertical/index.vue';
|
||||
import { useDesignStore } from '@/store';
|
||||
import { useDesignStore } from '@/stores';
|
||||
|
||||
// 这里添加布局类型
|
||||
const LayoutComponent: Record<LayoutType, Component> = {
|
||||
|
||||
@ -4,8 +4,8 @@ import { ElMessage } from 'element-plus';
|
||||
import { createApp } from 'vue';
|
||||
import ElementPlusX from 'vue-element-plus-x';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import router from './routers';
|
||||
import store from './stores';
|
||||
import './styles/index.scss';
|
||||
import 'virtual:uno.css';
|
||||
import 'element-plus/dist/index.css';
|
||||
|
||||
@ -1,20 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { Sender } from 'vue-element-plus-x';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { createSession } from '@/api';
|
||||
import { send } from '@/api/chat';
|
||||
import WelecomeText from '@/components/WelecomeText/index.vue';
|
||||
import { ModelEnum } from '@/constants/enums';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useChatStore } from '@/store/modules/chat';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChatDefaul from '@/pages/chat/layouts/chatDefaul/index.vue';
|
||||
import ChatWithId from '@/pages/chat/layouts/chatWithId/index.vue';
|
||||
import { useChatStore } from '@/stores/modules/chat';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const chatStore = useChatStore();
|
||||
|
||||
const senderValue = ref('');
|
||||
const isSelect = ref(false);
|
||||
|
||||
const chatId = computed(() => Number(route.params?.id));
|
||||
if (chatId.value) {
|
||||
@ -30,107 +23,28 @@ watch(
|
||||
senderValue.value = v;
|
||||
localStorage.removeItem('chatContent');
|
||||
// 发送消息
|
||||
console.log(v);
|
||||
console.log('发送消息 v', v);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
// const a = JSON.parse(`{"id":"chatcmpl-BVD1f4snw4KHOCKIgu4JOMoZbOwRh","object":"chat.completion.chunk","created":1746777939,"model":"gpt-4o-mini-2024-07-18","system_fingerprint":"fp_ded0d14823","choices":[{"delta":{"content":"","role":"assistant"},"logprobs":null,"finish_reason":null,"index":0}],"usage":null}`)
|
||||
// console.log(a);
|
||||
const loading = ref(false);
|
||||
async function handleSend() {
|
||||
if (!chatId.value) {
|
||||
try {
|
||||
const res = await createSession({
|
||||
userId: userStore.userInfo?.userId as number,
|
||||
sessionContent: senderValue.value,
|
||||
sessionTitle: senderValue.value.slice(0, 10),
|
||||
remark: senderValue.value.slice(0, 10),
|
||||
});
|
||||
localStorage.setItem('chatContent', senderValue.value);
|
||||
router.replace({
|
||||
name: 'chat',
|
||||
params: {
|
||||
id: res.data.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('createSessionError', error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 发送消息
|
||||
loading.value = true;
|
||||
const req = send({
|
||||
sessionId: chatId.value,
|
||||
model: ModelEnum.GPT_4o_MINI.value,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: senderValue.value,
|
||||
},
|
||||
],
|
||||
});
|
||||
for await (const chunk of req) {
|
||||
if (chunk.result && typeof chunk.result === 'string') {
|
||||
console.log('string:', chunk.result);
|
||||
// const a = JSON.parse(chunk.result);
|
||||
// console.log(a,'>>>');
|
||||
}
|
||||
console.log(chunk.result);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="chat-home-container">
|
||||
<div class="chat-home-wrap">
|
||||
<WelecomeText />
|
||||
<Sender
|
||||
v-model="senderValue"
|
||||
class="chat-home-sender"
|
||||
:auto-size="{
|
||||
maxRows: 9,
|
||||
minRows: 3,
|
||||
}"
|
||||
:loading="loading"
|
||||
variant="updown"
|
||||
clearable
|
||||
allow-speech
|
||||
@submit="handleSend"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
||||
<div
|
||||
class="flex items-center gap-4px px-12px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
>
|
||||
<el-icon>
|
||||
<Paperclip />
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="{ isSelect }"
|
||||
class="flex items-center gap-4px px-10px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
@click="isSelect = !isSelect"
|
||||
>
|
||||
<el-icon>
|
||||
<ElementPlus />
|
||||
</el-icon>
|
||||
<span>深度思考</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Sender>
|
||||
</div>
|
||||
<div class="chat-container">
|
||||
<!-- 默认聊天页面 -->
|
||||
<ChatDefaul v-if="!chatId" />
|
||||
<!-- 带id的聊天页面 -->
|
||||
<ChatWithId v-else :chat-id="chatId" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chat-home-container {
|
||||
.chat-container {
|
||||
padding: 0 16px;
|
||||
width: calc(100% - 32px);
|
||||
position: relative;
|
||||
@ -140,19 +54,5 @@ async function handleSend() {
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
overflow-anchor: none;
|
||||
|
||||
.chat-home-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
min-height: 450px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.chat-home-sender {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
91
src/pages/chat/layouts/chatDefaul/index.vue
Normal file
91
src/pages/chat/layouts/chatDefaul/index.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<!-- -->
|
||||
<script setup lang="ts">
|
||||
import WelecomeText from '@/components/WelecomeText/index.vue';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useChatStore } from '@/stores/modules/chat';
|
||||
import { useSessionStore } from '@/stores/modules/session';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const chatStore = useChatStore();
|
||||
const sessionStore = useSessionStore();
|
||||
const senderValue = ref('');
|
||||
|
||||
const isDeepThinking = computed(() => chatStore.isDeepThinking);
|
||||
|
||||
async function handleSend() {
|
||||
await sessionStore.createSessionList({
|
||||
userId: userStore.userInfo?.userId as number,
|
||||
sessionContent: senderValue.value,
|
||||
sessionTitle: senderValue.value.slice(0, 10),
|
||||
remark: senderValue.value.slice(0, 10),
|
||||
});
|
||||
}
|
||||
|
||||
// 设置是否深度思考
|
||||
function setIsDeepThinking() {
|
||||
chatStore.setDeepThinking(!chatStore.isDeepThinking);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="chat-defaul-wrap">
|
||||
<WelecomeText />
|
||||
<Sender
|
||||
v-model="senderValue"
|
||||
class="chat-defaul-sender"
|
||||
:auto-size="{
|
||||
maxRows: 9,
|
||||
minRows: 3,
|
||||
}"
|
||||
variant="updown"
|
||||
clearable
|
||||
allow-speech
|
||||
@submit="handleSend"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
||||
<div
|
||||
class="flex items-center gap-4px px-12px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
>
|
||||
<el-icon>
|
||||
<Paperclip />
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="{ 'is-select': isDeepThinking }"
|
||||
class="flex items-center gap-4px px-10px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||
@click="setIsDeepThinking"
|
||||
>
|
||||
<el-icon>
|
||||
<ElementPlus />
|
||||
</el-icon>
|
||||
<span>深度思考</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Sender>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.chat-defaul-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
min-height: 450px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.chat-defaul-sender {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.is-select {
|
||||
color: var(--el-color-primary, #409eff);
|
||||
border: 1px solid var(--el-color-primary, #409eff);
|
||||
border-radius: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
18
src/pages/chat/layouts/chatWithId/index.vue
Normal file
18
src/pages/chat/layouts/chatWithId/index.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 每个回话对应的聊天内容 -->
|
||||
<script setup lang="ts">
|
||||
interface ChatWithIdProps {
|
||||
chatId?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<ChatWithIdProps>(), {
|
||||
chatId: undefined,
|
||||
});
|
||||
|
||||
console.log('props ==> ', props);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>新建对话</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
65
src/pages/error/403.vue
Normal file
65
src/pages/error/403.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_URL } from '@/config/index.ts';
|
||||
|
||||
// 路由跳转
|
||||
const router = useRouter();
|
||||
|
||||
function handleHomePage() {
|
||||
router.push({ path: HOME_URL });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="box">
|
||||
<div id="banner" class="elx-top" />
|
||||
<div class="elx-bottom">
|
||||
<div class="elx-text1">
|
||||
403
|
||||
</div>
|
||||
<div class="elx-text2">
|
||||
对不起,您没有权限访问
|
||||
</div>
|
||||
<div class="h-20px" />
|
||||
<el-button type="primary" plain @click="handleHomePage">
|
||||
返回首页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#banner {
|
||||
margin-top: 60px;
|
||||
background: url("@/assets/images/error/403.png") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.elx-top {
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.elx-bottom {
|
||||
height: 300px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.elx-text1 {
|
||||
font-size: 46px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.elx-text2 {
|
||||
padding-top: 30px;
|
||||
font-family: YouYuan;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
65
src/pages/error/404.vue
Normal file
65
src/pages/error/404.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_URL } from '@/config/index.ts';
|
||||
|
||||
// 路由跳转
|
||||
const router = useRouter();
|
||||
|
||||
function handleHomePage() {
|
||||
router.push({ path: HOME_URL });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="box">
|
||||
<div id="banner" class="elx-top" />
|
||||
<div class="elx-bottom">
|
||||
<div class="elx-text1">
|
||||
404
|
||||
</div>
|
||||
<div class="elx-text2">
|
||||
您想看的页面不存在哟
|
||||
</div>
|
||||
<div class="h-20px" />
|
||||
<el-button type="primary" plain @click="handleHomePage">
|
||||
返回首页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#banner {
|
||||
margin-top: 60px;
|
||||
background: url("@/assets/images/error/404.png") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.elx-top {
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.elx-bottom {
|
||||
height: 300px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.elx-text1 {
|
||||
font-size: 46px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.elx-text2 {
|
||||
padding-top: 30px;
|
||||
font-family: YouYuan;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
60
src/pages/error/500.vue
Normal file
60
src/pages/error/500.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_URL } from '@/config/index.ts';
|
||||
|
||||
// 路由跳转
|
||||
const router = useRouter();
|
||||
|
||||
function handleHomePage() {
|
||||
router.push({ path: HOME_URL });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="box">
|
||||
<div id="banner" class="elx-top" />
|
||||
<div class="elx-bottom">
|
||||
<div class="elx-text1">
|
||||
500
|
||||
</div>
|
||||
<div class="elx-text2">
|
||||
服务器好像开小差了!请稍后试试...
|
||||
</div>
|
||||
<div class="h-20px" />
|
||||
<el-button type="primary" plain @click="handleHomePage">
|
||||
返回首页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#box {
|
||||
overflow: hidden;
|
||||
}
|
||||
#banner {
|
||||
margin-top: 60px;
|
||||
background: url("@/assets/images/error/500.png") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
.elx-top {
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.elx-bottom {
|
||||
height: 300px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.elx-text1 {
|
||||
font-size: 46px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.elx-text2 {
|
||||
padding-top: 30px;
|
||||
font-family: YouYuan;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@ -1,53 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import type { LoginDTO } from '@/api/auth/types';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { login } from '@/api';
|
||||
import { useUserStore } from '@/store';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const formModel = reactive<LoginDTO>({
|
||||
username: '',
|
||||
password: '',
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
await formRef.value?.validate();
|
||||
const res = await login(formModel);
|
||||
console.log(res, 'res');
|
||||
res.data.token && userStore.setToken(res.data.token);
|
||||
res.data.userInfo && userStore.setUserInfo(res.data.userInfo);
|
||||
router.replace('/');
|
||||
}
|
||||
catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-screen h-screen justify-center items-center flex bg-black">
|
||||
<div class="max-w-[500px] w-full p-5 rounded bg-white/60 backdrop-blur-md">
|
||||
<h1>登录</h1>
|
||||
<el-form ref="formRef" :model="formModel">
|
||||
<el-form-item label="用户名" name="username">
|
||||
<el-input v-model="formModel.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" name="password">
|
||||
<el-input v-model="formModel.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSubmit">
|
||||
登录
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,41 +0,0 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { jwtGuard } from './permissions';
|
||||
|
||||
const routes: Readonly<RouteRecordRaw>[] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: 'chat',
|
||||
component: () => import('@/layouts/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/chat',
|
||||
name: 'chat',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/chat:id',
|
||||
name: 'chatWithoutId',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import('@/pages/login/index.vue'),
|
||||
},
|
||||
] as const;
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
console.group('Routes');
|
||||
console.log('routes', router.getRoutes());
|
||||
console.groupEnd();
|
||||
|
||||
router.beforeEach(jwtGuard());
|
||||
|
||||
export default router;
|
||||
@ -1,7 +0,0 @@
|
||||
import type { NavigationGuard } from 'vue-router';
|
||||
|
||||
export function jwtGuard(): NavigationGuard {
|
||||
return () => {
|
||||
console.log('进入路由守卫');
|
||||
};
|
||||
}
|
||||
85
src/routers/index.ts
Normal file
85
src/routers/index.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
|
||||
import { useNProgress } from '@vueuse/integrations/useNProgress';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { ROUTER_WHITE_LIST } from '@/config';
|
||||
import { errorRouter, layoutRouter, staticRouter } from '@/routers/modules/staticRouter';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const { start, done } = useNProgress(0, {
|
||||
showSpinner: false,
|
||||
trickleSpeed: 200,
|
||||
minimum: 0.3,
|
||||
easing: 'ease',
|
||||
speed: 500,
|
||||
});
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [...layoutRouter, ...staticRouter, ...errorRouter],
|
||||
strict: false,
|
||||
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||
});
|
||||
|
||||
console.group('Routes');
|
||||
console.log('routes', router.getRoutes());
|
||||
console.groupEnd();
|
||||
|
||||
// 路由前置守卫
|
||||
router.beforeEach(
|
||||
async (
|
||||
to: RouteLocationNormalized,
|
||||
_from: RouteLocationNormalized,
|
||||
next: NavigationGuardNext,
|
||||
) => {
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 1、NProgress 开始
|
||||
start();
|
||||
|
||||
// 2、标题
|
||||
document.title = to.meta.title || import.meta.env.VITE_WEB_TITLE;
|
||||
|
||||
// 3、权限 预留
|
||||
// 3、判断是访问登陆页,有Token访问当前页面,token过期访问接口,axios封装则自动跳转登录页面,没有Token重置路由到登陆页。
|
||||
// if (to.path.toLocaleLowerCase() === LOGIN_URL) {
|
||||
// // 有Token访问当前页面
|
||||
// if (userStore.token) {
|
||||
// return next(from.fullPath);
|
||||
// }
|
||||
// else {
|
||||
// ElMessage.error('账号身份已过期,请重新登录🌻');
|
||||
// }
|
||||
// // 没有Token重置路由到登陆页。
|
||||
// // resetRouter(); // 预留
|
||||
// return next();
|
||||
// }
|
||||
|
||||
// 4、判断访问页面是否在路由白名单地址[静态路由]中,如果存在直接放行。
|
||||
if (ROUTER_WHITE_LIST.includes(to.path))
|
||||
return next();
|
||||
|
||||
// 5、判断是否有 Token,没有重定向到 login 页面。
|
||||
if (!userStore.token)
|
||||
userStore.logout();
|
||||
|
||||
// 其余逻辑 预留...
|
||||
|
||||
// 6、正常访问页面。
|
||||
next();
|
||||
},
|
||||
);
|
||||
|
||||
// 路由跳转错误
|
||||
router.onError((error) => {
|
||||
// 结束全屏动画
|
||||
done();
|
||||
console.warn('路由错误', error.message);
|
||||
});
|
||||
|
||||
// 后置路由
|
||||
router.afterEach(() => {
|
||||
// 结束全屏动画
|
||||
done();
|
||||
});
|
||||
|
||||
export default router;
|
||||
39
src/routers/modules/dynamicRouter.ts
Normal file
39
src/routers/modules/dynamicRouter.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// 预留
|
||||
import router from '@/routers/index';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useAuthStore } from '@/stores/modules/auth';
|
||||
|
||||
export async function initDynamicRouter() {
|
||||
const userStore = useUserStore();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
try {
|
||||
// 1、预留: 获取菜单列表 || 按钮权限列表 || 递归菜单数据
|
||||
await authStore.requestAuthMenuList();
|
||||
|
||||
// 2、判断当前用户是否拥有菜单权限
|
||||
console.log('authStore.authMenuList', authStore.authMenuList);
|
||||
|
||||
if (authStore.authMenuList == null || authStore.authMenuList.length === 0) {
|
||||
userStore.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
// 3、添加动态路由
|
||||
authStore.authMenuList.forEach((item: any) => {
|
||||
if (item.isFull === '0') {
|
||||
// 如果是全屏的话,直接为整个页面
|
||||
router.addRoute(item);
|
||||
}
|
||||
else {
|
||||
router.addRoute('layout', item);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
// 当菜单请求出错时,重定向到首页
|
||||
userStore.logout();
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
91
src/routers/modules/staticRouter.ts
Normal file
91
src/routers/modules/staticRouter.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { HOME_URL } from '@/config';
|
||||
|
||||
// LayoutRouter[布局路由]
|
||||
export const layoutRouter: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: HOME_URL,
|
||||
component: () => import('@/layouts/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: HOME_URL,
|
||||
name: 'chat',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
meta: {
|
||||
title: '通用聊天页面',
|
||||
icon: 'HomeFilled',
|
||||
isHide: '1',
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
// enName: "Master Station", // 英文名称 预留
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/chat/:id',
|
||||
name: 'chatWithId',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
meta: {
|
||||
title: '带 ID 的聊天页面',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// staticRouter[静态路由] 预留
|
||||
export const staticRouter: RouteRecordRaw[] = [];
|
||||
|
||||
// errorRouter (错误页面路由)
|
||||
export const errorRouter = [
|
||||
{
|
||||
path: '/403',
|
||||
name: '403',
|
||||
component: () => import('@/pages/error/403.vue'),
|
||||
meta: {
|
||||
title: '403页面',
|
||||
enName: '403 Page', // 英文名称
|
||||
icon: 'QuestionFilled', // 菜单图标
|
||||
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏,1显示]
|
||||
isLink: '1', // 是否外链[有值则是外链]
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
isAffix: '1', // 是否缓存固定路由[0是,1否]
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
name: '404',
|
||||
component: () => import('@/pages/error/404.vue'),
|
||||
meta: {
|
||||
title: '404页面',
|
||||
enName: '404 Page', // 英文名称
|
||||
icon: 'CircleCloseFilled', // 菜单图标
|
||||
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏,1显示]
|
||||
isLink: '1', // 是否外链[有值则是外链]
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
isAffix: '1', // 是否缓存固定路由[0是,1否]
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/500',
|
||||
name: '500',
|
||||
component: () => import('@/pages/error/500.vue'),
|
||||
meta: {
|
||||
title: '500页面',
|
||||
enName: '500 Page', // 英文名称
|
||||
icon: 'WarningFilled', // 图标
|
||||
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏,1显示]
|
||||
isLink: '1', // 是否外链[有值则是外链]
|
||||
isKeepAlive: '0', // 是否缓存路由数据[0是,1否]
|
||||
isFull: '1', // 是否缓存全屏[0是,1否]
|
||||
isAffix: '1', // 是否缓存固定路由[0是,1否]
|
||||
},
|
||||
},
|
||||
// 找不到path将跳转404页面
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
component: () => import('@/pages/error/404.vue'),
|
||||
},
|
||||
];
|
||||
18
src/stores/modules/auth.ts
Normal file
18
src/stores/modules/auth.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
// 权限状态管理
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
// 权限菜单列表
|
||||
const authMenuList = ref<any[]>([]);
|
||||
|
||||
// 请求权限菜单列表
|
||||
const requestAuthMenuList = async () => {
|
||||
// const res = await initDynamicRouter();
|
||||
authMenuList.value = [];
|
||||
};
|
||||
|
||||
return {
|
||||
authMenuList,
|
||||
requestAuthMenuList,
|
||||
};
|
||||
});
|
||||
@ -5,6 +5,7 @@ import { useUserStore } from './user';
|
||||
|
||||
export const useChatStore = defineStore('chat', () => {
|
||||
const userStore = useUserStore();
|
||||
|
||||
const chatMap = ref<Record<number, ChatMessageVo[]>>({});
|
||||
|
||||
const setChatMap = (id: number, data: ChatMessageVo[]) => {
|
||||
@ -26,8 +27,17 @@ export const useChatStore = defineStore('chat', () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 是否开启深度思考
|
||||
const isDeepThinking = ref<boolean>(false);
|
||||
|
||||
const setDeepThinking = (value: boolean) => {
|
||||
isDeepThinking.value = value;
|
||||
};
|
||||
|
||||
return {
|
||||
chatMap,
|
||||
requestChatList,
|
||||
isDeepThinking,
|
||||
setDeepThinking,
|
||||
};
|
||||
});
|
||||
69
src/stores/modules/session.ts
Normal file
69
src/stores/modules/session.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import type { CreateSessionDTO } from '@/api/session/types';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { createSession, getSessionList } from '@/api/session';
|
||||
import { useUserStore } from './user';
|
||||
|
||||
export const useSessionStore = defineStore('session', () => {
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const sessionList = ref<CreateSessionDTO[]>([]);
|
||||
|
||||
// 单独点击创建新对话按钮
|
||||
const createSessionBtn = async () => {
|
||||
try {
|
||||
// 直接回到首页
|
||||
router.replace({ name: 'chat' });
|
||||
}
|
||||
catch (error) {
|
||||
console.error('createSessionBtn:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 发送消息后,创建对话
|
||||
const createSessionList = async (data: CreateSessionDTO) => {
|
||||
try {
|
||||
const res = await createSession(data);
|
||||
localStorage.setItem('chatContent', data.sessionContent);
|
||||
router.replace({
|
||||
name: 'chatWithId',
|
||||
params: {
|
||||
id: `${res.data}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('createSession:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取会话列表
|
||||
const requestSessionList = async () => {
|
||||
try {
|
||||
const res = await getSessionList({
|
||||
userId: userStore.userInfo?.userId as number,
|
||||
});
|
||||
if (res.rows) {
|
||||
sessionList.value = (res.rows || []).map(item => ({
|
||||
...item,
|
||||
// 提供默认值
|
||||
remark: item.remark || '',
|
||||
sessionContent: item.sessionContent || '',
|
||||
sessionTitle: item.sessionTitle || '',
|
||||
userId: item.userId || -1,
|
||||
}));
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('getSessionList:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
sessionList,
|
||||
createSessionBtn,
|
||||
createSessionList,
|
||||
requestSessionList,
|
||||
};
|
||||
});
|
||||
@ -16,4 +16,9 @@
|
||||
--login-dialog-logo-background: #fff;
|
||||
--login-dialog-logo-text-color: #191919;
|
||||
|
||||
|
||||
|
||||
/* 覆盖 element-plus 样式 */
|
||||
--el-border-radius-base: 12px;
|
||||
--el-messagebox-border-radius: 16px;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import type { HookFetchPlugin } from 'hook-fetch';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import hookFetch from 'hook-fetch';
|
||||
import { sseTextDecoderPlugin } from 'hook-fetch/plugins';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
interface BaseResponse {
|
||||
code: number;
|
||||
@ -34,8 +34,9 @@ function jwtPlugin(): HookFetchPlugin<BaseResponse> {
|
||||
return response;
|
||||
}
|
||||
if (response.result?.code === 401) {
|
||||
// 如果没有权限,也不退出,则是弹框提示登录
|
||||
// 如果没有权限,退出,且弹框提示登录
|
||||
userStore.logout();
|
||||
userStore.openLoginDialog();
|
||||
}
|
||||
ElMessage.error(response.result?.msg);
|
||||
return Promise.reject(response);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user