更新上号系统需求文档,添加版本信息、项目概述、角色与权限、术语与规则及业务流程等内容,同时修改链接生成规则和请求拦截器以支持公开API的身份验证,新增路由配置以支持上号任务页面。

This commit is contained in:
zyh
2025-08-26 20:35:58 +08:00
parent 7854bd0288
commit 41739f32a1
7 changed files with 1670 additions and 24 deletions

47
src/api/play.js Normal file
View File

@@ -0,0 +1,47 @@
import http from '@/plugins/http'
/**
* 用户端游戏页面 API
*/
// 获取链接状态
export function getLinkStatus(code) {
return http.get('/api/link/status', {
params: { code }
})
}
// 选择区域
export function selectRegion(payload) {
// payload: { code: string, region: string }
return http.post('/api/link/select-region', payload)
}
// 刷新链接
export function refreshLink(code) {
return http.post('/api/link/refresh', {
code
})
}
// 轮询登录状态
export function pollLoginStatus(code) {
return http.get('/api/link/poll-login', {
params: { code }
})
}
// 获取游戏进度
export function getGameProgress(code) {
return http.get('/api/link/progress', {
params: { code }
})
}
// 获取二维码图片(可选,用于代理二维码避免混合内容问题)
export function getQRCode(code) {
return http.get('/api/link/qr.png', {
params: { code },
responseType: 'blob'
})
}

View File

@@ -3,7 +3,7 @@
// 链接地址生成规则
export const LINK_CONFIG = {
// 基础域名
BASE_URL: 'https://yourdomain.com',
BASE_URL: 'http://localhost:5173',
// 游戏页面路径
GAME_PATH: '/play',

View File

@@ -27,11 +27,22 @@ function onRefreshed(newToken, tokenType) {
// 请求拦截:附加 Authorization
http.interceptors.request.use(
(config) => {
const token = getAccessToken()
const type = getTokenType()
if (token) {
config.headers = config.headers || {}
config.headers.Authorization = `${type} ${token}`
// 跳过公开API的身份验证只跳过用户端游戏相关的公开接口
const publicAPIs = [
'/api/link/status',
'/api/link/select-region',
'/api/link/poll-login',
'/api/link/progress'
]
const isPublicAPI = publicAPIs.some(api => config.url?.includes(api))
if (!isPublicAPI) {
const token = getAccessToken()
const type = getTokenType()
if (token) {
config.headers = config.headers || {}
config.headers.Authorization = `${type} ${token}`
}
}
return config
},
@@ -58,10 +69,17 @@ http.interceptors.response.use(
const status = response?.status
const url = config?.url || ''
// 避免对登录/刷新自身进行重复刷新
// 避免对登录/刷新自身和公开API进行重复刷新
const isAuthPath = /\/auth\/(login|refresh)/.test(url || '')
const publicAPIs = [
'/api/link/status',
'/api/link/select-region',
'/api/link/poll-login',
'/api/link/progress'
]
const isPublicAPI = publicAPIs.some(api => url?.includes(api))
if (status === 401 && !isAuthPath) {
if (status === 401 && !isAuthPath && !isPublicAPI) {
if (!isRefreshing) {
isRefreshing = true
try {

View File

@@ -14,10 +14,12 @@ const Settings = () => import('@/views/settings/Settings.vue')
const LinkGenerate = () => import('@/views/links/LinkGenerate.vue')
const ErrorTest = () => import('@/views/ErrorTest.vue')
const PermissionTest = () => import('@/views/PermissionTest.vue')
const Play = () => import('@/views/Play.vue')
const NotFound = () => import('@/views/NotFound.vue')
export const routes = [
{ path: '/login', name: 'Login', component: Login, meta: { public: true, title: '登录' } },
{ path: '/play', name: 'Play', component: Play, meta: { public: true, title: '上号任务' } },
{
path: '/',
component: AdminLayout,

1171
src/views/Play.vue Normal file

File diff suppressed because it is too large Load Diff