api.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. import $app from "./app";
  2. import $config from "./config";
  3. const api = {};
  4. // 网络请求封装
  5. const Request = function (opts) {
  6. const originalComplete = opts.complete;
  7. return new Promise((resolve, reject) => {
  8. uni.request(
  9. Object.assign({}, opts, {
  10. complete: (res) => {
  11. const hasSuccess = Boolean(
  12. res.errMsg == "request:ok" &&
  13. res.statusCode >= 200 &&
  14. res.statusCode < 300
  15. );
  16. hasSuccess ? resolve(res.data) : reject(res);
  17. if (originalComplete && typeof originalComplete == "function")
  18. originalComplete(res);
  19. },
  20. })
  21. );
  22. });
  23. };
  24. // 路径拼接
  25. const pathJoin = function (...args) {
  26. return args.join("/").replace(/(?<!:)(\/{2,})/g, "/");
  27. };
  28. // 显示LOADING
  29. const showLoading = function () {
  30. uni.showLoading({ title: "", mask: true });
  31. };
  32. // 关闭LOADING
  33. const hideLoading = function () {
  34. uni.hideLoading();
  35. };
  36. // 获取用户TOKEN
  37. const getUserToken = function () {
  38. return uni.getStorageSync($config.keyname.userToken);
  39. };
  40. /**
  41. * 基础请求
  42. * @param {String} method 请求类型
  43. * @param {String} url 请求地址
  44. * @param {Object} data 请求数据
  45. * @param {Object} opts 配置参数
  46. */
  47. api.base = function (method, url, data, opts) {
  48. return new Promise(async (resolve, reject) => {
  49. const options = Object.assign(
  50. {
  51. // 请求地址
  52. url: pathJoin($config.url.request, url),
  53. // 请求数据
  54. data: data || {},
  55. // 请求类型
  56. method: method || "post",
  57. // 数据类型
  58. dataType: "json",
  59. // 自动显示LOADING
  60. loading: true,
  61. // 启用错误自动拦截
  62. error: true,
  63. // 请求头设定
  64. header: {
  65. "content-type": "application/json",
  66. Authorization: "Bearer " + getAccessToken(), // 修改这里,使用新的获取token方法
  67. },
  68. // 设置显示LOADING的方法
  69. showLoading: showLoading,
  70. // 设置关闭LOADING的方法
  71. hideLoading: hideLoading,
  72. },
  73. opts || {}
  74. );
  75. if (options.loading && typeof options.showLoading == "function") {
  76. options.showLoading();
  77. }
  78. Request(options)
  79. .then(async (res) => {
  80. if (options.loading && typeof options.hideLoading == "function") {
  81. options.hideLoading();
  82. }
  83. switch (res.code) {
  84. // 请求正常
  85. case "00000":
  86. resolve(res);
  87. break;
  88. // 约定401为未登录状态
  89. case "A0230":
  90. try {
  91. // 尝试刷新token
  92. console.log("进入刷新请求");
  93. const refreshResult = await refreshToken();
  94. if (refreshResult) {
  95. // 刷新成功,更新header中的token并重新请求
  96. options.header.token = getAccessToken();
  97. try {
  98. const db = await Request(options);
  99. resolve(db);
  100. } catch (err) {
  101. reject(err);
  102. }
  103. } else {
  104. // 刷新失败,执行登录
  105. // await api.login();
  106. options.header.token = getAccessToken();
  107. try {
  108. const db = await Request(options);
  109. resolve(db);
  110. } catch (err) {
  111. reject(err);
  112. }
  113. }
  114. } catch (err) {
  115. reject(err);
  116. }
  117. break;
  118. // 其他错误请求
  119. default:
  120. if (options.error) {
  121. $app.popup.alert(res.msg || `${url}\r\n未知错误`, "数据请求");
  122. } else {
  123. reject(res);
  124. }
  125. break;
  126. }
  127. })
  128. .catch(async (err) => {
  129. if (err.data.code == "A0230") {
  130. try {
  131. // 尝试刷新token
  132. const refreshResult = await refreshToken();
  133. if (refreshResult) {
  134. // 刷新成功,更新header中的token并重新请求
  135. options.header.token = getAccessToken();
  136. try {
  137. const db = await Request(options);
  138. resolve(db);
  139. } catch (err) {
  140. reject(err);
  141. }
  142. } else {
  143. // 刷新失败,执行登录
  144. $app.popup
  145. .confirm(
  146. `服务器响应失败\r\n${err.data.msg},点击确定去登录`,
  147. "提示",
  148. {
  149. showCancel: true,
  150. }
  151. )
  152. .then((confirmed) => {
  153. if (confirmed) {
  154. uni.navigateTo({ url: "/pages/login/login" });
  155. }
  156. });
  157. }
  158. } catch (err) {
  159. reject(err);
  160. }
  161. } else {
  162. $app.popup.alert(`服务器响应失败\r\n${err.data.msg}`, "数据请求");
  163. }
  164. /*失败处理,此处为非200状态码引起的错误*/
  165. options.hideLoading();
  166. });
  167. });
  168. };
  169. // 新增:获取accessToken的方法
  170. const getAccessToken = function () {
  171. return uni.getStorageSync($config.keyname.accessToken);
  172. };
  173. // 新增:刷新token的方法
  174. const refreshToken = async function () {
  175. const refreshToken = uni.getStorageSync($config.keyname.refreshToken);
  176. console.log("刷新token", refreshToken);
  177. if (!refreshToken) return false;
  178. try {
  179. const res = await Request({
  180. url: pathJoin($config.url.request, $config.api.refreshToken),
  181. method: "post",
  182. data: { refreshToken },
  183. header: {
  184. "content-type": "application/json",
  185. },
  186. });
  187. if (res.code === "00000") {
  188. uni.setStorageSync($config.keyname.accessToken, res.data.accessToken);
  189. uni.setStorageSync($config.keyname.refreshToken, res.data.refreshToken);
  190. return true;
  191. }
  192. return false;
  193. } catch (e) {
  194. return false;
  195. }
  196. };
  197. /**
  198. * POST请求
  199. * @param {String} url 请求地址
  200. * @param {Object} data 请求数据
  201. * @param {Object} opts 配置参数
  202. */
  203. api.post = function (url, data, opts) {
  204. return api.base("post", url, data, Object.assign({}, opts));
  205. };
  206. /**
  207. * GET请求
  208. * @param {String} url 请求地址
  209. * @param {Object} data 请求数据
  210. * @param {Object} opts 配置参数
  211. */
  212. api.get = function (url, data, opts) {
  213. return api.base("get", url, data, Object.assign({}, opts));
  214. };
  215. /**
  216. * PUT请求
  217. * @param {String} url 请求地址
  218. * @param {Object} data 请求数据
  219. * @param {Object} opts 配置参数
  220. */
  221. api.put = function (url, data, opts) {
  222. return api.base("put", url, data, Object.assign({}, opts));
  223. };
  224. /**
  225. * 获取静态数据
  226. * @param {String} url 静态文件地址
  227. * @param {Object} data 参数数据
  228. * @param {Object} opts 配置参数
  229. */
  230. api.static = function (url, data, opts) {
  231. return new Promise(async (resolve, reject) => {
  232. // 设置选项
  233. var _opts = Object.assign(
  234. {
  235. url: /^http/.test(url) ? url : API_BASE + (url || ""),
  236. data: Object.assign({ cache: Date.now() }, data),
  237. },
  238. opts || {}
  239. );
  240. uni.request({
  241. ..._opts,
  242. success: (res) => {
  243. resolve(res.data);
  244. },
  245. });
  246. });
  247. };
  248. /**
  249. * 文件上传
  250. * @param {String} file 文件临时路径
  251. * @param {Object} opts 上传参数
  252. */
  253. api.upload = function (file, opts) {
  254. return new Promise((resolve, reject) => {
  255. const options = Object.assign(
  256. {
  257. // 请求地址
  258. url: pathJoin($config.url.upload, opts?.url || ""),
  259. // 请求数据
  260. filePath: file,
  261. // 自动显示LOADING
  262. loading: true,
  263. // 启用错误自动拦截
  264. error: true,
  265. // 请求头设定
  266. header: {
  267. token: uni.getStorageSync($config.keyname.userToken),
  268. },
  269. // 设置显示LOADING的方法
  270. showLoading: showLoading,
  271. // 设置关闭LOADING的方法
  272. hideLoading: hideLoading,
  273. },
  274. opts || {}
  275. );
  276. });
  277. };
  278. /**
  279. * 获取登录code
  280. */
  281. api.userCode = function () {
  282. return new Promise((resolve, reject) => {
  283. uni.login({
  284. provider: "weixin",
  285. success: (res) => resolve(res.code),
  286. fail: (err) => reject(err),
  287. });
  288. });
  289. };
  290. /**
  291. * 自动登录
  292. * @param {Object} data 登录数据(非必填)
  293. */
  294. api.login = function (data) {
  295. return new Promise(async (resolve, reject) => {
  296. const code = await api.userCode();
  297. api
  298. .post($config.api.login, { ...(data || {}), code })
  299. .then(async (res) => {
  300. // 保存 accessToken 和 refreshToken
  301. uni.setStorageSync($config.keyname.accessToken, res?.data?.accessToken);
  302. uni.setStorageSync(
  303. $config.keyname.refreshToken,
  304. res?.data?.refreshToken
  305. );
  306. // 保留原有的 userInfo 存储
  307. uni.setStorageSync($config.keyname.userInfo, res?.data?.userInfo);
  308. // 返回 accessToken 保持向后兼容
  309. resolve(res.data.accessToken);
  310. })
  311. .catch((err) => reject(err));
  312. });
  313. };
  314. export default api;