api.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // API 服务器地址 - 开发环境使用本地地址,生产环境请替换为实际域名
  2. // 微信开发者工具需勾选: 设置 → 安全 → 不校验合法域名
  3. const API_BASE_URL = 'http://127.0.0.1:8186/api'
  4. const TIMEOUT = 30000
  5. async function request(method, url, data) {
  6. const token = uni.getStorageSync('token')
  7. const header = { 'Content-Type': 'application/json' }
  8. if (token) {
  9. header.Authorization = `Bearer ${token}`
  10. }
  11. return new Promise((resolve, reject) => {
  12. uni.request({
  13. url: API_BASE_URL + url,
  14. method,
  15. data,
  16. header,
  17. timeout: TIMEOUT,
  18. success(res) {
  19. const response = res.data
  20. if (response.code !== 0) {
  21. uni.showToast({ title: response.message || '请求失败', icon: 'none' })
  22. if (response.code === 1001) {
  23. uni.removeStorageSync('token')
  24. // 跳转到登录页,避免 switchTab 超时问题
  25. setTimeout(() => {
  26. uni.reLaunch({ url: '/pages/login/index' })
  27. }, 500)
  28. }
  29. const err = new Error(response.message || '请求失败')
  30. err.code = response.code
  31. reject(err)
  32. } else {
  33. resolve(response.data)
  34. }
  35. },
  36. fail(err) {
  37. uni.showToast({ title: '网络错误', icon: 'none' })
  38. reject(err)
  39. }
  40. })
  41. })
  42. }
  43. const requestInstance = {
  44. get: (url, data) => request('GET', url, data),
  45. post: (url, data) => request('POST', url, data),
  46. put: (url, data) => request('PUT', url, data),
  47. delete: (url, data) => request('DELETE', url, data)
  48. }
  49. export default requestInstance
  50. export const authApi = {
  51. login: (data) => requestInstance.post('/auth/login', data)
  52. }
  53. export const consultationApi = {
  54. start: (data) => requestInstance.post('/consultation/start', data),
  55. check: (data) => requestInstance.post('/consultation/check', data),
  56. regenerate: (chartRecordId) => requestInstance.post('/consultation/regenerate', { chartRecordId })
  57. }
  58. export const chartApi = {
  59. create: (data) => requestInstance.post('/chart/create', data),
  60. list: () => requestInstance.post('/chart/list', {}),
  61. detail: (id) => requestInstance.post('/chart/detail', { id }),
  62. delete: (id) => requestInstance.post('/chart/delete', { id }),
  63. interpret: (chartRecordId) => requestInstance.post('/chart/interpret', { chartRecordId }),
  64. academicOrientation: (chartRecordId) => requestInstance.post('/chart/academic-orientation', { chartRecordId })
  65. }
  66. export const chatApi = {
  67. send: (data) => requestInstance.post('/chat/send', data),
  68. history: (chartRecordId) => requestInstance.post('/chat/history', { chartRecordId }),
  69. voiceUpload: (filePath, chartRecordId) => {
  70. const token = uni.getStorageSync('token')
  71. return new Promise((resolve, reject) => {
  72. uni.uploadFile({
  73. url: API_BASE_URL + '/chat/voice',
  74. filePath,
  75. name: 'file',
  76. formData: { chartRecordId: String(chartRecordId || '') },
  77. header: token ? { Authorization: `Bearer ${token}` } : {},
  78. success: (res) => {
  79. try {
  80. const data = JSON.parse(res.data)
  81. if (data.code === 0) resolve(data.data)
  82. else reject(new Error(data.message || '上传失败'))
  83. } catch (e) { reject(new Error('解析响应失败')) }
  84. },
  85. fail: (err) => reject(err)
  86. })
  87. })
  88. }
  89. }
  90. export const payApi = {
  91. create: (data) => requestInstance.post('/pay/create', data)
  92. }
  93. export const pricingApi = {
  94. current: () => requestInstance.post('/pricing/current', {}),
  95. upgrade: () => requestInstance.post('/pricing/upgrade', {})
  96. }
  97. export const planApi = {
  98. apply: (data) => requestInstance.post('/plan/apply', data),
  99. myRequests: () => requestInstance.post('/plan/requests/my', {})
  100. }
  101. export const workbenchApi = {
  102. list: () => requestInstance.post('/plan/requests/incoming', {}),
  103. accept: (requestId) => requestInstance.post('/plan/requests/accept', { requestId }),
  104. reject: (requestId) => requestInstance.post('/plan/requests/reject', { requestId })
  105. }
  106. export const proposalApi = {
  107. create: (data) => requestInstance.post('/plan/proposals/create', data),
  108. counter: (data) => requestInstance.post('/plan/proposals/counter', data),
  109. accept: (data) => requestInstance.post('/plan/proposals/accept', data),
  110. reject: (data) => requestInstance.post('/plan/proposals/reject', data),
  111. logs: (requestId) => requestInstance.post('/plan/proposals/logs', { requestId })
  112. }
  113. export const profileApi = {
  114. info: () => requestInstance.post('/profile/info', {}),
  115. vipStatus: () => requestInstance.post('/profile/vip-status', {}),
  116. quota: () => requestInstance.post('/profile/quota', {}),
  117. commissionSummary: () => requestInstance.post('/profile/commission-summary', {}),
  118. chartCount: () => requestInstance.post('/profile/chart-count', {}),
  119. trackShare: () => requestInstance.post('/profile/share/track', {}),
  120. complete: (data) => requestInstance.post('/profile/complete', data),
  121. update: (data) => requestInstance.post('/profile/update', data),
  122. qrcode: () => requestInstance.get('/profile/qrcode', {})
  123. }
  124. export const annotationApi = {
  125. add: (data) => requestInstance.post('/annotation/add', data),
  126. list: (recordId) => requestInstance.post('/annotation/list', { recordId }),
  127. delete: (id) => requestInstance.post('/annotation/delete', { id }),
  128. addTag: (data) => requestInstance.post('/annotation/tag/add', data),
  129. listTags: (recordId) => requestInstance.post('/annotation/tag/list', { recordId }),
  130. deleteTag: (id) => requestInstance.post('/annotation/tag/delete', { id })
  131. }
  132. export const commissionApi = {
  133. list: () => requestInstance.post('/commission/list', {}),
  134. total: () => requestInstance.post('/commission/total', {}),
  135. team: () => requestInstance.post('/commission/team', {}),
  136. stats: () => requestInstance.post('/commission/stats', {})
  137. }
  138. export const withdrawApi = {
  139. apply: (amount) => requestInstance.post('/withdraw/apply', { amount }),
  140. list: () => requestInstance.post('/withdraw/list', {}),
  141. balance: () => requestInstance.post('/withdraw/balance', {})
  142. }
  143. export const interventionApi = {
  144. chatList: () => requestInstance.post('/intervention/chat-list', {}),
  145. history: (chartRecordId) => requestInstance.post('/intervention/chat-history', { chartRecordId }),
  146. start: (chartRecordId) => requestInstance.post('/intervention/start', { chartRecordId }),
  147. end: (interventionId) => requestInstance.post('/intervention/end', { interventionId, endedBy: 'practitioner' }),
  148. endByUser: (interventionId) => requestInstance.post('/intervention/end', { interventionId, endedBy: 'user' }),
  149. send: (data) => requestInstance.post('/intervention/send', data)
  150. }
  151. /**
  152. * Admin-specific request that uses adminToken (stored separately from user token).
  153. */
  154. async function adminRequest(method, url, data) {
  155. const token = uni.getStorageSync('adminToken')
  156. const header = { 'Content-Type': 'application/json' }
  157. if (token) {
  158. header.Authorization = `Bearer ${token}`
  159. }
  160. return new Promise((resolve, reject) => {
  161. uni.request({
  162. url: API_BASE_URL + url,
  163. method,
  164. data,
  165. header,
  166. timeout: TIMEOUT,
  167. success(res) {
  168. const response = res.data
  169. if (response.code !== 0) {
  170. if (response.code === 1001) {
  171. // Token invalid or expired — clear admin token
  172. uni.removeStorageSync('adminToken')
  173. }
  174. const err = new Error(response.message || '请求失败')
  175. err.code = response.code
  176. reject(err)
  177. } else {
  178. resolve(response.data)
  179. }
  180. },
  181. fail(err) {
  182. uni.showToast({ title: '网络错误', icon: 'none' })
  183. reject(err)
  184. }
  185. })
  186. })
  187. }
  188. const adminRequestInstance = {
  189. post: (url, data) => adminRequest('POST', url, data)
  190. }
  191. export const adminApi = {
  192. login: (username, password) => adminRequestInstance.post('/admin/login', { username, password }),
  193. stats: () => adminRequestInstance.post('/admin/stats', {}),
  194. users: () => adminRequestInstance.post('/admin/users', {}),
  195. upgradeUser: (userId) => adminRequestInstance.post('/admin/user/upgrade', { userId }),
  196. downgradeUser: (userId) => adminRequestInstance.post('/admin/user/downgrade', { userId }),
  197. setAdmin: (userId, isAdmin) => adminRequestInstance.post('/admin/user/set-admin', { userId, isAdmin }),
  198. orders: () => adminRequestInstance.post('/admin/orders', {}),
  199. commissions: () => adminRequestInstance.post('/admin/commissions', {}),
  200. charts: () => adminRequestInstance.post('/admin/charts', {}),
  201. withdraws: () => adminRequestInstance.post('/admin/withdraws', {}),
  202. approveWithdraw: (id) => adminRequestInstance.post('/admin/withdraw/approve', { id }),
  203. rejectWithdraw: (id) => adminRequestInstance.post('/admin/withdraw/reject', { id }),
  204. configList: () => adminRequestInstance.post('/admin/config/list', {}),
  205. configUpdate: (data) => adminRequestInstance.post('/admin/config/update', data),
  206. configReset: (configKey) => adminRequestInstance.post('/admin/config/reset', { configKey })
  207. }
  208. export const deliveryApi = {
  209. create: (data) => requestInstance.post('/plan/delivery/create', data),
  210. list: (planRequestId) => requestInstance.post('/plan/delivery/list', { planRequestId })
  211. }
  212. export const exportApi = {
  213. pdf: (recordId) => {
  214. const token = uni.getStorageSync('token')
  215. return new Promise((resolve, reject) => {
  216. uni.downloadFile({
  217. url: API_BASE_URL + '/export/pdf',
  218. method: 'POST',
  219. data: { recordId },
  220. header: token ? { Authorization: `Bearer ${token}` } : {},
  221. success: (res) => {
  222. if (res.statusCode === 200) {
  223. resolve(res.tempFilePath)
  224. } else {
  225. reject(new Error('导出失败: ' + res.statusCode))
  226. }
  227. },
  228. fail: (err) => {
  229. reject(err)
  230. }
  231. })
  232. })
  233. }
  234. }