| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- // 基础配置
- import { showLoading, hideLoading } from '@/hooks/useLoading'
- import config1 from "@/config";
- import ls from "@/utils/store2";
- const baseUrl = config1.Host85;
- const timeout = 60000;
- // 不加loading
- const urlLoading = ['/list', '/page', '/field/params', '/dropdown', '/single', '/detail']
- import { CLIENT, lang, userToken, shopToken } from "@/composables/config";
- const LOGIN_PAGE_PATH = "/pages/login/index";
- // import useGlobalStore from "@/stores/use-global-store";
- import useUserStore from "@/stores/use-user-store";
- // const globalStore = useGlobalStore()
- export const getCurrentPageUrl = () => {
- const pages = getCurrentPages(); // UniApp获取当前页面栈
- const currentPage = pages[pages.length - 1];
- return currentPage.route; // 返回当前页面路径(如:pages/login/index)
- };
- // 请求拦截器
- const requestInterceptor = (config) => {
- if (!config.header) {
- config.header = {};
- }
- switch (config.type) {
- case 'HostShop':
- if (shopToken.value) {
- config.header["Access-Token"] = `${shopToken.value}`;
- }
- break;
- default:
- if (userToken.value) {
- config.header["Access-Token"] = `${userToken.value}`;
- }
- break;
- }
- if (lang.value) {
- config.header.Language = `${lang.value}`;
- }
- if (CLIENT.value) {
- config.header.CLIENT = `${CLIENT.value}`;
- }
- const userStore = useUserStore();
- const cId = userStore.userInfo?.cId;
- const method = String(config.method || "GET").toUpperCase();
- if (method === "GET") {
- config.data = { ...(config.data || {}) };
- } else {
- config.data = { ...(config.data || {}) };
- }
- if (!config.header["Content-Type"]) {
- config.header["Content-Type"] = "application/json";
- }
- return config;
- };
- // 记录是否正在跳转登录页
- let isRedirectingToLogin = false;
- // 响应拦截器
- const responseInterceptor = (response, options = {}) => {
- const { data, statusCode } = response;
- // 处理业务错误
- if (statusCode === 200) {
- if (options.responseType === "arraybuffer" || data instanceof ArrayBuffer) {
- return data;
- }
- // 1. 捕获 401 未授权错误
- if (data.code === 401 || data.code === 600) {
- // 关键:判断当前页面是否为登录页,避免循环跳转
- const currentPage = getCurrentPageUrl();
- if (currentPage === LOGIN_PAGE_PATH) {
- return Promise.reject({
- ...data,
- msg: data.message || "登录失败,请重试",
- });
- }
- userToken.value = "";
- // 3. 判断是否需要跳转登录(支持单个请求忽略跳转)
- const ignore401 = options.ignore401 || false; // 单个请求的配置
- if (ignore401) {
- return Promise.reject({
- ...data,
- code: 401,
- });
- }
-
- // 4. 提示并跳转登录页(防抖/防重复跳转处理)
- if (!isRedirectingToLogin) {
- isRedirectingToLogin = true;
- uni.showToast({
- title: "登录已过期,请重新登录",
- icon: "none",
- });
-
- uni.$emit('logout');
-
- setTimeout(() => {
- uni.reLaunch({
- url: LOGIN_PAGE_PATH,
- success: () => {
- uni.setStorageSync('logoutToSystem',1)
- ls.set('mode', 'customer');
- // globalStore.setMode('customer');
- // uni.clearStorageSync()
- isRedirectingToLogin = false;
- },
- fail: () => {
- isRedirectingToLogin = false;
- }
- });
- }, 1500);
- }
-
- return Promise.reject({
- ...data,
- code: 401,
- message: "登录已过期,请重新登录",
- });
- }
- if (data.code === 200) {
- return data;
- } else if (data.code === 400) {
- return Promise.reject(data);
- } else {
- uni.showToast({
- title: data.msg || "请求失败",
- icon: "none",
- });
- return Promise.reject(data);
- }
- } else {
- uni.showToast({
- title: `网络错误: ${statusCode}`,
- icon: "none",
- });
- return Promise.reject(response);
- }
- };
- // 错误处理
- const errorHandler = (error) => {
- uni.hideLoading();
- uni.showToast({
- title: "网络异常,请稍后重试",
- icon: "none",
- });
- return Promise.reject(error);
- };
- // 核心请求函数
- export const request = (options) => {
- // const host = config1[options.type || 'Host85'] || '';
- const host = config1[options.type || 'Host80'] || '';
- // 合并配置
- const config = {
- ...options,
- url: `${host}${options.url}`,
- method: options.method || "GET",
- timeout,
- };
- // 应用请求拦截器
- const processedConfig = requestInterceptor(config);
- return new Promise((resolve, reject) => {
- const needLoading = urlLoading.some(item => config.url.includes(item));
- if (!needLoading) {
- // showLoading();
- }
- uni.request({
- ...processedConfig,
- success: (response) => {
- try {
- const result = responseInterceptor(response, options);
- resolve(result);
- } catch (err) {
- reject(err);
- } finally {
- if (!needLoading) {
- // hideLoading();
- }
- }
- },
- fail: (error) => {
- const handledError = errorHandler(error);
- reject(handledError);
- if (!needLoading) {
- // hideLoading();
- }
- },
- });
- });
- };
- // ---------------------- 图片上传封装(新增)----------------------
- /**
- * 图片上传函数
- * @param {Object} options - 上传配置
- * @param {string} options.url - 上传接口路径(如 /Upload/Image)
- * @param {string|string[]} options.filePath - 图片临时路径(单文件:字符串;多文件:数组)
- * @param {string} [options.name=file] - 后端接收文件的字段名(默认file,需与后端一致)
- * @param {Object} [options.formData={}] - 额外表单参数(如业务ID、类型)
- * @param {Function} [options.onProgressUpdate] - 进度监听函数(可选)
- * @returns {Promise} - 上传结果
- */
- export const upload = (options) => {
- // 1. 处理基础配置
- const uploadConfig = {
- ...options,
- url: `${baseUrl}${options.url}`, // 完整上传接口地址
- timeout,
- name: options.name || "file", // 后端接收文件的字段名(默认file)
- filePath: options.filePath, // 图片临时路径
- formData: options.formData || {}, // 额外表单参数
- onProgressUpdate: options.onProgressUpdate, // 进度监听(可选)
- };
- // 2. 应用请求拦截器(添加token等header)
- const processedConfig = requestInterceptor(uploadConfig);
- // 3. 区分单文件/多文件上传
- return new Promise((resolve, reject) => {
- // 多文件上传(filePath为数组)
- if (Array.isArray(processedConfig.filePath)) {
- // 批量调用uni.uploadFile,并行上传
- const uploadPromises = processedConfig.filePath.map((filePath) => {
- return new Promise((innerResolve, innerReject) => {
- uni.uploadFile({
- ...processedConfig,
- filePath, // 单个文件路径
- success: (res) => {
- // 注意:uni.uploadFile的res.data是字符串,需转为JSON
- res.data = JSON.parse(res.data || "{}");
- try {
- const result = responseInterceptor(res);
- innerResolve(result);
- } catch (err) {
- innerReject(err);
- }
- },
- fail: (err) => innerReject(errorHandler(err)),
- });
- });
- });
- // 所有文件上传完成后 resolve
- Promise.all(uploadPromises).then(resolve).catch(reject);
- }
- // 单文件上传(filePath为字符串)
- else {
- uni.uploadFile({
- ...processedConfig,
- success: (res) => {
- res.data = JSON.parse(res.data || "{}"); // 转为JSON
- try {
- const result = responseInterceptor(res);
- resolve(result);
- } catch (err) {
- reject(err);
- }
- },
- fail: (err) => reject(errorHandler(err)),
- });
- }
- });
- };
- /**
- * 兼容性上传函数(按需直接调用)
- * @param {string} url - 接口相对路径,如 `/wasabi/api/upload/file`
- * @param {string|Object|File} file - 文件路径(临时路径字符串)或包含 path/url/tempFilePath 的对象或 File
- * @param {Object} [data] - 额外表单字段
- * @param {Object} [header] - 额外请求头
- * @param {boolean} [checkCode=true] - 是否走响应码检查(默认走)
- */
- export const uploadFile = (url, file, data = {}, header = {}, checkCode = true) => {
- return new Promise((resolve, reject) => {
- try {
- // 提取文件路径
- let filePath = file;
- if (file && typeof file === "object") {
- filePath = file.path || file.url || file.tempFilePath || file.filePath || file;
- }
- const finalUrl = `${baseUrl}${url}`;
- // 构建 headers,优先使用传入 header
- const headers = {
- ...(header || {}),
- };
- if (userToken.value) headers["Access-Token"] = `${userToken.value}`;
- if (lang.value) headers["Language"] = `${lang.value}`;
- if (CLIENT.value) headers["CLIENT"] = `${CLIENT.value}`;
- uni.uploadFile({
- url: finalUrl,
- filePath: filePath,
- name: "file",
- header: headers,
- formData: data || {},
- success: (res) => {
- try {
- // uni.uploadFile 的 res.data 是字符串
- res.data = JSON.parse(res.data || "{}");
- } catch (e) {
- res.data = {};
- }
- // 适配 responseInterceptor 接口
- const resp = { data: res.data, statusCode: res.statusCode };
- if (checkCode) {
- try {
- const result = responseInterceptor(resp);
- resolve(result);
- } catch (err) {
- reject(err);
- }
- } else {
- resolve(resp.data);
- }
- },
- fail: (err) => {
- reject(errorHandler(err));
- },
- });
- } catch (err) {
- reject(err);
- }
- });
- };
- // 快捷方法
- export const get = (url, data = {}, typeOrOptions = {}, options = {}) => {
- const mergedOptions =
- typeof typeOrOptions === "string"
- ? { type: typeOrOptions, ...(options || {}) }
- : (typeOrOptions || {});
- return request({
- url,
- method: "GET",
- data,
- ...mergedOptions,
- });
- };
- export const post = (url, data = {}, type, options = {}) => {
- return request({
- url,
- method: "POST",
- data,
- type,
- ...options,
- });
- };
|