api.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. (function (window) {
  2. 'use strict';
  3. /**
  4. * ColorMapRun API SDK (Full Version with Mock)
  5. * 封装了与后端服务器的所有交互
  6. * 依赖: bridge.js (用于 401 跳转登录)
  7. */
  8. // 基础配置
  9. var Config = {
  10. baseUrl: 'https://t-mapi.colormaprun.com/api/card/',
  11. ossUrl: 'http://oss-card.colormaprun.com/card/',
  12. token: '',
  13. useMock: false
  14. };
  15. // 模拟数据定义 (涵盖所有接口)
  16. var MOCK_DB = {
  17. 'CardBaseQuery': {
  18. ecName: '[Mock]跑向大明湖卡片',
  19. ecDesc: '欢迎参加彩图奔跑活动!',
  20. beginSecond: Date.now() / 1000 - 86400 * 5,
  21. endSecond: Date.now() / 1000 + 86400 * 10,
  22. secondCardName: '地图导航'
  23. },
  24. 'CardDetailQuery': {
  25. mcId: 101,
  26. mcName: '[Mock]线上马拉松',
  27. mcType: 1,
  28. beginSecond: Date.now() / 1000 - 86400 * 2,
  29. endSecond: Date.now() / 1000 + 86400 * 5,
  30. teamNum: 0,
  31. coiName: '个人组'
  32. },
  33. 'MatchRsDetailQuery': [
  34. { id: 1, name: '[Mock]活动1', status: 1 },
  35. { id: 2, name: '[Mock]活动2', status: 0 }
  36. ],
  37. 'CardRankDetailQuery': {
  38. totalRankRs: [
  39. { nickName: 'Mock张三', score: 10000, headUrl: 'https://picsum.photos/40/40?random=1', rankNum: 1 },
  40. { nickName: 'Mock李四', score: 9500, headUrl: 'https://picsum.photos/40/40?random=2', rankNum: 2 },
  41. { nickName: 'Mock王五', score: 8800, headUrl: 'https://picsum.photos/40/40?random=3', rankNum: 3 },
  42. { nickName: 'Mock赵六', score: 7200, headUrl: 'https://picsum.photos/40/40?random=4', rankNum: 4 },
  43. { nickName: 'Mock小明', score: 6500, headUrl: 'https://picsum.photos/40/40?random=5', rankNum: 5 }
  44. ],
  45. teamRankRs: [],
  46. inTeamRs: [],
  47. otherRs: []
  48. },
  49. 'UserCurrentRankNumQuery': { rankNum: 5 },
  50. 'UserJoinCardQuery': { isJoin: false }, // 默认未报名
  51. 'IsNewUserInCardComp': { isNew: true },
  52. 'OnlineMcSignUpDetail': {
  53. teamList: [
  54. { teamId: 1, teamName: '[Mock]个人组' },
  55. { teamId: 2, teamName: '[Mock]团队组' }
  56. ],
  57. signupFields: [
  58. { name: 'realName', label: '真实姓名', type: 'text', required: true, value: '' },
  59. { name: 'phone', label: '手机号码', type: 'tel', required: true, value: '' }
  60. ]
  61. },
  62. 'OnlineMcSignUp': {}, // 报名成功返回空 data
  63. 'IsAllowMcSignUp': { allowSignUp: true },
  64. 'CurrentMonthlyChallengeQuery': {
  65. year: '2023',
  66. monthRs: [{ month: 11, realNum: 10, targetNum: 20 }]
  67. },
  68. 'CardConfigQuery': {
  69. configJson: JSON.stringify({
  70. css: ".custom-header { background-color: #f0f8ff; }",
  71. tabActiveColor: "#007bff",
  72. popupRuleConfig: { height: "60%", theme: "light" },
  73. popupRuleList: [
  74. { type: 1, data: { title: '规则1', content: '这是<b>Mock</b>的活动规则内容。' } },
  75. { type: 1, data: { title: '规则2', content: '第二条规则。', logo: { src: 'https://picsum.photos/100/50', width: '100px', height: '50px' } } }
  76. ]
  77. })
  78. },
  79. 'UserConfigQuery': {
  80. configJson: JSON.stringify({
  81. tplInfo: { tplTypeId: 1, ssctId: 1 },
  82. mapInfo: [
  83. { activityList: [{ showName: '迷你路线', pathImg: '', ocaId: 1, matchType: 1, point: { longitude: 117.0, latitude: 36.6, name: '起点' } }] }
  84. ],
  85. popupRuleList: [{ type: 1, data: { title: '用户个性化', content: '这是用户专属内容' } }]
  86. })
  87. },
  88. 'MonthlyChallengeQuery': [
  89. { year: '2023', monthRs: [{ month: 10, realNum: 15, targetNum: 20 }] },
  90. { year: '2022', monthRs: [{ month: 12, realNum: 25, targetNum: 20 }] }
  91. ],
  92. 'MonthRankDetailQuery': [
  93. { nickName: '月榜冠军', score: 500, headUrl: 'https://picsum.photos/40/40?random=6' }
  94. ],
  95. 'AchievementQuery': [
  96. {
  97. year: '2023',
  98. aiRs: [
  99. { aiName: '初次登场', aiTime: Date.now() / 1000 - 86400 * 30, iconUrl: 'https://picsum.photos/60/60?random=7' },
  100. { aiName: '跑步达人', aiTime: Date.now() / 1000 - 86400 * 10, iconUrl: 'https://picsum.photos/60/60?random=8' }
  101. ]
  102. }
  103. ],
  104. 'ExchangeListQuery': [
  105. { exchangeId: 1, goodsName: '[Mock]运动手环', createTime: Date.now() / 1000 - 86400 * 7, status: 1 },
  106. { exchangeId: 2, goodsName: '[Mock]定制水杯', createTime: Date.now() / 1000 - 86400 * 15, status: 0 }
  107. ],
  108. 'ExchangeDetailQuery': {
  109. exchangeId: 1, goodsName: '[Mock]运动手环', createTime: Date.now() / 1000 - 86400 * 7, status: 1,
  110. address: 'Mock地址', receiver: 'Mock收件人', phone: '138****8888'
  111. },
  112. 'UnReadMessageQuery': [
  113. { mqId: 1, mqType: 1, mqTitle: '[Mock]新成就', mqMessage: '恭喜您解锁新成就!', iconUrl: 'https://picsum.photos/50/50?random=9' }
  114. ],
  115. 'ReadMessage': {},
  116. 'MapListQuery': [
  117. { mapId: 1, mapName: '[Mock]公园地图', latitude: 36.6, longitude: 117.0, activityList: [] }
  118. ],
  119. 'CompStatisticQuery': { totalDistance: 123.45, totalPeople: 1000 },
  120. 'WarnMessageQuery': [
  121. { warnType: 1, warnTitle: '[Mock]黄牌警告', warnMessage: '您的成绩异常', iconUrl: 'https://picsum.photos/50/50?random=10' }
  122. ],
  123. 'CertStyleQuery': {
  124. styleId: 1, styleName: '简约风', templateUrl: 'https://picsum.photos/600/400?random=11',
  125. elements: [
  126. { type: 'text', field: 'userName', x: 100, y: 150, fontSize: 24, color: '#333' }
  127. ]
  128. },
  129. 'UserBaseQueryInCertificate': { userName: '[Mock]证书用户', activityName: '[Mock]活动名', completionTime: Date.now() / 1000 },
  130. 'CertificateCreateByUserAi': { certUrl: 'https://picsum.photos/600/400?random=12' },
  131. 'OnlineScoreQuery': { score: 880, extTime: Date.now() / 1000 + 86400 * 30 },
  132. 'CanExchangeGoodsList': [
  133. { goodsId: 1, goodsName: '[Mock]运动手环', goodsPic: 'https://picsum.photos/100/100?random=13', goodsLeftNum: 50, corrScore: 500 },
  134. { goodsId: 2, goodsName: '[Mock]定制水杯', goodsPic: 'https://picsum.photos/100/100?random=14', goodsLeftNum: 0, corrScore: 300 }
  135. ],
  136. 'CanExchangeGoodsDetail': {
  137. goodsId: 1, goodsName: '[Mock]运动手环', goodsPic: 'https://picsum.photos/200/200?random=15', corrScore: 500,
  138. desc: '这是<b>Mock</b>的运动手环详情,功能强大,是您运动的好伙伴!'
  139. },
  140. 'ScoreExchangeGoods': {},
  141. 'UserBasicInformationQuery': { nickName: 'Mock用户', headUrl: 'https://picsum.photos/50/50?random=16' },
  142. 'GridsQuery': {
  143. compId: 201, compName: '[Mock]网格挑战', widthNum: 3, heightNum: 3,
  144. maskImgPic: 'https://picsum.photos/300/300?random=17',
  145. actualImgPic: 'https://picsum.photos/300/300?random=18',
  146. state: 2, // 1:未开始 2:进行中 3:已结束
  147. detailRs: [
  148. { orderNum: 1, isComplete: 1, showName: '完成1', relationType: 1, ocaId: 10, longitude: 117.1, latitude: 36.6, popupImg: 'https://picsum.photos/100/100?random=19' },
  149. { orderNum: 2, isComplete: 0, showName: '未完2', relationType: 1, ocaId: 11, longitude: 117.2, latitude: 36.7, popupImg: 'https://picsum.photos/100/100?random=20' }
  150. ]
  151. }
  152. };
  153. var API = {
  154. init: function(options) {
  155. if (options.baseUrl) Config.baseUrl = options.baseUrl;
  156. if (options.ossUrl) Config.ossUrl = options.ossUrl;
  157. if (options.token) Config.token = options.token;
  158. if (typeof options.useMock === 'boolean') Config.useMock = options.useMock;
  159. if (Config.useMock) console.warn('%c [API] Mock 模式已开启 ', 'background: orange; color: white;');
  160. },
  161. getOssUrl: function() {
  162. return Config.ossUrl;
  163. },
  164. setToken: function(token) {
  165. Config.token = token;
  166. },
  167. request: function(endpoint, data) {
  168. if (Config.useMock) {
  169. return new Promise(function(resolve, reject) {
  170. console.log('[API-Mock] Request:', endpoint, data);
  171. setTimeout(function() {
  172. var mockData = MOCK_DB[endpoint];
  173. if (endpoint === 'OnlineMcSignUp') MOCK_DB['UserJoinCardQuery'].isJoin = true;
  174. if (endpoint === 'ScoreExchangeGoods') MOCK_DB['OnlineScoreQuery'].score -= 100;
  175. console.log('[API-Mock] Response:', endpoint, mockData || {});
  176. resolve(mockData || {});
  177. }, 300);
  178. });
  179. }
  180. var url = Config.baseUrl + endpoint;
  181. var headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'token': Config.token };
  182. var formData = new URLSearchParams();
  183. for (var key in data) { if (data.hasOwnProperty(key)) formData.append(key, data[key]); }
  184. console.log('[API] Request:', endpoint, data);
  185. return fetch(url, { method: 'POST', headers: headers, body: formData })
  186. .then(function(response) { return response.json(); })
  187. .then(function(res) {
  188. console.log('[API] Response:', endpoint, res);
  189. if (res.code === 0) return res.data;
  190. if (res.code === 401 || res.statusCode === 401) {
  191. console.warn('[API] Token invalid');
  192. if (window.Bridge && window.Bridge._post) window.Bridge._post('toLogin');
  193. else alert('登录已过期');
  194. throw new Error('Unauthorized');
  195. }
  196. var msg = res.message || '请求失败';
  197. alert(msg);
  198. throw new Error(msg);
  199. })
  200. .catch(function(err) { console.error('[API] Error:', err); throw err; });
  201. },
  202. // ==============================
  203. // 完整业务接口封装 (按原始 api.js 顺序)
  204. // ==============================
  205. // 1. 卡片基本信息查询
  206. getCardBase: function(ecId, pageName) { return this.request('CardBaseQuery', { ecId: ecId, pageName: pageName }); },
  207. // 2. 卡片对应活动或赛事详情查询
  208. getCardDetail: function(ecId) { return this.request('CardDetailQuery', { ecId: ecId }); },
  209. // 3. 卡片对应线上赛多个活动查询
  210. getMatchRsDetail: function(ecId) { return this.request('MatchRsDetailQuery', { ecId: ecId }); },
  211. // 4. 排名查询
  212. getRankDetail: function(mcIdListStr, mcType, dispArrStr) { return this.request('CardRankDetailQuery', { mcIdListStr: mcIdListStr, mcType: mcType, dispArrStr: dispArrStr }); },
  213. // 5. 卡片用户当前排名查询
  214. getUserCurrentRank: function(ecId) { return this.request('UserCurrentRankNumQuery', { ecId: ecId }); },
  215. // 6. 用户是否已经报名卡片对应赛事查询
  216. getUserJoinStatus: function(ecId) { return this.request('UserJoinCardQuery', { ecId: ecId }); },
  217. // 7. 用户在卡片对应赛事是否新用户
  218. isNewUserInCardComp: function(ecId) { return this.request('IsNewUserInCardComp', { ecId: ecId }); },
  219. // 8. 线上赛报名页面信息详情
  220. getOnlineMcSignUpDetail: function(ecId) { return this.request('OnlineMcSignUpDetail', { ecId: ecId }); },
  221. // 9. 线上赛报名(重新分组)
  222. signUpOnline: function(mcId, coiId, selectTeam, nickName) {
  223. return this.request('OnlineMcSignUp', { mcId: mcId, coiId: coiId, selectTeam: selectTeam, nickName: nickName });
  224. },
  225. // 10. 是否允许重新分组(报名)
  226. isAllowMcSignUp: function(ecId) { return this.request('IsAllowMcSignUp', { ecId: ecId }); },
  227. // 11. 玩家当前月挑战记录查询
  228. getCurrentMonthlyChallenge: function() { return this.request('CurrentMonthlyChallengeQuery', {}); },
  229. // 12. 卡片配置信息查询
  230. getCardConfig: function(ecId, pageName) { return this.request('CardConfigQuery', { ecId: ecId, pageName: pageName }); },
  231. // 13. 用户自定义配置信息查询
  232. getUserConfig: function(ecId, pageName) { return this.request('UserConfigQuery', { ecId: ecId, pageName: pageName }); },
  233. // 14. 玩家所有月挑战记录查询
  234. getMonthlyChallenge: function() { return this.request('MonthlyChallengeQuery', {}); },
  235. // 15. 月挑战排名查询
  236. getMonthRankDetail: function() { return this.request('MonthRankDetailQuery', {}); },
  237. // 16. 玩家活动成就查询
  238. getAchievement: function() { return this.request('AchievementQuery', {}); },
  239. // 17. 玩家兑换记录查询
  240. getExchangeList: function(ecId) { return this.request('ExchangeListQuery', { ecId: ecId }); },
  241. // 18. 玩家兑换详情查询
  242. getExchangeDetail: function(ecId, exchangeId) { return this.request('ExchangeDetailQuery', { ecId: ecId, exchangeId: exchangeId }); },
  243. // 19. 未读消息列表查询
  244. getUnReadMessages: function(relationId, relationType) { return this.request('UnReadMessageQuery', { relationId: relationId, relationType: relationType || 2 }); },
  245. // 20. 标记消息已读
  246. readMessage: function(mqIdListStr) { return this.request('ReadMessage', { mqIdListStr: mqIdListStr }); },
  247. // 21. 卡片对应地图列表详情查询
  248. getMapList: function(ecId) { return this.request('MapListQuery', { ecId: ecId }); },
  249. // 22. 赛事总成绩统计查询
  250. getCompStatistic: function(ecId) { return this.request('CompStatisticQuery', { ecId: ecId }); },
  251. // 23. 警告列表查询
  252. getWarnMessage: function(ecId) { return this.request('WarnMessageQuery', { ecId: ecId }); },
  253. // 24. 查询电子证书样式
  254. getCertStyle: function(ecId) { return this.request('CertStyleQuery', { ecId: ecId }); },
  255. // 25. 查询电子证书成就对应用户基本信息
  256. getUserBaseInCertificate: function(ecId) { return this.request('UserBaseQueryInCertificate', { ecId: ecId }); },
  257. // 26. 根据成就信息确认生成电子证书
  258. createCertificate: function(data) { return this.request('CertificateCreateByUserAi', data); },
  259. // 27. 卡片内可用积分查询
  260. getScore: function(ecId) { return this.request('OnlineScoreQuery', { ecId: ecId }); },
  261. // 28. 积分可兑换商品列表查询
  262. getGoodsList: function(ecId) { return this.request('CanExchangeGoodsList', { ecId: ecId }); },
  263. // 29. 积分可兑换商品详情
  264. getGoodsDetail: function(goodsId) { return this.request('CanExchangeGoodsDetail', { goodsId: goodsId }); },
  265. // 30. 积分兑换商品
  266. exchangeGoods: function(ecId, goodsId) { return this.request('ScoreExchangeGoods', { ecId: ecId, goodsId: goodsId }); },
  267. // 31. 用户基本信息查询
  268. getUserInfo: function() { return this.request('UserBasicInformationQuery', {}); },
  269. // 32. 网格卡片信息查询
  270. getGrids: function(ecId) { return this.request('GridsQuery', { ecId: ecId }); }
  271. };
  272. window.API = API;
  273. })(window);