本次更新实现了基于用户类型的论述题访问权限控制,并为论述题添加了专门的AI评分功能。 后端更新: - 添加论述题权限验证:根据用户类型(ordinary-person/management-person)控制不同论述题的访问权限 - 新增 GradeEssay 方法:为论述题提供专门的AI评分,不依赖标准答案,基于保密法规进行专业评分 - 优化AI评分提示词:增加法规依据要求,返回参考答案、评分依据等更详细的评分信息 - 添加用户类型管理:新增 UpdateUserType API,支持用户更新个人类型 - 路由调整:将练习题相关API移至需要认证的路由组 前端更新: - 论述题答题界面优化:不显示标准答案,展示AI评分的参考答案和评分依据 - 用户类型选择:登录/注册时支持选择用户类型 - 权限控制适配:根据用户类型显示对应的论述题列表 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
128 lines
3.3 KiB
TypeScript
128 lines
3.3 KiB
TypeScript
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||
|
||
// 创建 axios 实例
|
||
const instance: AxiosInstance = axios.create({
|
||
baseURL: '/api', // 通过 Vite 代理转发到 Go 后端
|
||
timeout: 10000,
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
})
|
||
|
||
// 请求拦截器
|
||
instance.interceptors.request.use(
|
||
(config) => {
|
||
// 可以在这里添加 token 等认证信息
|
||
const token = localStorage.getItem('token')
|
||
if (token && config.headers) {
|
||
config.headers.Authorization = `Bearer ${token}`
|
||
}
|
||
return config
|
||
},
|
||
(error) => {
|
||
return Promise.reject(error)
|
||
}
|
||
)
|
||
|
||
// 响应拦截器
|
||
instance.interceptors.response.use(
|
||
(response: AxiosResponse) => {
|
||
return response.data
|
||
},
|
||
(error) => {
|
||
// 统一错误处理
|
||
if (error.response) {
|
||
switch (error.response.status) {
|
||
case 401:
|
||
// 未授权,清除本地存储并跳转到登录页
|
||
console.error('Token已过期或未授权,请重新登录')
|
||
localStorage.removeItem('token')
|
||
localStorage.removeItem('user')
|
||
// 跳转到登录页
|
||
window.location.href = '/login'
|
||
break
|
||
case 403:
|
||
console.error('没有权限访问')
|
||
break
|
||
case 404:
|
||
console.error('请求的资源不存在')
|
||
break
|
||
case 500:
|
||
console.error('服务器错误')
|
||
break
|
||
default:
|
||
console.error('请求失败:', error.response.data)
|
||
}
|
||
} else {
|
||
console.error('网络错误:', error.message)
|
||
}
|
||
return Promise.reject(error)
|
||
}
|
||
)
|
||
|
||
// 封装请求方法
|
||
export const request = {
|
||
get: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.get(url, config)
|
||
},
|
||
post: <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.post(url, data, config)
|
||
},
|
||
put: <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.put(url, data, config)
|
||
},
|
||
delete: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.delete(url, config)
|
||
},
|
||
}
|
||
|
||
// 统一的 fetch 请求工具(用于需要原生 fetch 的场景,如流式请求)
|
||
interface FetchOptions extends RequestInit {
|
||
// 扩展选项(如果需要)
|
||
}
|
||
|
||
/**
|
||
* 统一封装的 fetch 请求方法
|
||
* 自动添加 Authorization header 和其他通用配置
|
||
*/
|
||
export const fetchWithAuth = async (
|
||
url: string,
|
||
options: FetchOptions = {}
|
||
): Promise<Response> => {
|
||
// 获取 token
|
||
const token = localStorage.getItem('token')
|
||
|
||
// 合并 headers
|
||
const headers: HeadersInit = {
|
||
'Content-Type': 'application/json',
|
||
...options.headers,
|
||
}
|
||
|
||
// 如果有 token,添加到请求头
|
||
if (token) {
|
||
headers['Authorization'] = `Bearer ${token}`
|
||
}
|
||
|
||
// 构建完整的请求配置
|
||
const fetchOptions: RequestInit = {
|
||
...options,
|
||
headers,
|
||
}
|
||
|
||
// 发送请求
|
||
const response = await fetch(url, fetchOptions)
|
||
|
||
// 统一处理 401 未授权错误
|
||
if (response.status === 401) {
|
||
console.error('Token已过期或未授权,请重新登录')
|
||
localStorage.removeItem('token')
|
||
localStorage.removeItem('user')
|
||
window.location.href = '/login'
|
||
throw new Error('未授权,请重新登录')
|
||
}
|
||
|
||
return response
|
||
}
|
||
|
||
export default instance
|