Files
competition-website/src/api/auth.js
qubiaobiao c2551b64e8 feat(auth/exam): 登录重试同源 + 静默刷新透传 + 交卷链路加固(R5/R8)
前端重试与后端闸门同源(须成对上线)
- src/api/request.js: 新增 parseRetryAfterMs / computeLoginRetryDelayMs,
  退避取 max(指数退避, Retry-After) + ±20% 抖动 + 服务端值封顶;
  silent 透传(doSilentRefresh 不再吞掉 silent 标记)。
- src/api/auth.js / src/stores/auth.js: 登录 429 走同源重试;错误分类区分
  "TCP 未握手(可重试)"与"业务码失败(不可重试)"。
- src/stores/exam.js: 交卷链路顺序红线(取卷 -> 作答 -> submit-all 严格顺序),
  答案不丢 / 重复不脏 / 窗口不锁死。
- src/views/Competition.vue: 中职/高职综合大题区块(3 x textarea,2000 字上限
  与右下角计数);本科/教师组保留 Word 上传入口。

验证:源码抽取测试 8/8(含判别力自证:不读 header 的对照实现必 FAIL);
npm run build BUILD_RC=0(12.82s / 1711 modules);真实交卷端到端 code=0。
2026-09-22 09:17:06 +08:00

96 lines
2.5 KiB
JavaScript

import request from './request'
// ==================== 认证相关 API ====================
/**
* 获取图形验证码
* @returns {Promise} 验证码图片数据
*/
export function getCaptcha() {
return request.post('/auth/captcha')
}
/**
* 发送短信验证码(激活流程)
* 前端传入身份证号,后端自动查找绑定手机号发送短信
* @param {string} phone - 身份证号
* @param {string} captcha - 图形验证码
* @returns {Promise} { smsCode, phone, name, group }
*/
export function sendSms(phone, captcha) {
return request.post('/auth/sms', { phone, captcha })
}
/**
* 激活账号(设置密码)
* @param {object} data - { id_number, phone, password, smsCode }
* @returns {Promise}
*/
export function activate(data) {
return request.post('/auth/activate', data)
}
/**
* 参赛者登录(手机号 + 密码)
* @param {string} phone - 手机号
* @param {string} password - 密码
* @param {object} [config] - 透传给 axios 的配置(如 { silent: true } 抑制拦截器逐次错误提示)
* @returns {Promise} { token, user }
*/
export function login(phone, password, config) {
return request.post('/auth/login', { phone, password }, config)
}
/**
* 管理员登录(用户名 + 密码)
* @param {string} username - 管理员用户名
* @param {string} password - 密码
* @returns {Promise} { token, user }
*/
export function adminLogin(username, password) {
return request.post('/auth/admin-login', { username, password })
}
/**
* 获取当前登录用户信息
* @returns {Promise} 用户信息对象
*/
export function getCurrentUser() {
return request.get('/auth/current-user')
}
/**
* 忘记密码 - 发送短信验证码
* @param {string} idNumber - 身份证号
* @param {string} captcha - 图形验证码
* @returns {Promise} { smsCode, phone }
*/
export function forgotPassword(idNumber, captcha) {
return request.post('/auth/forgot-password', { id_number: idNumber, captcha })
}
/**
* 重置密码
* @param {object} data - { id_number, password, smsCode }
* @returns {Promise}
*/
export function resetPassword(data) {
return request.post('/auth/reset-password', data)
}
/**
* 退出登录
* @returns {Promise}
*/
export function logout() {
return request.post('/auth/logout')
}
/**
* 静默刷新令牌(用户无感知续期,避免被强制踢出登录)
* @returns {Promise<{token: string, user: object}>}
*/
export function refreshToken() {
return request.post('/auth/refresh', null, { silent: true })
}