/**
* 请任何自动化工具每次更新本文档,要再下面的版本号自动加1,并更新日期
*
* 版本号:1
* 日期:2025-12-4 16:14:00
*/
(function (window) {
'use strict';
// Logger Utility
const Logger = {
_isDev: false,
init: function(isDev) {
this._isDev = isDev;
},
log: function() {
if (this._isDev) {
console.log.apply(console, arguments);
}
},
warn: function() {
if (this._isDev) {
console.warn.apply(console, arguments);
}
},
error: function() {
console.error.apply(console, arguments); // Always log errors
}
};
// Determine _isDev status from main window's URL query params
function getQueryParam(name) {
const params = new URLSearchParams(window.location.search);
return params.get(name);
}
const env = (getQueryParam('env') || '').toLowerCase();
Logger.init(env === 'mock'); // Initialize Logger
/**
* ColorMapRun API SDK (Full Version with Mock)
* 封装了与后端服务器的所有交互
* 依赖: bridge.js (用于 401 跳转登录)
*/
// 基础配置
var Config = {
baseUrl: 'https://colormaprun.com/api/card/',
ossUrl: 'http://oss-card.colormaprun.com/card/',
token: '',
useMock: false
};
// 模拟数据定义 (涵盖所有接口)
var MOCK_DB = {
'CardBaseQuery': {
ecName: '[Mock]跑向大明湖卡片',
ecDesc: '欢迎参加彩图奔跑活动!',
beginSecond: Date.now() / 1000 - 86400 * 5,
endSecond: Date.now() / 1000 + 86400 * 10,
secondCardName: '地图导航'
},
'CardDetailQuery': {
mcId: 101,
mcName: '[Mock]线上马拉松',
nickName: '[Mock]用户昵称', // Added as per user request
mcType: 1,
beginSecond: Date.now() / 1000 - 86400 * 2,
endSecond: Date.now() / 1000 + 86400 * 5,
teamNum: 0,
coiId: 1, // Mocked coiId
coiName: '个人组',
ocaId: 201 // Mocked ocaId
},
'MatchRsDetailQuery': {
id: 1,
name: '[Mock]活动1',
status: 1,
totalSysPoint: 100,
mcType: 1,
mcId: 101,
mcName: '[Mock]线上马拉松',
beginSecond: Date.now() / 1000 - 86400 * 2,
endSecond: Date.now() / 1000 + 86400 * 5,
nickName: '[Mock]用户昵称',
totalNum: 10,
totalDistanct: 5000,
totalDistanctRankNum: 5,
totalCp: 20,
totalCpRankNum: 3,
totalSysPointRankNum: 10,
fastPace: 300,
fastPaceRankNum: 8
},
'CardRankDetailQuery': {
totalRankRs: [
{ userName: 'Mock张三', score: 10000, headUrl: 'https://picsum.photos/40/40?random=1', rankNum: 1, isSelf: 0, inRankNum: 1, isInGame: 0, additionalName: '计算机学院', isDispAdditionalName: 1, inGameUserNum: 0, isDispInGameUserNum: 0, isTodayFinishGame: 0 },
{ userName: 'Mock李四', score: 9500, headUrl: 'https://picsum.photos/40/40?random=2', rankNum: 2, isSelf: 0, inRankNum: 2, isInGame: 0, additionalName: '土木建筑', isDispAdditionalName: 1, inGameUserNum: 0, isDispInGameUserNum: 0, isTodayFinishGame: 0 },
{ userName: 'Mock王五', score: 8800, headUrl: 'https://picsum.photos/40/40?random=3', rankNum: 3, isSelf: 0, inRankNum: 3, isInGame: 0, additionalName: '艺术设计', isDispAdditionalName: 1, inGameUserNum: 0, isDispInGameUserNum: 0, isTodayFinishGame: 0 },
{ userName: 'Mock赵六', score: 7200, headUrl: 'https://picsum.photos/40/40?random=4', rankNum: 4, isSelf: 0, inRankNum: 4, isInGame: 0, additionalName: '交通运输', isDispAdditionalName: 1, inGameUserNum: 0, isDispInGameUserNum: 0, isTodayFinishGame: 0 },
{ userName: 'Mock小明', score: 6500, headUrl: 'https://picsum.photos/40/40?random=5', rankNum: 5, isSelf: 1, inRankNum: 5, isInGame: 0, additionalName: '信息工程', isDispAdditionalName: 1, inGameUserNum: 0, isDispInGameUserNum: 0, isTodayFinishGame: 0 }
],
teamRankRs: [],
inTeamRs: [],
otherRs: [],
regionPaceRs: null,
regionTodayPaceRs: null,
regionSpeedRs: null
},
'UserCurrentRankNumQuery': { rankNum: 5 },
'UserJoinCardQuery': { isJoin: false }, // 默认未报名
'IsNewUserInCardComp': { isNew: true },
'OnlineMcSignUpDetail': {
teamList: [
{ teamId: 1, teamName: '[Mock]个人组' },
{ teamId: 2, teamName: '[Mock]团队组' }
],
signupFields: [
{ name: 'realName', label: '真实姓名', type: 'text', required: true, value: '' },
{ name: 'phone', label: '手机号码', type: 'tel', required: true, value: '' }
]
},
'OnlineMcSignUp': {}, // 报名成功返回空 data
'IsAllowMcSignUp': { allowSignUp: true },
'CurrentMonthlyChallengeQuery': {
year: '2023',
monthRs: [{ month: 11, realNum: 10, targetNum: 20 }]
},
'CardConfigQuery': {
configJson: JSON.stringify({
css: ".custom-header { background-color: #f0f8ff; }",
tabActiveColor: "#007bff",
teamType: 0, // Mocked teamType
popupRuleConfig: { height: "60%", theme: "light" },
popupMessageConfig: {}, // Mocked popupMessageConfig
popupRuleList: [
{ type: 1, data: { title: '规则1', content: '这是Mock的活动规则内容。' } },
{ type: 1, data: { title: '规则2', content: '第二条规则。', logo: { src: 'https://picsum.photos/100/50', width: '100px', height: '50px' } } }
],
popupDataList: [ // Mocked popupDataList
{ type: 1, data: { title: '通用弹窗1', content: '通用弹窗内容1。' } }
]
})
},
'UserConfigQuery': {
configJson: JSON.stringify({
tplInfo: { tplTypeId: 1, ssctId: 1 },
mapInfo: [
{ activityList: [{ showName: '迷你路线', pathImg: '', ocaId: 1, matchType: 1, point: { longitude: 117.0, latitude: 36.6, name: '起点' } }] }
],
popupRuleList: [{ type: 1, data: { title: '用户个性化', content: '这是用户专属内容' } }]
})
},
'MonthlyChallengeQuery': [
{ year: '2023', monthRs: [{ month: 10, realNum: 15, targetNum: 20 }] },
{ year: '2022', monthRs: [{ month: 12, realNum: 25, targetNum: 20 }] }
],
'MonthRankDetailQuery': [
{ nickName: '月榜冠军', score: 500, headUrl: 'https://picsum.photos/40/40?random=6' }
],
'AchievementQuery': [
{
year: '2023',
aiRs: [
{ aiName: '初次登场', aiTime: Date.now() / 1000 - 86400 * 30, iconUrl: 'https://picsum.photos/60/60?random=7' },
{ aiName: '跑步达人', aiTime: Date.now() / 1000 - 86400 * 10, iconUrl: 'https://picsum.photos/60/60?random=8' }
]
}
],
'ExchangeListQuery': [
{ exchangeId: 1, goodsName: '[Mock]运动手环', createTime: Date.now() / 1000 - 86400 * 7, status: 1 },
{ exchangeId: 2, goodsName: '[Mock]定制水杯', createTime: Date.now() / 1000 - 86400 * 15, status: 0 }
],
'ExchangeDetailQuery': {
exchangeId: 1, goodsName: '[Mock]运动手环', createTime: Date.now() / 1000 - 86400 * 7, status: 1,
address: 'Mock地址', receiver: 'Mock收件人', phone: '138****8888'
},
'UnReadMessageQuery': [
{ mqId: 1, mqType: 1, mqTitle: '[Mock]新成就', mqMessage: '恭喜您解锁新成就!', iconUrl: 'https://picsum.photos/50/50?random=9' }
],
'ReadMessage': {},
'MapListQuery': [
{ mapId: 1, mapName: '[Mock]公园地图', latitude: 36.6, longitude: 117.0, activityList: [] }
],
'CompStatisticQuery': { totalDistance: 5024, totalPeople: 1000, totalAnswerNum: 1500, totalCp: 8900 },
'WarnMessageQuery': [
{ warnType: 1, warnTitle: '[Mock]黄牌警告', warnMessage: '您的成绩异常', iconUrl: 'https://picsum.photos/50/50?random=10' }
],
'CertStyleQuery': {
styleId: 1, styleName: '简约风', templateUrl: 'https://picsum.photos/600/400?random=11',
elements: [
{ type: 'text', field: 'userName', x: 100, y: 150, fontSize: 24, color: '#333' }
]
},
'UserBaseQueryInCertificate': { userName: '[Mock]证书用户', activityName: '[Mock]活动名', completionTime: Date.now() / 1000 },
'CertificateCreateByUserAi': { certUrl: 'https://picsum.photos/600/400?random=12' },
'OnlineScoreQuery': { score: 880, extTime: Date.now() / 1000 + 86400 * 30 },
'CanExchangeGoodsList': [
{ goodsId: 1, goodsName: '[Mock]运动手环', goodsPic: 'https://picsum.photos/100/100?random=13', goodsLeftNum: 50, corrScore: 500 },
{ goodsId: 2, goodsName: '[Mock]定制水杯', goodsPic: 'https://picsum.photos/100/100?random=14', goodsLeftNum: 0, corrScore: 300 }
],
'CanExchangeGoodsDetail': {
goodsId: 1, goodsName: '[Mock]运动手环', goodsPic: 'https://picsum.photos/200/200?random=15', corrScore: 500,
desc: '这是Mock的运动手环详情,功能强大,是您运动的好伙伴!'
},
'ScoreExchangeGoods': {},
'UserBasicInformationQuery': { nickName: 'Mock用户', headUrl: 'https://picsum.photos/50/50?random=16' },
'GridsQuery': {
compId: 201, compName: '[Mock]网格挑战', widthNum: 3, heightNum: 3,
maskImgPic: 'https://picsum.photos/300/300?random=17',
actualImgPic: 'https://picsum.photos/300/300?random=18',
state: 2, // 1:未开始 2:进行中 3:已结束
detailRs: [
{ orderNum: 1, isComplete: 1, showName: '完成1', relationType: 1, ocaId: 10, longitude: 117.1, latitude: 36.6, popupImg: 'https://picsum.photos/100/100?random=19' },
{ orderNum: 2, isComplete: 0, showName: '未完2', relationType: 1, ocaId: 11, longitude: 117.2, latitude: 36.7, popupImg: 'https://picsum.photos/100/100?random=20' }
]
},
'CardUrlQuery': { url: 'https://mock-uri.colormaprun.com/card/nanning1/index.html'}, // 暂无 Mock 结构
'MatchFininshInfoQuery': {}, // 暂无 Mock 结构
'RedisRebulid': {} // 暂无 Mock 结构
};
var API = {
init: function(options) {
if (options.baseUrl) Config.baseUrl = options.baseUrl;
if (options.ossUrl) Config.ossUrl = options.ossUrl;
if (options.token) Config.token = options.token;
if (typeof options.useMock === 'boolean') Config.useMock = options.useMock;
if (Config.useMock) Logger.warn('%c [API] Mock 模式已开启 ', 'background: orange; color: white;');
},
getOssUrl: function() {
return Config.ossUrl;
},
setToken: function(token) {
Config.token = token;
},
request: function(endpoint, data, method) {
var reqMethod = (method || 'POST').toUpperCase();
if (Config.useMock) {
return new Promise(function(resolve, reject) {
Logger.log('[API-Mock] Request (' + reqMethod + '):', endpoint, data);
setTimeout(function() {
var mockData = MOCK_DB[endpoint];
if (endpoint === 'OnlineMcSignUp') MOCK_DB['UserJoinCardQuery'].isJoin = true;
if (endpoint === 'ScoreExchangeGoods') MOCK_DB['OnlineScoreQuery'].score -= 100;
Logger.log('[API-Mock] Response:', endpoint, mockData || {});
resolve(mockData || {});
}, 300);
});
}
var url = Config.baseUrl + endpoint;
var body = null;
if (reqMethod === 'GET') {
var headers = { 'Content-Type': 'application/x-www-form-urlencoded','Authorization': 'Bearer ' + Config.token };
var params = new URLSearchParams();
for (var key in data) { if (data.hasOwnProperty(key)) params.append(key, data[key]); }
var queryString = params.toString();
if (queryString) url += '?' + queryString;
} else {
var headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'token': Config.token};
var formData = new URLSearchParams();
for (var key in data) { if (data.hasOwnProperty(key)) formData.append(key, data[key]); }
body = formData;
}
Logger.log('[API] Request (' + reqMethod + '):', endpoint, data);
return fetch(url, { method: reqMethod, headers: headers, body: body, mode: 'cors', credentials: 'omit' })
.then(function(response) { return response.json(); })
.then(function(res) {
Logger.log('[API] Response:', endpoint, res);
if (res.code === 0) return res.data;
// if (res.code === 401 || res.statusCode === 401) {
// Logger.warn('[API] Token invalid');
// if (window.Bridge && window.Bridge._post) window.Bridge._post('toLogin');
// else alert('登录已过期');
// throw new Error('Unauthorized');
// }
// var msg = res.message || '请求失败';
// if (window.Bridge && window.Bridge.showToast) {
// window.Bridge.showToast(msg, 'none');
// } else {
// alert(msg);
// }
// throw new Error(msg);
})
.catch(function(err) { Logger.error('[API] Error:', err); throw err; });
},
// ==============================
// 完整业务接口封装 (按原始 api.js 顺序)
// ==============================
// 1. 卡片基本信息查询
getCardBase: function(ecId) { return this.request('CardBaseQuery', { ecId: ecId }); },
// 2. 卡片对应活动或赛事详情查询
getCardDetail: function(ecId) { return this.request('CardDetailQuery', { ecId: ecId }); },
// 3. 卡片对应线上赛多个活动查询
getMatchRsDetail: function(ecId, ocaId) { return this.request('MatchRsDetailQuery', { ecId: ecId, ocaId: ocaId }); },
// 4. 排名查询
getRankDetail: function(mcIdListStr, mcType, ocaId, dispArrStr) { return this.request('CardRankDetailQuery', { mcIdListStr: mcIdListStr, mcType: mcType, ocaId: ocaId, dispArrStr: dispArrStr }); },
// 5. 卡片用户当前排名查询
getUserCurrentRank: function(ecId) { return this.request('UserCurrentRankNumQuery', { ecId: ecId }); },
// 6. 用户是否已经报名卡片对应赛事查询
getUserJoinStatus: function(ecId) { return this.request('UserJoinCardQuery', { ecId: ecId }); },
// 7. 用户在卡片对应赛事是否新用户
isNewUserInCardComp: function(ecId) { return this.request('IsNewUserInCardComp', { ecId: ecId }); },
// 8. 线上赛报名页面信息详情
getOnlineMcSignUpDetail: function(ecId, mcId) { return this.request('OnlineMcSignUpDetail', { ecId: ecId, mcId: mcId }); },
// 9. 线上赛报名(重新分组)
signUpOnline: function(mcId, coiId, selectTeam, nickName) {
return this.request('OnlineMcSignUp', { mcId: mcId, coiId: coiId, selectTeam: selectTeam, nickName: nickName });
},
// 10. 是否允许重新分组(报名)
isAllowMcSignUp: function(ecId) { return this.request('IsAllowMcSignUp', { ecId: ecId }); },
// 11. 玩家当前月挑战记录查询
getCurrentMonthlyChallenge: function(year, month) { return this.request('CurrentMonthlyChallengeQuery', {year: year, month: month}); },
// 12. 卡片配置信息查询
getCardConfig: function(ecId, pageName) { return this.request('CardConfigQuery', { ecId: ecId, pageName: pageName }); },
// 13. 用户自定义配置信息查询
getUserConfig: function(ecId, pageName) { return this.request('UserConfigQuery', { ecId: ecId, pageName: pageName }); },
// 14. 玩家所有月挑战记录查询
getMonthlyChallenge: function() { return this.request('MonthlyChallengeQuery', {}); },
// 15. 月挑战排名查询
getMonthRankDetail: function(year, month, dispArrStr) { return this.request('MonthRankDetailQuery', {year: year, month: month, dispArrStr: dispArrStr}); },
// 16. 玩家活动成就查询
getAchievement: function() { return this.request('AchievementQuery', {}); },
// 17. 玩家兑换记录查询
getExchangeList: function() { return this.request('ExchangeListQuery', {}); },
// 18. 玩家兑换详情查询
getExchangeDetail: function(oarId) { return this.request('ExchangeDetailQuery', { oarId: oarId}); },
// 19. 未读消息列表查询
getUnReadMessages: function(relationId, relationType) { return this.request('UnReadMessageQuery', { relationId: relationId, relationType: relationType || 2 }); },
// 20. 标记消息已读
readMessage: function(mqIdListStr) { return this.request('ReadMessage', { mqIdListStr: mqIdListStr }); },
// 21. 卡片对应地图列表详情查询
getMapList: function(mcId) { return this.request('MapListQuery', { mcId: mcId }); },
// 22. 赛事总成绩统计查询
getCompStatistic: function(mcId) { return this.request('CompStatisticQuery', { mcId: mcId }); },
// 23. 警告列表查询
getWarnMessage: function(ecId) { return this.request('WarnMessageQuery', { ecId: ecId }); },
// 24. 查询电子证书样式
getCertStyle: function(certStyleType) { return this.request('CertStyleQuery', { certStyleType: certStyleType }); },
// 25. 查询电子证书成就对应用户基本信息
getUserBaseInCertificate: function(oarId) { return this.request('UserBaseQueryInCertificate', { oarId: oarId }); },
// 26. 根据成就信息确认生成电子证书
createCertificate: function(nickName,oarId) { return this.request('CertificateCreateByUserAi', {nickName: nickName, oarId: oarId}); },
// 27. 卡片内可用积分查询
getScore: function(ecId) { return this.request('OnlineScoreQuery', { ecId: ecId }); },
// 28. 积分可兑换商品列表查询
getGoodsList: function(ecId) { return this.request('CanExchangeGoodsList', { ecId: ecId }); },
// 29. 积分可兑换商品详情
getGoodsDetail: function(ecId, goodsId) { return this.request('CanExchangeGoodsDetail', {ecid: ecId, goodsId: goodsId }); },
// 30. 积分兑换商品
exchangeGoods: function(ecId, goodsId, exchNum) { return this.request('ScoreExchangeGoods', { ecId: ecId, goodsId: goodsId, exchNum: exchNum }); },
// 31. 用户基本信息查询
getUserInfo: function() { return this.request('UserBasicInformationQuery', {}, 'GET'); },
// 32. 网格卡片信息查询
getGrids: function(ecId) { return this.request('GridsQuery', { ecId: ecId }); },
// 33. 卡片URI查询
getCardUrl: function(actId, matchType) { return this.request('CardUrlQuery', { actId: actId, matchType: matchType }); },
// 34. 赛事完赛信息查询
getMatchFininshInfo: function(actId, matchType) { return this.request('MatchFininshInfoQuery', { actId, matchType }); },
// 35. Redis 重建 (管理接口)
redisRebulid: function(compId) { return this.request('RedisRebulid', { compId: compId }); }
};
window.API = API;
})(window);