feat(doc): 添加用户信息接口并配置前端代理

- 在后端添加用户信息接口 GetUserInfo
- 在前端配置 Vite 代理,支持后端接口访问
- 更新 VuePress 配置,添加客户端配置文件
- 调整导航栏布局,增加用户信息组件
This commit is contained in:
高手 2025-02-16 14:13:46 +08:00
parent b5788cd8b5
commit 43a2f31eda
10 changed files with 470 additions and 13 deletions

5
.gitignore vendored
View File

@ -2,7 +2,10 @@ node_modules/
doc/src/.vuepress/.cache/
doc/src/.vuepress/.temp/
doc/src/.vuepress/dist/
gateway/static/
.DS_Store
*.db
log/
# 忽略 static 文件夹
gateway/static/*
# 如果需要保留 static 文件夹本身,可以添加以下规则
!gateway/static/.gitkeep

View File

@ -17,5 +17,9 @@
"vuepress": "2.0.0-rc.19",
"vuepress-theme-hope": "2.0.0-rc.71"
},
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee"
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
"dependencies": {
"vuepress/client": "2.0.0-rc.19",
"axios": "^1.7.9"
}
}

234
doc/pnpm-lock.yaml generated
View File

@ -7,6 +7,13 @@ settings:
importers:
.:
dependencies:
'vuepress/client':
specifier: 2.0.0-rc.19
version: 2.0.0-rc.19
axios:
specifier: ^1.7.9
version: 1.7.9
devDependencies:
'@vuepress/bundler-vite':
specifier: 2.0.0-rc.19
@ -820,12 +827,21 @@ packages:
'@vue/devtools-api@7.7.1':
resolution: {integrity: sha512-Cexc8GimowoDkJ6eNelOPdYIzsu2mgNyp0scOQ3tiaYSb9iok6LOESSsJvHaI+ib3joRfqRJNLkHFjhNuWA5dg==}
'@vue/devtools-api@7.7.2':
resolution: {integrity: sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==}
'@vue/devtools-kit@7.7.1':
resolution: {integrity: sha512-yhZ4NPnK/tmxGtLNQxmll90jIIXdb2jAhPF76anvn5M/UkZCiLJy28bYgPIACKZ7FCosyKoaope89/RsFJll1w==}
'@vue/devtools-kit@7.7.2':
resolution: {integrity: sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==}
'@vue/devtools-shared@7.7.1':
resolution: {integrity: sha512-BtgF7kHq4BHG23Lezc/3W2UhK2ga7a8ohAIAGJMBr4BkxUFzhqntQtCiuL1ijo2ztWnmusymkirgqUrXoQKumA==}
'@vue/devtools-shared@7.7.2':
resolution: {integrity: sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==}
'@vue/reactivity@3.5.13':
resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==}
@ -853,7 +869,7 @@ packages:
resolution: {integrity: sha512-QFicPNIj3RZAJbHoLbeYlPJsPchnQLGuw0n8xv0eeUi9ejEXO1huWA8sLoPbTGdiDW+PHr1MHnaVMkyUfwaKcQ==}
hasBin: true
'@vuepress/client@2.0.0-rc.19':
'vuepress/client@2.0.0-rc.19':
resolution: {integrity: sha512-vUAU6n4qmtXqthxkb4LHq0D+VWSDenwBDf0jUs7RaBLuOVrbPtmH/hs4k1vLIlGdwC3Zs/G6tlB4UmuZiiwR8Q==}
'@vuepress/core@2.0.0-rc.19':
@ -1084,6 +1100,9 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
autoprefixer@10.4.20:
resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
engines: {node: ^10 || ^12 || >=14}
@ -1091,6 +1110,9 @@ packages:
peerDependencies:
postcss: ^8.1.0
axios@1.7.9:
resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
balloon-css@1.2.0:
resolution: {integrity: sha512-urXwkHgwp6GsXVF+it01485Z2Cj4pnW02ICnM0TemOlkKmCNnDLmyy+ZZiRXBpwldUXO+aRNr7Hdia4CBvXJ5A==}
@ -1124,6 +1146,10 @@ packages:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
camelcase@5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
engines: {node: '>=6'}
@ -1180,6 +1206,10 @@ packages:
colorjs.io@0.5.2:
resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
@ -1229,6 +1259,10 @@ packages:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
@ -1252,6 +1286,10 @@ packages:
domutils@3.2.2:
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
electron-to-chromium@1.5.95:
resolution: {integrity: sha512-XNsZaQrgQX+BG37BRQv+E+HcOZlWhqYaDoVVNCws/WrYYdbGrkR1qCDJ2mviBF3flCs6/BTa4O7ANfFTFZk6Dg==}
@ -1276,6 +1314,22 @@ packages:
engines: {node: '>=4'}
hasBin: true
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
@ -1328,6 +1382,19 @@ packages:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
form-data@4.0.2:
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
engines: {node: '>= 6'}
fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
@ -1340,6 +1407,9 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
@ -1348,6 +1418,14 @@ packages:
resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
engines: {node: '>=18'}
get-intrinsic@1.2.7:
resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
get-stream@9.0.1:
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
engines: {node: '>=18'}
@ -1363,6 +1441,10 @@ packages:
resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==}
engines: {node: '>=18'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@ -1374,9 +1456,21 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hash-sum@2.0.0:
resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
hast-util-to-html@9.0.4:
resolution: {integrity: sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==}
@ -1513,6 +1607,10 @@ packages:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
hasBin: true
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
mdast-util-to-hast@13.2.0:
resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
@ -1542,6 +1640,14 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
mimic-function@5.0.1:
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
engines: {node: '>=18'}
@ -1682,6 +1788,9 @@ packages:
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
@ -2861,6 +2970,10 @@ snapshots:
dependencies:
'@vue/devtools-kit': 7.7.1
'@vue/devtools-api@7.7.2':
dependencies:
'@vue/devtools-kit': 7.7.2
'@vue/devtools-kit@7.7.1':
dependencies:
'@vue/devtools-shared': 7.7.1
@ -2871,10 +2984,24 @@ snapshots:
speakingurl: 14.0.1
superjson: 2.2.2
'@vue/devtools-kit@7.7.2':
dependencies:
'@vue/devtools-shared': 7.7.2
birpc: 0.2.19
hookable: 5.5.3
mitt: 3.0.1
perfect-debounce: 1.0.0
speakingurl: 14.0.1
superjson: 2.2.2
'@vue/devtools-shared@7.7.1':
dependencies:
rfdc: 1.4.1
'@vue/devtools-shared@7.7.2':
dependencies:
rfdc: 1.4.1
'@vue/reactivity@3.5.13':
dependencies:
'@vue/shared': 3.5.13
@ -2903,7 +3030,7 @@ snapshots:
dependencies:
'@vitejs/plugin-vue': 5.2.1(vite@6.0.11(@types/node@22.13.1)(sass-embedded@1.83.4))(vue@3.5.13)
'@vuepress/bundlerutils': 2.0.0-rc.19
'@vuepress/client': 2.0.0-rc.19
'vuepress/client': 2.0.0-rc.19
'@vuepress/core': 2.0.0-rc.19
'@vuepress/shared': 2.0.0-rc.19
'@vuepress/utils': 2.0.0-rc.19
@ -2932,7 +3059,7 @@ snapshots:
'@vuepress/bundlerutils@2.0.0-rc.19':
dependencies:
'@vuepress/client': 2.0.0-rc.19
'vuepress/client': 2.0.0-rc.19
'@vuepress/core': 2.0.0-rc.19
'@vuepress/shared': 2.0.0-rc.19
'@vuepress/utils': 2.0.0-rc.19
@ -2955,9 +3082,9 @@ snapshots:
- supports-color
- typescript
'@vuepress/client@2.0.0-rc.19':
'vuepress/client@2.0.0-rc.19':
dependencies:
'@vue/devtools-api': 7.7.1
'@vue/devtools-api': 7.7.2
'@vuepress/shared': 2.0.0-rc.19
vue: 3.5.13
vue-router: 4.5.0(vue@3.5.13)
@ -2966,7 +3093,7 @@ snapshots:
'@vuepress/core@2.0.0-rc.19':
dependencies:
'@vuepress/client': 2.0.0-rc.19
'vuepress/client': 2.0.0-rc.19
'@vuepress/markdown': 2.0.0-rc.19
'@vuepress/shared': 2.0.0-rc.19
'@vuepress/utils': 2.0.0-rc.19
@ -3345,6 +3472,8 @@ snapshots:
argparse@2.0.1: {}
asynckit@0.4.0: {}
autoprefixer@10.4.20(postcss@8.5.1):
dependencies:
browserslist: 4.24.4
@ -3355,6 +3484,14 @@ snapshots:
postcss: 8.5.1
postcss-value-parser: 4.2.0
axios@1.7.9:
dependencies:
follow-redirects: 1.15.9
form-data: 4.0.2
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
balloon-css@1.2.0: {}
bcrypt-ts@5.0.3: {}
@ -3380,6 +3517,11 @@ snapshots:
cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
camelcase@5.3.1: {}
caniuse-lite@1.0.30001697: {}
@ -3451,6 +3593,10 @@ snapshots:
colorjs.io@0.5.2: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
comma-separated-tokens@2.0.3: {}
commander@13.1.0: {}
@ -3489,6 +3635,8 @@ snapshots:
decamelize@1.2.0: {}
delayed-stream@1.0.0: {}
dequal@2.0.3: {}
devlop@1.1.0:
@ -3515,6 +3663,12 @@ snapshots:
domelementtype: 2.3.0
domhandler: 5.0.3
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
electron-to-chromium@1.5.95: {}
emoji-regex-xs@1.0.0: {}
@ -3532,6 +3686,21 @@ snapshots:
envinfo@7.14.0: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.2.7
has-tostringtag: 1.0.2
hasown: 2.0.2
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@ -3638,6 +3807,15 @@ snapshots:
locate-path: 5.0.0
path-exists: 4.0.0
follow-redirects@1.15.9: {}
form-data@4.0.2:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
mime-types: 2.1.35
fraction.js@4.3.7: {}
fs-extra@11.3.0:
@ -3649,10 +3827,30 @@ snapshots:
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {}
get-caller-file@2.0.5: {}
get-east-asian-width@1.3.0: {}
get-intrinsic@1.2.7:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
get-stream@9.0.1:
dependencies:
'@sec-ant/readable-stream': 0.4.1
@ -3675,6 +3873,8 @@ snapshots:
slash: 5.1.0
unicorn-magic: 0.1.0
gopd@1.2.0: {}
graceful-fs@4.2.11: {}
gray-matter@4.0.3:
@ -3686,8 +3886,18 @@ snapshots:
has-flag@4.0.0: {}
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hash-sum@2.0.0: {}
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
hast-util-to-html@9.0.4:
dependencies:
'@types/hast': 3.0.4
@ -3825,6 +4035,8 @@ snapshots:
punycode.js: 2.3.1
uc.micro: 2.1.0
math-intrinsics@1.1.0: {}
mdast-util-to-hast@13.2.0:
dependencies:
'@types/hast': 3.0.4
@ -3863,6 +4075,12 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.1
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
mimic-function@5.0.1: {}
mitt@3.0.1: {}
@ -3973,6 +4191,8 @@ snapshots:
property-information@6.5.0: {}
proxy-from-env@1.1.0: {}
punycode.js@2.3.1: {}
qrcode@1.5.4:
@ -4437,7 +4657,7 @@ snapshots:
vuepress@2.0.0-rc.19(@vuepress/bundler-vite@2.0.0-rc.19(@types/node@22.13.1)(sass-embedded@1.83.4))(vue@3.5.13):
dependencies:
'@vuepress/cli': 2.0.0-rc.19
'@vuepress/client': 2.0.0-rc.19
'vuepress/client': 2.0.0-rc.19
'@vuepress/core': 2.0.0-rc.19
'@vuepress/markdown': 2.0.0-rc.19
'@vuepress/shared': 2.0.0-rc.19

View File

@ -0,0 +1,11 @@
import { defineClientConfig } from "@vuepress/client";
import UserInfo from "./components/UserInfo.vue";
export default defineClientConfig({
enhance({ app, router }) {
app.component("UserInfo", UserInfo);
},
setup() {
// 这里可以添加全局的设置
},
});

View File

@ -0,0 +1,165 @@
<template>
<div class="user-info-container" v-if="userInfo">
<div class="user-icon" @click="togglePopup">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="user-avatar">
<path fill="currentColor" d="M12 4a4 4 0 0 1 4 4a4 4 0 0 1-4 4a4 4 0 0 1-4-4a4 4 0 0 1 4-4m0 10c4.42 0 8 1.79 8 4v2H4v-2c0-2.21 3.58-4 8-4"/>
</svg>
</div>
<Teleport to="body">
<div class="popup" v-if="showPopup" ref="popupRef">
<div class="popup-content">
<div class="user-details">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="user-avatar">
<path fill="currentColor" d="M12 4a4 4 0 0 1 4 4a4 4 0 0 1-4 4a4 4 0 0 1-4-4a4 4 0 0 1 4-4m0 10c4.42 0 8 1.79 8 4v2H4v-2c0-2.21 3.58-4 8-4"/>
</svg>
<span class="fullname">{{ userInfo.fullName }}</span>
</div>
<a href="/logout" class="logout-btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="logout-icon">
<path fill="currentColor" d="M16 17v-3H9v-4h7V7l5 5l-5 5M14 2a2 2 0 0 1 2 2v2h-2V4H5v16h9v-2h2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9Z"/>
</svg>
退出登录
</a>
</div>
</div>
</Teleport>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
const userInfo = ref(null)
const showPopup = ref(false)
const popupRef = ref(null)
const togglePopup = () => {
showPopup.value = !showPopup.value
}
const handleClickOutside = (event: MouseEvent) => {
if (popupRef.value && !popupRef.value.contains(event.target) &&
!(event.target as HTMLElement).closest('.user-icon')) {
showPopup.value = false
}
}
onMounted(async () => {
try {
const response = await fetch('/api/user/info')
if (response.ok) {
userInfo.value = await response.json()
}
} catch (error) {
console.error('获取用户信息失败:', error)
}
document.addEventListener('click', handleClickOutside)
})
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside)
})
</script>
<style scoped>
.user-info-container {
position: relative;
}
.user-icon {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--c-brand);
/* color: white; */
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.2s;
padding: 6px;
}
.icon {
width: 20px;
height: 20px;
}
.user-icon:hover {
background: var(--c-brand-light);
}
.popup {
position: fixed;
top: 50px;
right: 20px;
background: var(--c-bg);
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
padding: 1rem;
min-width: 200px;
z-index: 1000;
}
.popup::before {
content: '';
position: absolute;
top: -6px;
right: 10px;
width: 12px;
height: 12px;
background: var(--c-bg);
transform: rotate(45deg);
box-shadow: -2px -2px 5px rgba(0, 0, 0, 0.04);
}
.popup-content {
display: flex;
flex-direction: column;
gap: 1rem;
position: relative;
z-index: 1;
}
.user-details {
display: flex;
align-items: center;
gap: 0.8rem;
padding-bottom: 0.8rem;
border-bottom: 1px solid var(--c-border);
}
.user-avatar {
width: 24px;
height: 24px;
color: var(--c-text-lighter);
}
.logout-icon {
width: 18px;
height: 18px;
}
.fullname {
font-size: 0.9rem;
color: var(--c-text);
}
.logout-btn {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
border-radius: 4px;
color: var(--c-text);
text-decoration: none;
transition: all 0.2s;
}
.logout-btn:hover {
background: var(--c-brand-light);
color: white;
}
</style>

View File

@ -1,4 +1,7 @@
import { defineUserConfig } from "vuepress";
import { getDirname, path } from 'vuepress/utils'
import { viteBundler } from "@vuepress/bundler-vite"
const __dirname = getDirname(import.meta.url)
import theme from "./theme.js";
@ -11,6 +14,24 @@ export default defineUserConfig({
theme,
// 添加客户端配置
clientConfigFile: path.resolve(__dirname, './client.ts'),
// 配置 Vite
bundler: viteBundler({
viteOptions: {
server: {
proxy: {
'/api': {
target: 'http://localhost:7070',
changeOrigin: true,
// rewrite: path => path.replace(/^\/api/, '') // 如果你的后端接口不需要 /api 前缀,可以启用这行
}
}
}
}
}),
// 和 PWA 一起启用
// shouldPrefetch: false,
});

View File

@ -1,8 +1,10 @@
import { hopeTheme } from "vuepress-theme-hope";
import UserInfo from "./components/UserInfo.vue";
import navbar from "./navbar.js";
import sidebar from "./sidebar.js";
export default hopeTheme({
// hostname: "https://vuepress-theme-hope-docs-demo.netlify.app",
@ -19,12 +21,15 @@ export default hopeTheme({
// 导航栏
navbar,
navbarLayout: {
start: ["Brand"],
center: ["Links"],
end: [ "Outlook", "UserInfo"],
},
// 侧边栏
sidebar,
// 页脚
// footer: "默认页脚",
displayFooter: true,
// 加密配置
@ -129,7 +134,7 @@ export default hopeTheme({
// },
components: {
components: ["Badge", "VPCard","PDF"],
components: ["Badge", "VPCard", "PDF"],
},
icon: {

View File

@ -16,5 +16,6 @@ actions:
type: primary
---
<Catalog />

View File

@ -180,3 +180,27 @@ func handleRegisterError(c *gin.Context, db *gorm.DB, errorMessage string) {
},
})
}
func GetUserInfo(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
session := sessions.Default(c)
userID := session.Get("user")
if userID == nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"})
return
}
var user models.User
if err := db.First(&user, userID).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取用户信息失败"})
return
}
c.JSON(http.StatusOK, gin.H{
"id": user.ID,
"fullName": user.FullName,
"mobile": user.Mobile,
})
}
}

View File

@ -42,10 +42,13 @@ func main() {
r.POST("/login", handlers.PostLogin(db))
r.GET("/register", handlers.GetRegister(db))
r.POST("/register", handlers.PostRegister(db))
r.GET("/api/user/info", handlers.GetUserInfo(db))
// 权限校验中间件
r.Use(middleware.AuthRequired())
// 添加用户信息API
// 文档页面路由
r.GET("/", handlers.ServeIndex(db))