micro_request.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * @Date: 2021-11-27 15:27:19
  3. * @LastEditors: wanglj
  4. * @LastEditTime: 2024-03-13 16:34:10
  5. * @FilePath: \labsop_backup\frontend\packages\base\src\utils\micro_request.js
  6. * @Description: file content
  7. */
  8. import { Local, Session } from '@/utils/storage';
  9. import { CACHE_KEY } from '@/constants';
  10. const errorCode = {
  11. '401': '认证失败,无法访问系统资源',
  12. '403': '当前操作没有权限',
  13. '404': '访问资源不存在',
  14. 'default': '系统未知错误,请反馈给管理员'
  15. };
  16. const baseURL = import.meta.env.VITE_API_URL || '';
  17. function request(options) {
  18. // 拼接请求路径
  19. let url = options.url || '';
  20. if (!/^\/?http/.test(url)) {
  21. url = baseURL + url;
  22. }
  23. // 头部处理
  24. let header = Object.assign({}, options.headers, options.header);
  25. header['Content-Type'] = header['Content-Type'] || 'application/json;charset=utf-8';
  26. if (import.meta.env.VITE_TENANT) {
  27. header['Tenant'] = import.meta.env.VITE_TENANT;
  28. }
  29. // 是否需要设置 token
  30. const isToken = header.isToken === false;
  31. const token = Local.get(CACHE_KEY.TOKEN);
  32. if (token && !isToken) {
  33. header['Authorization'] = 'Bearer ' + token;
  34. }
  35. // uni.request 只有在 Content-Type 为 application/json 时才自动对对象执行 JSON.stringify
  36. // 对于 application/rpcx,需要手动序列化,否则会被 toString() 处理成 [object Object]
  37. let requestData = options.data;
  38. if (typeof requestData === 'object' && requestData !== null && header['Content-Type'] === 'application/rpcx') {
  39. requestData = JSON.stringify(requestData);
  40. }
  41. return new Promise((resolve, reject) => {
  42. uni.request({
  43. url: url,
  44. method: (options.method || 'GET').toUpperCase(),
  45. data: requestData,
  46. header: header,
  47. timeout: options.timeout || 60000,
  48. responseType: options.responseType || 'text',
  49. success: (res) => {
  50. // 文件流处理
  51. if (options.responseType === 'arraybuffer' || res.header?.['content-type']?.includes('application/octet-stream')) {
  52. downLoadBlobFile(res, options);
  53. resolve(res.data);
  54. return;
  55. }
  56. processResponse(res, resolve, reject);
  57. },
  58. fail: (err) => {
  59. console.log('err: ', err);
  60. uni.showToast({
  61. title: err.errMsg || '网络环境异常,请稍后重试',
  62. icon: 'none',
  63. duration: 3000
  64. });
  65. reject(err);
  66. }
  67. });
  68. });
  69. }
  70. function processResponse(res, resolve, reject) {
  71. const data = res.data || {};
  72. // 未设置状态码则默认成功状态
  73. const code = data.code || res.statusCode || 200;
  74. // 获取错误信息
  75. const message = errorCode[code] || data.message || data.msg || errorCode['default'];
  76. if (code === 401) {
  77. uni.showModal({
  78. title: '系统提示',
  79. content: '登录状态已过期,您可以继续留在该页面,或者重新登录',
  80. confirmText: '重新登录',
  81. cancelText: '取消',
  82. success: function (modalRes) {
  83. if (modalRes.confirm) {
  84. // 清除缓存/token等
  85. Session.clear();
  86. Local.remove(CACHE_KEY.TOKEN);
  87. // 重新定向到登录页
  88. uni.reLaunch({
  89. url: '/pages/login/index'
  90. });
  91. }
  92. }
  93. });
  94. reject(new Error(message));
  95. } else if (code === 500) {
  96. uni.showToast({
  97. title: message,
  98. icon: 'none',
  99. duration: 2000
  100. });
  101. reject(new Error(message));
  102. } else if (code !== 200) {
  103. uni.showToast({
  104. title: message,
  105. icon: 'none',
  106. duration: 2000
  107. });
  108. reject(new Error(message));
  109. } else {
  110. // 返回真实的业务数据,此处直接返回 data(也可根据业务需要只回 data.data)
  111. resolve(data);
  112. }
  113. }
  114. function downLoadBlobFile(res, options) {
  115. let mimeType = options.mimeType || 'application/vnd.ms-excel';
  116. let fileName = 'data.xlsx';
  117. // 尝试从header中获取文件名
  118. const header = res.header || {};
  119. let contentDisposition = header['content-disposition'] || header['Content-Disposition'];
  120. if (contentDisposition) {
  121. let patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*');
  122. let result = patt.exec(decodeURI(contentDisposition));
  123. if (result && result.length > 1) {
  124. fileName = result[1];
  125. fileName = decodeURI(escape(fileName));
  126. fileName = fileName.replace(/\"/g, '');
  127. }
  128. }
  129. // #ifdef H5
  130. const blob = new Blob([res.data], { type: mimeType });
  131. const aLink = document.createElement('a');
  132. aLink.href = URL.createObjectURL(blob);
  133. aLink.setAttribute('download', fileName);
  134. document.body.appendChild(aLink);
  135. aLink.click();
  136. document.body.removeChild(aLink);
  137. // #endif
  138. // #ifndef H5
  139. // 非H5平台(小程序、APP等)需要使用原生的文件保存及打开API
  140. const fs = uni.getFileSystemManager ? uni.getFileSystemManager() : null;
  141. if (fs && res.data) {
  142. const filePath = `${uni.env.USER_DATA_PATH}/${fileName}`;
  143. fs.writeFile({
  144. filePath: filePath,
  145. data: res.data,
  146. encoding: 'binary',
  147. success: () => {
  148. uni.openDocument({
  149. filePath: filePath,
  150. showMenu: true,
  151. success: function () {
  152. console.log('打开文档成功');
  153. }
  154. });
  155. },
  156. fail: (err) => {
  157. uni.showToast({ title: '保存文件失败', icon: 'none' });
  158. }
  159. });
  160. } else {
  161. uni.showToast({
  162. title: '文件已下载,但当前平台暂不支持直接打开',
  163. icon: 'none',
  164. duration: 3000
  165. });
  166. }
  167. // #endif
  168. }
  169. request.postRequest = function postRequest(basePath, srvName, funcName, data) {
  170. if (data == undefined) {
  171. data = { nullparam: 0 };
  172. }
  173. return request({
  174. url: basePath,
  175. method: 'post',
  176. headers: {
  177. 'Content-Type': 'application/rpcx',
  178. 'X-RPCX-SerializeType': '1',
  179. 'X-RPCX-ServicePath': srvName,
  180. 'X-RPCX-ServiceMethod': funcName,
  181. Srvenv: 'dev',
  182. },
  183. data: data,
  184. });
  185. };
  186. // 发出请求并要求把客户端信息传输给后端(IP和User-Agent)
  187. request.postRequestWithClientInfo = function postRequestWithClientInfo(basePath, srvName, funcName, data) {
  188. if (data == undefined) {
  189. data = { nullparam: 0 };
  190. }
  191. return request({
  192. url: basePath,
  193. method: 'post',
  194. headers: {
  195. 'Content-Type': 'application/rpcx',
  196. 'X-RPCX-SerializeType': '1',
  197. 'X-RPCX-ServicePath': srvName,
  198. 'X-RPCX-Meta': 'need_clint_Info=1',
  199. Srvenv: import.meta.env.VITE_SRV_ENV || 'dev',
  200. },
  201. data: data,
  202. });
  203. };
  204. // Excel文件下载(服务端生成文件流)
  205. request.downloadExcel = function downloadExcel(basePath, srvName, funcName, data) {
  206. if (data == undefined) {
  207. data = { nullparam: 0 };
  208. }
  209. let base_Path = '';
  210. // 使用 import.meta.env 替换 process.env
  211. if (basePath == import.meta.env.VITE_APP_FOSHAN_PATH) {
  212. base_Path = (import.meta.env.VITE_APP_MicroSrvProxy_foshan_API || '') + basePath;
  213. } else if (basePath == import.meta.env.VITE_APP_AdminPath) {
  214. base_Path = (import.meta.env.VITE_APP_MicroSrvProxy_API || '') + basePath;
  215. } else {
  216. base_Path = basePath;
  217. }
  218. return request({
  219. url: base_Path,
  220. method: 'post',
  221. responseType: 'arraybuffer', // uniapp中使用 arraybuffer 替代 blob下载文件
  222. headers: {
  223. 'Content-Type': 'application/rpcx',
  224. 'X-RPCX-SerializeType': '1',
  225. 'X-RPCX-ServicePath': srvName,
  226. 'X-RPCX-ServiceMethod': funcName,
  227. Srvenv: 'dev',
  228. },
  229. data: data,
  230. });
  231. };
  232. export default request;