feat: 添加Mock版本保护机制 - 基础架构完成
完成内容: ✅ 第一层保护: Git分支隔离 - 创建 v1.0-mock 标签 - 创建 feature/api-integration 分支 ✅ 第二层保护: 配置开关控制 - config/env.config.js (环境配置,支持Mock/API模式切换) ✅ 第三层保护: 代码架构分离 - utils/request.js (网络请求封装,支持Blade-Auth) - utils/dataAdapter.js (核心适配器,自动选择数据源) ✅ Mock数据模块 (4个文件): - mock/index.js (统一入口) - mock/login.js (登录Mock数据) - mock/athlete.js (选手Mock数据,含场地、项目) - mock/score.js (评分Mock数据,含扣分项、详情、修改) ✅ API接口模块 (4个文件): - api/index.js (统一入口) - api/auth.js (认证API,含后端接口规范) - api/athlete.js (选手API,含SQL示例) - api/score.js (评分API,含实现逻辑说明) 特性: - 通过修改 config/env.config.js 的 dataMode 即可切换Mock/API模式 - Mock模式: 完全离线,无需后端,UI功能完整 - API模式: 调用真实后端接口(需后端实现5个专用接口) - 零UI修改: 原有页面代码完全保护,仅替换数据源 下一步: - 修改5个页面使用 dataAdapter - 测试Mock模式功能 - 后端开发5个小程序专用接口 代码统计: - 新增11个文件 - 约1000行代码 - 完整的注释和使用说明
This commit is contained in:
142
api/athlete.js
Normal file
142
api/athlete.js
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* API接口 - 选手模块
|
||||
* 真实后端接口调用(需要后端实现)
|
||||
*/
|
||||
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
/**
|
||||
* 获取我的选手列表(普通评委)
|
||||
* @param {Object} params
|
||||
* @param {String} params.judgeId - 评委ID
|
||||
* @param {String} params.venueId - 场地ID
|
||||
* @param {String} params.projectId - 项目ID
|
||||
* @returns {Promise}
|
||||
*
|
||||
* 注意:此接口需要后端实现
|
||||
* 建议路径: GET /api/mini/athletes
|
||||
*/
|
||||
export function getMyAthletes(params) {
|
||||
return request({
|
||||
url: '/api/mini/athletes',
|
||||
method: 'GET',
|
||||
data: params,
|
||||
showLoading: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选手列表(裁判长)
|
||||
* @param {Object} params
|
||||
* @param {String} params.competitionId - 比赛ID
|
||||
* @param {String} params.venueId - 场地ID
|
||||
* @param {String} params.projectId - 项目ID
|
||||
* @returns {Promise}
|
||||
*
|
||||
* 注意:此接口需要后端实现
|
||||
* 建议路径: GET /api/mini/athletes/admin
|
||||
*/
|
||||
export function getAthletesForAdmin(params) {
|
||||
return request({
|
||||
url: '/api/mini/athletes/admin',
|
||||
method: 'GET',
|
||||
data: params,
|
||||
showLoading: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场地列表
|
||||
* @param {Object} params
|
||||
* @param {String} params.competitionId - 比赛ID
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getVenues(params) {
|
||||
return request({
|
||||
url: '/martial/venue/list',
|
||||
method: 'GET',
|
||||
data: {
|
||||
...params,
|
||||
current: 1,
|
||||
size: 100
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目列表
|
||||
* @param {Object} params
|
||||
* @param {String} params.competitionId - 比赛ID
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getProjects(params) {
|
||||
return request({
|
||||
url: '/martial/project/list',
|
||||
method: 'GET',
|
||||
data: {
|
||||
...params,
|
||||
current: 1,
|
||||
size: 100
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
getMyAthletes,
|
||||
getAthletesForAdmin,
|
||||
getVenues,
|
||||
getProjects
|
||||
}
|
||||
|
||||
/**
|
||||
* 后端接口规范(待实现):
|
||||
*
|
||||
* GET /api/mini/athletes
|
||||
*
|
||||
* 请求参数:
|
||||
* {
|
||||
* "judgeId": "456",
|
||||
* "venueId": "1",
|
||||
* "projectId": "5"
|
||||
* }
|
||||
*
|
||||
* 响应:
|
||||
* {
|
||||
* "code": 200,
|
||||
* "success": true,
|
||||
* "msg": "操作成功",
|
||||
* "data": [
|
||||
* {
|
||||
* "athleteId": "1",
|
||||
* "name": "张三",
|
||||
* "idCard": "123456789000000000",
|
||||
* "team": "少林寺武术大学院",
|
||||
* "number": "123-4567898275",
|
||||
* "myScore": 8.906,
|
||||
* "totalScore": 8.907,
|
||||
* "scored": true,
|
||||
* "scoreTime": "2025-06-25 09:15:00"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* SQL示例:
|
||||
* SELECT
|
||||
* a.id AS athleteId,
|
||||
* a.player_name AS name,
|
||||
* a.id_card AS idCard,
|
||||
* a.team_name AS team,
|
||||
* a.player_no AS number,
|
||||
* a.total_score AS totalScore,
|
||||
* s.score AS myScore,
|
||||
* CASE WHEN s.id IS NOT NULL THEN 1 ELSE 0 END AS scored,
|
||||
* s.score_time AS scoreTime
|
||||
* FROM martial_athlete a
|
||||
* LEFT JOIN martial_score s
|
||||
* ON a.id = s.athlete_id
|
||||
* AND s.judge_id = #{judgeId}
|
||||
* WHERE a.venue_id = #{venueId}
|
||||
* AND a.project_id = #{projectId}
|
||||
* AND a.is_deleted = 0
|
||||
* ORDER BY a.order_num ASC
|
||||
*/
|
||||
85
api/auth.js
Normal file
85
api/auth.js
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* API接口 - 认证模块
|
||||
* 真实后端接口调用(需要后端实现)
|
||||
*/
|
||||
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
/**
|
||||
* 登录验证
|
||||
* @param {Object} data
|
||||
* @param {String} data.matchCode - 比赛编码
|
||||
* @param {String} data.inviteCode - 邀请码
|
||||
* @returns {Promise}
|
||||
*
|
||||
* 注意:此接口需要后端实现
|
||||
* 建议路径: POST /api/mini/login
|
||||
*/
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: '/api/mini/login',
|
||||
method: 'POST',
|
||||
data,
|
||||
showLoading: true,
|
||||
loadingText: '登录中...'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function logout() {
|
||||
return request({
|
||||
url: '/api/mini/logout',
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Token验证
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function verifyToken() {
|
||||
return request({
|
||||
url: '/api/mini/verify',
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
login,
|
||||
logout,
|
||||
verifyToken
|
||||
}
|
||||
|
||||
/**
|
||||
* 后端接口规范(待实现):
|
||||
*
|
||||
* POST /api/mini/login
|
||||
*
|
||||
* 请求:
|
||||
* {
|
||||
* "matchCode": "123",
|
||||
* "inviteCode": "pub"
|
||||
* }
|
||||
*
|
||||
* 响应:
|
||||
* {
|
||||
* "code": 200,
|
||||
* "success": true,
|
||||
* "msg": "登录成功",
|
||||
* "data": {
|
||||
* "token": "xxx",
|
||||
* "userRole": "pub",
|
||||
* "matchId": "123",
|
||||
* "matchName": "2025年全国武术散打锦标赛...",
|
||||
* "matchTime": "2025年6月25日 9:00",
|
||||
* "judgeId": "456",
|
||||
* "judgeName": "欧阳丽娜",
|
||||
* "venueId": "1",
|
||||
* "venueName": "第一场地",
|
||||
* "projects": ["女子组长拳", "男子组陈氏太极拳"]
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
158
api/index.js
Normal file
158
api/index.js
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* API接口中心
|
||||
* 所有API接口的统一入口
|
||||
*
|
||||
* 这个文件汇总了所有业务模块的API接口函数,
|
||||
* 提供给 dataAdapter.js 调用
|
||||
*/
|
||||
|
||||
import authApi from './auth.js'
|
||||
import athleteApi from './athlete.js'
|
||||
import scoreApi from './score.js'
|
||||
|
||||
/**
|
||||
* 导出所有API接口函数
|
||||
*
|
||||
* 资源名称(key)对应 dataAdapter.getData() 的第一个参数
|
||||
* 例如:dataAdapter.getData('login', params) 会调用 authApi.login(params)
|
||||
*/
|
||||
export default {
|
||||
// ==================== 认证模块 ====================
|
||||
/**
|
||||
* 登录验证
|
||||
* @param {Object} data - { matchCode, inviteCode }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
login: authApi.login,
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @returns {Promise}
|
||||
*/
|
||||
logout: authApi.logout,
|
||||
|
||||
/**
|
||||
* Token验证
|
||||
* @returns {Promise}
|
||||
*/
|
||||
verifyToken: authApi.verifyToken,
|
||||
|
||||
// ==================== 选手模块 ====================
|
||||
/**
|
||||
* 获取我的选手列表(普通评委)
|
||||
* @param {Object} params - { judgeId, venueId, projectId }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getMyAthletes: athleteApi.getMyAthletes,
|
||||
|
||||
/**
|
||||
* 获取选手列表(裁判长)
|
||||
* @param {Object} params - { competitionId, venueId, projectId }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getAthletesForAdmin: athleteApi.getAthletesForAdmin,
|
||||
|
||||
/**
|
||||
* 获取场地列表
|
||||
* @param {Object} params - { competitionId }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getVenues: athleteApi.getVenues,
|
||||
|
||||
/**
|
||||
* 获取项目列表
|
||||
* @param {Object} params - { competitionId }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getProjects: athleteApi.getProjects,
|
||||
|
||||
// ==================== 评分模块 ====================
|
||||
/**
|
||||
* 获取扣分项列表
|
||||
* @param {Object} params - { projectId }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getDeductions: scoreApi.getDeductions,
|
||||
|
||||
/**
|
||||
* 提交评分
|
||||
* @param {Object} data - { athleteId, judgeId, score, deductions, note }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
submitScore: scoreApi.submitScore,
|
||||
|
||||
/**
|
||||
* 获取评分详情(裁判长查看)
|
||||
* @param {Object} params - { athleteId }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getScoreDetail: scoreApi.getScoreDetail,
|
||||
|
||||
/**
|
||||
* 修改评分(裁判长)
|
||||
* @param {Object} data - { athleteId, modifierId, modifiedScore, note }
|
||||
* @returns {Promise}
|
||||
*/
|
||||
modifyScore: scoreApi.modifyScore
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用说明:
|
||||
*
|
||||
* 这个文件不直接在页面中使用,而是通过 dataAdapter.js 间接调用。
|
||||
*
|
||||
* 当 config/env.config.js 中 dataMode 设置为 'api' 时,
|
||||
* dataAdapter.getData() 会自动调用这里的API函数。
|
||||
*
|
||||
* 页面使用示例:
|
||||
*
|
||||
* import dataAdapter from '@/utils/dataAdapter.js'
|
||||
*
|
||||
* // 配置 dataMode: 'api' 时,以下代码会调用真实API
|
||||
* const res = await dataAdapter.getData('login', {
|
||||
* matchCode: '123',
|
||||
* inviteCode: 'pub'
|
||||
* })
|
||||
* // 实际调用: authApi.login({ matchCode, inviteCode })
|
||||
* // 请求: POST /api/mini/login
|
||||
*
|
||||
* // 配置 dataMode: 'mock' 时,同样的代码会使用Mock数据
|
||||
* // 实际调用: mockData.login({ matchCode, inviteCode })
|
||||
* // 无网络请求,返回本地Mock数据
|
||||
*/
|
||||
|
||||
/**
|
||||
* 后端开发者注意事项:
|
||||
*
|
||||
* 1. 需要实现的新接口(小程序专用):
|
||||
* - POST /api/mini/login # 登录验证
|
||||
* - GET /api/mini/athletes # 普通评委选手列表
|
||||
* - GET /api/mini/athletes/admin # 裁判长选手列表
|
||||
* - GET /api/mini/score/detail/{athleteId} # 评分详情
|
||||
* - PUT /api/mini/score/modify # 修改评分
|
||||
*
|
||||
* 2. 可以复用的现有接口:
|
||||
* - POST /martial/score/submit # 提交评分
|
||||
* - GET /martial/venue/list # 场地列表
|
||||
* - GET /martial/project/list # 项目列表
|
||||
* - GET /martial/deductionItem/list # 扣分项列表
|
||||
*
|
||||
* 3. 响应格式统一为 BladeX 标准格式:
|
||||
* {
|
||||
* "code": 200,
|
||||
* "success": true,
|
||||
* "msg": "操作成功",
|
||||
* "data": { ... }
|
||||
* }
|
||||
*
|
||||
* 4. 请求头要求:
|
||||
* - Content-Type: application/json
|
||||
* - Blade-Auth: Bearer {token}
|
||||
*
|
||||
* 5. 建议创建专门的Controller:
|
||||
* @RestController
|
||||
* @RequestMapping("/api/mini")
|
||||
* public class MartialMiniController {
|
||||
* // 实现上述5个专用接口
|
||||
* }
|
||||
*/
|
||||
165
api/score.js
Normal file
165
api/score.js
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* API接口 - 评分模块
|
||||
* 真实后端接口调用(需要后端实现)
|
||||
*/
|
||||
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
/**
|
||||
* 获取扣分项列表
|
||||
* @param {Object} params
|
||||
* @param {String} params.projectId - 项目ID
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getDeductions(params) {
|
||||
return request({
|
||||
url: '/martial/deductionItem/list',
|
||||
method: 'GET',
|
||||
data: {
|
||||
...params,
|
||||
current: 1,
|
||||
size: 100
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交评分
|
||||
* @param {Object} data
|
||||
* @param {String} data.athleteId - 选手ID
|
||||
* @param {String} data.judgeId - 评委ID
|
||||
* @param {Number} data.score - 评分
|
||||
* @param {Array} data.deductions - 扣分项
|
||||
* @param {String} data.note - 备注
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function submitScore(data) {
|
||||
return request({
|
||||
url: '/martial/score/submit',
|
||||
method: 'POST',
|
||||
data,
|
||||
showLoading: true,
|
||||
loadingText: '提交中...'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取评分详情(裁判长查看)
|
||||
* @param {Object} params
|
||||
* @param {String} params.athleteId - 选手ID
|
||||
* @returns {Promise}
|
||||
*
|
||||
* 注意:此接口需要后端实现
|
||||
* 建议路径: GET /api/mini/score/detail/{athleteId}
|
||||
*/
|
||||
export function getScoreDetail(params) {
|
||||
return request({
|
||||
url: `/api/mini/score/detail/${params.athleteId}`,
|
||||
method: 'GET',
|
||||
showLoading: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改评分(裁判长)
|
||||
* @param {Object} data
|
||||
* @param {String} data.athleteId - 选手ID
|
||||
* @param {String} data.modifierId - 修改人ID
|
||||
* @param {Number} data.modifiedScore - 修改后的分数
|
||||
* @param {String} data.note - 修改原因
|
||||
* @returns {Promise}
|
||||
*
|
||||
* 注意:此接口需要后端实现
|
||||
* 建议路径: PUT /api/mini/score/modify
|
||||
*/
|
||||
export function modifyScore(data) {
|
||||
return request({
|
||||
url: '/api/mini/score/modify',
|
||||
method: 'PUT',
|
||||
data,
|
||||
showLoading: true,
|
||||
loadingText: '修改中...'
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
getDeductions,
|
||||
submitScore,
|
||||
getScoreDetail,
|
||||
modifyScore
|
||||
}
|
||||
|
||||
/**
|
||||
* 后端接口规范(待实现):
|
||||
*
|
||||
* 1. GET /api/mini/score/detail/{athleteId}
|
||||
*
|
||||
* 响应:
|
||||
* {
|
||||
* "code": 200,
|
||||
* "success": true,
|
||||
* "msg": "操作成功",
|
||||
* "data": {
|
||||
* "athleteInfo": {
|
||||
* "athleteId": "1",
|
||||
* "name": "张三",
|
||||
* "idCard": "123456789000000000",
|
||||
* "team": "少林寺武术大学院",
|
||||
* "number": "123-4567898275",
|
||||
* "totalScore": 8.907
|
||||
* },
|
||||
* "judgeScores": [
|
||||
* {
|
||||
* "judgeId": "1",
|
||||
* "judgeName": "欧阳丽娜",
|
||||
* "score": 8.907,
|
||||
* "scoreTime": "2025-06-25 09:15:00",
|
||||
* "note": ""
|
||||
* }
|
||||
* ],
|
||||
* "modification": null
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* SQL示例:
|
||||
* SELECT
|
||||
* s.judge_id AS judgeId,
|
||||
* s.judge_name AS judgeName,
|
||||
* s.score,
|
||||
* s.score_time AS scoreTime,
|
||||
* s.note
|
||||
* FROM martial_score s
|
||||
* WHERE s.athlete_id = #{athleteId}
|
||||
* ORDER BY s.score_time ASC
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* 2. PUT /api/mini/score/modify
|
||||
*
|
||||
* 请求:
|
||||
* {
|
||||
* "athleteId": "1",
|
||||
* "modifierId": "789",
|
||||
* "modifiedScore": 8.910,
|
||||
* "note": "修改原因"
|
||||
* }
|
||||
*
|
||||
* 响应:
|
||||
* {
|
||||
* "code": 200,
|
||||
* "success": true,
|
||||
* "msg": "修改成功",
|
||||
* "data": {
|
||||
* "athleteId": "1",
|
||||
* "originalScore": 8.907,
|
||||
* "modifiedScore": 8.910,
|
||||
* "modifyTime": "2025-06-25 10:00:00"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* 实现逻辑:
|
||||
* 1. 验证权限(只有裁判长可以修改)
|
||||
* 2. 保存 originalScore(如果是第一次修改)
|
||||
* 3. 更新 totalScore
|
||||
* 4. 记录 modifyReason 和 modifyTime
|
||||
*/
|
||||
Reference in New Issue
Block a user