完善错误提示

This commit is contained in:
2025-05-09 09:36:23 +08:00
parent fbc6478496
commit 0665a4e13c
6 changed files with 74 additions and 55 deletions

View File

@@ -1,10 +1,10 @@
## TODO ## TODO
- 总览页 - 总览页
- 个人中心
- 页面图片替换 - 页面图片替换
- 网页标题根据实际页面变化 - 网页标题根据实际页面变化
- 表格页筛选日期,范围筛选需要联动;检查时间范围选择,限定到一定范围内 - 表格页筛选日期,范围筛选需要联动;检查时间范围选择,限定到一定范围内
- 中间件 Limiter
- 购买套餐页的冗余组件 - 购买套餐页的冗余组件
- 确认各个页面操作列的内容 - 确认各个页面操作列的内容
- 提取后刷新提取页套餐可用余量 - 提取后刷新提取页套餐可用余量
@@ -13,16 +13,18 @@
- 后台页面: - 后台页面:
- 提取记录 - 提取记录
- 使用记录 - 使用记录
- 登录流程有问题,在人机验证前不允许提交登录请求
### 下阶段 ### 下阶段
- markdown 文档渲染
- 后台首页改为 grid 布局,需要额外实现用于布局的客户端组件 - 后台首页改为 grid 布局,需要额外实现用于布局的客户端组件
- 检查页面,为后端请求标记 wait 实现防抖机制 - 检查页面,为后端请求标记 wait 实现防抖机制
- 页面切换动效 - 页面切换动效
- 使用 pure js 的包代替 canvas加快编译速度 - 使用 pure js 的包代替 canvas加快编译速度
- 验证码读秒用 store 保存到本地,(全局共享读秒时间) - 验证码读秒用 store 保存到本地,(全局共享读秒时间)
- 将翻页操作反映在路由历史中,可以通过后退返回到上一个翻页状态? - 将翻页操作反映在路由历史中,可以通过后退返回到上一个翻页状态?
-
### 长期 ### 长期
- 检查扩大服务端组件边界 - 检查扩大服务端组件边界

View File

@@ -113,24 +113,17 @@ const _callByUser = cache(async <R = undefined>(
// ====================== // ======================
async function call<R = undefined>(url: string, request: RequestInit): Promise<ApiResponse<R>> { async function call<R = undefined>(url: string, request: RequestInit): Promise<ApiResponse<R>> {
const response = await fetch(url, request) let response: Response
try {
response = await fetch(url, request)
}
catch (e) {
console.error('后端请求失败', url, (e as Error).message)
throw new Error(`请求失败,网络错误`)
}
const type = response.headers.get('Content-Type') ?? 'text/plain' const type = response.headers.get('Content-Type') ?? 'text/plain'
if (type.indexOf('application/json') !== -1) { if (type.indexOf('text/plain') !== -1) {
const json = await response.json()
if (!response.ok) {
console.log('后端请求失败', url, `status=${response.status}`, json)
return {
success: false,
status: response.status,
message: json.message || '请求失败',
}
}
return {
success: true,
data: json,
}
}
else if (type.indexOf('text/plain') !== -1) {
const text = await response.text() const text = await response.text()
if (!response.ok) { if (!response.ok) {
console.log('后端请求失败', url, `status=${response.status}`, text) console.log('后端请求失败', url, `status=${response.status}`, text)
@@ -141,12 +134,30 @@ async function call<R = undefined>(url: string, request: RequestInit): Promise<A
} }
} }
if (!!text?.trim()?.length) {
console.log('未处理的响应成功', `type=text`, `text=${text}`) console.log('未处理的响应成功', `type=text`, `text=${text}`)
}
return { return {
success: true, success: true,
data: undefined as R, // 强转类型,考虑优化 data: undefined as R, // 强转类型,考虑优化
} }
} }
else if (type.indexOf('application/json') !== -1) {
const json = await response.json()
if (!response.ok) {
console.log('后端请求失败', url, `status=${response.status}`, json)
return {
success: false,
status: response.status,
message: json.message || json.error_description || '请求失败' // 业务错误message或者 oauth 错误error_description
}
}
return {
success: true,
data: json,
}
}
throw new Error(`无法解析响应数据,未处理的 Content-Type: ${type}`) throw new Error(`无法解析响应数据,未处理的 Content-Type: ${type}`)
} }
@@ -163,8 +174,7 @@ async function postCall<R = undefined>(rawResp: Promise<ApiResponse<R>>) {
].some(item => item.test(pathname)) ].some(item => item.test(pathname))
if (match && !resp.success && resp.status === 401) { if (match && !resp.success && resp.status === 401) {
console.log('!!!!!!!!!redirect', '"', pathname, '"', resp.message) redirect('/login?force=true')
redirect(pathname === '/' ? '/login' : `/login?redirect=${pathname}`)
} }
return resp return resp

View File

@@ -89,7 +89,9 @@ export default function LoginPage(props: LoginPageProps) {
}) })
} }
catch (e) { catch (e) {
toast.error(`请求失败:${e}`) toast.error('短信发送失败', {
description: (e as Error).message,
})
return false return false
} }
@@ -164,9 +166,7 @@ export default function LoginPage(props: LoginPageProps) {
// 登录失败 // 登录失败
if (!result.success) { if (!result.success) {
return toast.error(result.message, { throw new Error(result.message || '请检查手机号码和验证码是否正确')
description: '请检查您的手机号码和验证码',
})
} }
// 登录成功 // 登录成功
@@ -177,7 +177,7 @@ export default function LoginPage(props: LoginPageProps) {
}) })
} }
catch (e) { catch (e) {
toast.error('登录错误', { toast.error('登录失败', {
description: (e as Error).message, description: (e as Error).message,
}) })
} }

View File

@@ -68,8 +68,6 @@ export default function BillsPage(props: BillsPageProps) {
} }
useEffect(() => { useEffect(() => {
console.log('init bill list')
refresh(1, 10).then()
refresh(1, 10).then() refresh(1, 10).then()
}, []) }, [])

View File

@@ -1,5 +1,6 @@
import {NextRequest, NextResponse} from 'next/server' import {NextRequest, NextResponse} from 'next/server'
import {refreshAuth} from '@/actions/auth' import {refreshAuth} from '@/actions/auth'
import { UnauthorizedError } from './lib/api'
export const config = { export const config = {
matcher: [ matcher: [
@@ -28,15 +29,23 @@ export async function middleware(request: NextRequest) {
console.log('❌ 刷新访问令牌失败', e) console.log('❌ 刷新访问令牌失败', e)
} }
// 如果刷新访问令牌成功,则继续访问之前的页面
const isLogin = request.nextUrl.pathname === '/login'
const redirect = request.nextUrl.searchParams.get('redirect')
if (isLogin && redirect) {
console.log('redirect to', redirect)
return NextResponse.redirect(`${request.nextUrl.origin}${redirect}`)
}
// 没有访问令牌不允许访问 admin 页面 // 没有访问令牌不允许访问 admin 页面
const match = [ const isAdmin = [
RegExp(`^/admin.*`), RegExp(`^/admin.*`),
].some(item => item.test(request.nextUrl.pathname)) ].some(item => item.test(request.nextUrl.pathname))
const accessToken = request.cookies.get('auth_token') const accessToken = request.cookies.get('auth_token')
if (match && !accessToken) { if (isAdmin && !accessToken) {
console.log('redirect!!!!!!!!!') console.log('🚗🚗🚗🚗🚗 非正常重定向 🚗🚗🚗🚗🚗')
return NextResponse.redirect(`${request.nextUrl.origin}/login?redirect=${request.nextUrl.pathname}`) return NextResponse.redirect(`${request.nextUrl.origin}/login?redirect=${request.nextUrl.pathname}`)
} }