api.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. import config from '@/config.js'
  2. const BASE_URL = config.API_BASE_URL
  3. var _redirectingToLogin = false
  4. function _clearAuthAndRedirect() {
  5. if (_redirectingToLogin) return
  6. _redirectingToLogin = true
  7. uni.removeStorageSync('token')
  8. uni.removeStorageSync('userId')
  9. uni.removeStorageSync('role')
  10. uni.removeStorageSync('alumniVerify')
  11. uni.removeStorageSync('classId')
  12. uni.removeStorageSync('userInfo')
  13. try {
  14. var app = typeof getApp === 'function' ? getApp() : null
  15. if (app && app.$store) {
  16. app.$store.commit('logout')
  17. }
  18. } catch (e) {}
  19. uni.showToast({ title: '登录已过期,请重新登录', icon: 'none' })
  20. setTimeout(function() {
  21. uni.$emit('showLoginSheet', {})
  22. _redirectingToLogin = false
  23. }, 1500)
  24. }
  25. export const request = (url, method = 'POST', data = {}, options = {}) => {
  26. var fullUrl = BASE_URL + url
  27. const token = uni.getStorageSync('token')
  28. // 过滤空字符串 ID 字段,防止后端 Long.valueOf("") 抛 NumberFormatException
  29. var body = data
  30. if (data && typeof data === 'object' && !Array.isArray(data)) {
  31. body = {}
  32. var hasFiltered = false
  33. for (var bk in data) {
  34. if (Object.prototype.hasOwnProperty.call(data, bk)) {
  35. var bv = data[bk]
  36. if (bv === '' && /(?:Id|ID|_id)$/.test(bk)) {
  37. hasFiltered = true
  38. continue
  39. }
  40. body[bk] = bv
  41. }
  42. }
  43. if (!hasFiltered) body = data
  44. }
  45. return new Promise((resolve, reject) => {
  46. uni.request({
  47. url: fullUrl,
  48. method: method,
  49. data: body,
  50. header: {
  51. 'Content-Type': 'application/json',
  52. 'Authorization': token ? 'Bearer ' + token : ''
  53. },
  54. success: (res) => {
  55. if (res.statusCode === 401 || (res.data && res.data.code === 401)) {
  56. _clearAuthAndRedirect()
  57. reject(res.data || { code: 401, message: '未授权' })
  58. return
  59. }
  60. if (res.data && res.data.code === 200) {
  61. resolve(res.data)
  62. } else {
  63. // silent:业务型空态(如未入组/未报名)由页面自行展示,不弹全局 toast
  64. if (!options.silent) {
  65. uni.showToast({
  66. title: (res.data && res.data.message) || '请求失败',
  67. icon: 'none'
  68. })
  69. }
  70. reject(res.data)
  71. }
  72. },
  73. fail: (err) => {
  74. console.error('[API] 网络错误 ' + method + ' ' + fullUrl, err)
  75. uni.showToast({ title: '网络请求失败', icon: 'none' })
  76. reject(err)
  77. }
  78. })
  79. })
  80. }
  81. // === API 函数 ===
  82. // 登录
  83. export const wechatLogin = (code) => {
  84. return request('/api/auth/wechat-login', 'POST', { code })
  85. }
  86. // 微信手机号快捷登录(getPhoneNumber 授权,自动获取手机号+昵称)
  87. export const wechatPhoneLogin = (data) => {
  88. return request('/api/auth/wechat-phone-login', 'POST', data)
  89. }
  90. // 校友验证
  91. export const alumniVerify = (data) => {
  92. return request('/api/auth/alumni-verify', 'POST', data)
  93. }
  94. // 班次
  95. export const joinClass = (code) => {
  96. return request('/api/class/join', 'POST', { code })
  97. }
  98. export const getClassInfo = () => {
  99. return request('/api/class/info', 'POST')
  100. }
  101. // 课程(L0/L1/L2/L3/L4)
  102. export const getCourseList = () => {
  103. return request('/api/course/list', 'POST')
  104. }
  105. export const getMyCourse = (courseId) => {
  106. var data = {}
  107. if (courseId) {
  108. data = { courseId }
  109. }
  110. return request('/api/course/current', 'POST', data)
  111. }
  112. export const enterCourse = (courseId) => {
  113. return request('/api/course/enter', 'POST', { courseId })
  114. }
  115. export const getCourseProgress = () => {
  116. return request('/api/course/progress', 'POST')
  117. }
  118. export const getCourseModules = (courseId) => {
  119. return request('/api/course/modules', 'POST', { courseId })
  120. }
  121. // 分组
  122. export const joinGroup = (groupId) => {
  123. return request('/api/group/join', 'POST', { groupId })
  124. }
  125. export const getMyGroup = () => {
  126. // 未入组是正常空态,静默交由页面展示引导,不弹全局 toast
  127. return request('/api/group/mine', 'POST', {}, { silent: true })
  128. }
  129. export const getClassGroups = () => {
  130. return request('/api/group/list', 'POST')
  131. }
  132. export const setSpokesperson = (speakerUid) => {
  133. return request('/api/group/spokesperson', 'POST', { speakerUid })
  134. }
  135. export const assignRole = (bookType) => {
  136. return request('/api/group/assign', 'POST', { bookType })
  137. }
  138. // 三本账
  139. export const claimAssignment = (data) => {
  140. return request('/api/assignment/claim', 'POST', data)
  141. }
  142. export const getMyAssignments = () => {
  143. return request('/api/assignment/mine', 'POST')
  144. }
  145. export const getGroupAssignments = () => {
  146. return request('/api/assignment/group', 'POST')
  147. }
  148. // 提交/打卡
  149. export const checkin = (image) => {
  150. return request('/api/submission/checkin', 'POST', { image })
  151. }
  152. export const getCheckinStatus = () => {
  153. return request('/api/submission/checkin/status', 'POST')
  154. }
  155. export const prepCheck = (data) => {
  156. return request('/api/submission/prep-check', 'POST', data)
  157. }
  158. export const getPrepCheckStatus = () => {
  159. return request('/api/submission/prep-check/status', 'POST')
  160. }
  161. export const uploadSubmission = (data) => {
  162. return request('/api/submission/upload', 'POST', data)
  163. }
  164. export const getMySubmissions = () => {
  165. return request('/api/submission/mylist', 'POST')
  166. }
  167. export const submitTeachingCard = (data) => {
  168. return request('/api/submission/teaching-card', 'POST', data)
  169. }
  170. // 路演
  171. export const uploadRoadmap = (data) => {
  172. return request('/api/vote/roadmap/upload', 'POST', data)
  173. }
  174. // 投票
  175. export const castVote = (data) => {
  176. return request('/api/vote/cast', 'POST', data)
  177. }
  178. export const getVoteResult = (data) => {
  179. return request('/api/vote/result', 'POST', data)
  180. }
  181. export const getVotedStatus = (data) => {
  182. return request('/api/vote/voted', 'POST', data)
  183. }
  184. export const getScoreboard = (classId) => {
  185. return request('/api/vote/scoreboard', 'POST', { classId })
  186. }
  187. // 行动计划
  188. export const submitPlan = (data) => {
  189. return request('/api/plan/submit', 'POST', data)
  190. }
  191. export const getMyPlan = () => {
  192. return request('/api/plan/mine', 'POST')
  193. }
  194. export const submitSurvey = (data) => {
  195. return request('/api/plan/survey', 'POST', data)
  196. }
  197. export const getMyCoupons = () => {
  198. return request('/api/plan/coupons', 'POST')
  199. }
  200. export const getMyCert = () => {
  201. return request('/api/plan/cert', 'POST')
  202. }
  203. export const verifyCert = (certNo) => {
  204. return request('/api/cert/verify', 'POST', { certNo })
  205. }
  206. export const getMyBadges = () => {
  207. return request('/api/badge/mine', 'POST')
  208. }
  209. export const redeemCoupon = (data) => {
  210. return request('/api/plan/coupon/redeem', 'POST', data)
  211. }
  212. // 报名
  213. export const getEnrollClasses = () => {
  214. return request('/api/enroll/classes', 'POST')
  215. }
  216. export const createEnrollment = (data) => {
  217. return request('/api/enroll/create', 'POST', data)
  218. }
  219. export const getMyEnrollments = () => {
  220. return request('/api/enroll/mine', 'POST')
  221. }
  222. // 沙龙
  223. export const getSalonList = () => {
  224. return request('/api/salon/list', 'POST')
  225. }
  226. export const createSalonEnroll = (data) => {
  227. return request('/api/salon/create', 'POST', data)
  228. }
  229. export const getMySalons = () => {
  230. return request('/api/salon/mine', 'POST')
  231. }
  232. export const salonCheckin = (salonId) => {
  233. return request('/api/salon/checkin', 'POST', { salonId })
  234. }
  235. export const salonFeedback = (data) => {
  236. return request('/api/salon/feedback', 'POST', data)
  237. }
  238. // 支付
  239. export const createPayOrder = (data) => {
  240. return request('/api/pay/create', 'POST', data)
  241. }
  242. export const getPayStatus = (data) => {
  243. return request('/api/pay/status', 'POST', data)
  244. }
  245. export const cancelPayOrder = (data) => {
  246. return request('/api/pay/cancel', 'POST', data)
  247. }
  248. // 裂变分享
  249. export const getMyPoster = () => {
  250. return request('/api/invite/myposter', 'POST')
  251. }
  252. export const getInviteStats = () => {
  253. return request('/api/invite/stats', 'POST')
  254. }
  255. // 团报(FR-PAY-03)
  256. export const createGroupOrder = (data) => {
  257. return request('/api/group-order/create', 'POST', data)
  258. }
  259. export const getMyGroupOrders = () => {
  260. return request('/api/group-order/mine', 'POST')
  261. }
  262. export const getGroupOrderDetail = (data) => {
  263. return request('/api/group-order/detail', 'POST', data)
  264. }
  265. export const payGroupOrder = (data) => {
  266. return request('/api/group-order/pay', 'POST', data)
  267. }
  268. // 案例授权(FR-FISS-04)
  269. export const getMyCases = () => {
  270. return request('/api/case/mine', 'POST')
  271. }
  272. export const decideCase = (data) => {
  273. return request('/api/case/decide', 'POST', data)
  274. }
  275. // 课前资料
  276. export const getClassMaterials = () => {
  277. return request('/api/class/materials', 'POST')
  278. }
  279. // 文件上传
  280. export const uploadFile = (filePath) => {
  281. return new Promise((resolve, reject) => {
  282. const token = uni.getStorageSync('token')
  283. uni.uploadFile({
  284. url: BASE_URL + '/api/upload/file',
  285. filePath: filePath,
  286. name: 'file',
  287. header: {
  288. 'Authorization': token ? 'Bearer ' + token : ''
  289. },
  290. success: (res) => {
  291. try {
  292. const data = JSON.parse(res.data)
  293. if (data.code === 200) {
  294. resolve(data)
  295. } else {
  296. uni.showToast({ title: data.message || '上传失败', icon: 'none' })
  297. reject(data)
  298. }
  299. } catch (e) {
  300. reject(e)
  301. }
  302. },
  303. fail: (err) => {
  304. console.error('[API] 上传失败', err)
  305. uni.showToast({ title: '上传失败', icon: 'none' })
  306. reject(err)
  307. }
  308. })
  309. })
  310. }