diff --git a/klp-ui/src/store/modules/category.js b/klp-ui/src/store/modules/category.js index 42ffac95..1b7bdcba 100644 --- a/klp-ui/src/store/modules/category.js +++ b/klp-ui/src/store/modules/category.js @@ -1,10 +1,18 @@ -import { listCategory } from '@/api/wms/category'; -import { listProduct } from '@/api/wms/product'; -import { listRawMaterial } from '@/api/wms/rawMaterial'; -import { listBomItem } from '@/api/wms/bomItem'; - -// 目前存在一个问题,当新增或删除,修改分类、产品、物料时,需要刷新整个页面,才能看到最新的数据 -// 需要优化,当新增或删除,修改分类、产品、物料时,只刷新相关的数据,而不是整个页面,修改和删除可以解决,新增由于没有返回id,所以需要重新获取整个列表 +// import { listCategory } from '@/api/wms/category'; +// import { listBomItem } from '@/api/wms/bomItem'; +// import { listProduct } from '@/api/wms/product'; +// import { listRawMaterial } from '@/api/wms/rawMaterial'; +import veilReq from '@/utils/veilReq'; +const listRawMaterial = (params) => veilReq({ + url: '/wms/rawMaterial/list', + method: 'get', + params +}); +const listProduct = (params) => veilReq({ + url: '/wms/product/list', + method: 'get', + params +}); const state = { categoryList: [], @@ -53,15 +61,37 @@ const actions = { return Promise.resolve(state.productMap); } - const pageSize = 2000; // 每次获取2000条 + const pageSize = 5000; // 每次获取5000条 const allRows = []; // 存储所有批次的列表数据 const productMap = {}; // 最终的产品映射表 + const maxRetries = 5; // 最大重试次数 + + // 带重试机制的请求函数 + const fetchWithRetry = async (pageNum) => { + let retries = 0; + while (retries < maxRetries) { + try { + // 尝试调用接口 + const res = await listProduct({ pageNum, pageSize }); + return res; // 成功则返回结果 + } catch (error) { + retries++; + if (retries >= maxRetries) { + // 达到最大重试次数,抛出错误 + throw new Error(`获取第${pageNum}页产品数据失败,已重试${maxRetries}次: ${error.message}`); + } + // 可选:添加重试间隔(如1秒),避免频繁请求 + await new Promise(resolve => setTimeout(resolve, 1000)); + console.log(`获取第${pageNum}页失败,正在进行第${retries}次重试...`); + } + } + }; // 异步处理分批次获取逻辑 const fetchAllProducts = async () => { - // 1. 获取第一页数据,拿到总条数total + // 1. 获取第一页数据,拿到总条数total(带重试) let currentPage = 1; - const firstRes = await listProduct({ pageNum: currentPage, pageSize }); + const firstRes = await fetchWithRetry(currentPage); const total = firstRes.total || 0; const firstRows = firstRes.rows || []; @@ -71,10 +101,10 @@ const actions = { productMap[item.productId.toString()] = item; }); - // 2. 计算总页数,循环获取剩余页面数据 + // 2. 计算总页数,循环获取剩余页面数据(每一页都带重试) const totalPages = Math.ceil(total / pageSize); for (currentPage = 2; currentPage <= totalPages; currentPage++) { - const res = await listProduct({ pageNum: currentPage, pageSize }); + const res = await fetchWithRetry(currentPage); const rows = res.rows || []; // 合并当前页数据到总列表和映射表 @@ -100,15 +130,37 @@ const actions = { return Promise.resolve(state.rawMaterialMap); } - const pageSize = 2000; // 每次获取2000条 + const pageSize = 5000; // 每次获取5000条 const allRows = []; // 存储所有批次的原材料列表 const rawMaterialMap = {}; // 最终的原材料映射表 + const maxRetries = 5; // 最大重试次数 + + // 带重试机制的请求函数(针对原材料接口) + const fetchWithRetry = async (pageNum) => { + let retries = 0; + while (retries < maxRetries) { + try { + // 尝试调用原材料列表接口 + const res = await listRawMaterial({ pageNum, pageSize }); + return res; // 成功则返回结果 + } catch (error) { + retries++; + if (retries >= maxRetries) { + // 达到最大重试次数,抛出错误(包含具体页码) + throw new Error(`获取第${pageNum}页原材料数据失败,已重试${maxRetries}次: ${error.message}`); + } + // 重试间隔1秒,避免频繁请求 + await new Promise(resolve => setTimeout(resolve, 1000)); + console.log(`获取第${pageNum}页原材料失败,正在进行第${retries}次重试...`); + } + } + }; // 异步处理分批次获取逻辑 const fetchAllRawMaterials = async () => { - // 1. 获取第一页数据,拿到总条数total + // 1. 获取第一页数据(带重试) let currentPage = 1; - const firstRes = await listRawMaterial({ pageNum: currentPage, pageSize }); + const firstRes = await fetchWithRetry(currentPage); const total = firstRes.total || 0; const firstRows = firstRes.rows || []; @@ -118,27 +170,27 @@ const actions = { rawMaterialMap[item.rawMaterialId.toString()] = item; }); - // 2. 计算总页数,循环获取剩余页面数据 + // 2. 循环获取剩余页面数据(每一页都带重试) const totalPages = Math.ceil(total / pageSize); for (currentPage = 2; currentPage <= totalPages; currentPage++) { - const res = await listRawMaterial({ pageNum: currentPage, pageSize }); + const res = await fetchWithRetry(currentPage); const rows = res.rows || []; - // 合并当前页数据到总列表和映射表 + // 合并当前页数据 allRows.push(...rows); rows.forEach(item => { rawMaterialMap[item.rawMaterialId.toString()] = item; }); } - // 3. 所有数据获取完成后,更新状态 + // 3. 更新状态 commit('SET_RAW_MATERIAL_MAP', rawMaterialMap); commit('SET_RAW_MATERIAL_LIST', allRows); return rawMaterialMap; }; - // 返回Promise,确保外部可通过.then获取结果 + // 返回Promise供外部调用 return fetchAllRawMaterials(); }, getBomMap({ state, commit }) { diff --git a/klp-ui/src/utils/veilReq.js b/klp-ui/src/utils/veilReq.js new file mode 100644 index 00000000..7422a87f --- /dev/null +++ b/klp-ui/src/utils/veilReq.js @@ -0,0 +1,101 @@ +import axios from 'axios' +import { MessageBox } from 'element-ui' +import store from '@/store' +import { getToken } from '@/utils/auth' +import errorCode from '@/utils/errorCode' +import { tansParams, } from "@/utils/klp"; +import cache from '@/plugins/cache' + +// 创建axios实例 +const service = axios.create({ + // axios中请求配置有baseURL选项,表示请求URL公共部分 + baseURL: process.env.VUE_APP_BASE_API, + // 超时 + timeout: 600000 +}) + +// request拦截器 +service.interceptors.request.use(config => { + // 是否需要设置 token + const isToken = (config.headers || {}).isToken === false + // 是否需要防止数据重复提交 + const isRepeatSubmit = (config.headers || {}).repeatSubmit === false + if (getToken() && !isToken) { + config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 + } + // get请求映射params参数 + if (config.method === 'get' && config.params) { + let url = config.url + '?' + tansParams(config.params); + url = url.slice(0, -1); + config.params = {}; + config.url = url; + } + if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { + const requestObj = { + url: config.url, + data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, + time: new Date().getTime() + } + const sessionObj = cache.session.getJSON('sessionObj') + if (sessionObj === undefined || sessionObj === null || sessionObj === '') { + cache.session.setJSON('sessionObj', requestObj) + } else { + const s_url = sessionObj.url; // 请求地址 + const s_data = sessionObj.data; // 请求数据 + const s_time = sessionObj.time; // 请求时间 + const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交 + if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) { + const message = '数据正在处理,请勿重复提交'; + console.warn(`[${s_url}]: ` + message) + return Promise.reject(new Error(message)) + } else { + cache.session.setJSON('sessionObj', requestObj) + } + } + } + return config +}, error => { + console.log(error) + Promise.reject(error) +}) + +// 响应拦截器 +service.interceptors.response.use(res => { + // 未设置状态码则默认成功状态 + const code = res.data.code || 200; + // 获取错误信息 + const msg = errorCode[code] || res.data.msg || errorCode['default'] + // 二进制数据则直接返回 + if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') { + return res.data + } + if (code === 401) { + if (!isRelogin.show) { + isRelogin.show = true; + MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { + isRelogin.show = false; + store.dispatch('LogOut').then(() => { + location.href = process.env.VUE_APP_CONTEXT_PATH + "index"; + }) + }).catch(() => { + isRelogin.show = false; + }); + } + return Promise.reject('无效的会话,或者会话已过期,请重新登录。') + } else if (code === 500) { + return Promise.reject(new Error(msg)) + } else if (code === 601) { + return Promise.reject('error') + } else if (code !== 200) { + return Promise.reject('error') + } else { + return res.data + } + }, + error => { + console.log('err' + error) + return Promise.reject(error) + } +) + +export default service \ No newline at end of file