import { request } from './index'; import $storage from '@/sheep/utils/storage'; import { ElMessage } from 'element-plus'; // 检测是否为mall前缀的接口 const isMallAPI = (url) => { return url.startsWith('/mall') || url.startsWith('mall'); }; // 查看列表 export const LIST = (url, data) => { const requestConfig = { url: url + `/list`, method: 'POST', }; requestConfig.data = data; return request(requestConfig); }; // 查看详情 export const DETAIL = (url, id) => { const isMall = isMallAPI(url); return request({ url: url + `/detail`, method: isMall ? 'GET' : 'POST', // mall用GET,其他用POST params: { id }, }); }; // 新增 export const ADD = (url, data) => request({ url: url + '/add', method: 'POST', data, options: { showSuccessMessage: false, }, }); // 编辑&更新 export const EDIT = (url, data) => { const isMall = isMallAPI(url); return request({ url: url + `/update`, method: isMall ? 'PUT' : 'POST', // mall用PUT,其他用POST data, options: { showSuccessMessage: false, }, }); }; // 删除(软删除/真实删除) export const DELETE = (url, data) => { const isMall = isMallAPI(url); return request({ url: url + `/delete`, method: isMall ? 'DELETE' : 'POST', // mall用DELETE,其他用POST params: data, options: { showSuccessMessage: true, }, }); }; // 选择 export const SELECT = (url, params) => request({ url: url + '/select', method: 'GET', params, }); // 回收站列表 export const RECYCLE_BIN = (url, params) => request({ url: url + '/recyclebin', method: 'GET', params, }); // 销毁 export const DESTROY = (url, id) => request({ url: url + '/destroy/' + id, method: 'DELETE', }); // 还原 export const RESTORE = (url, id) => request({ url: url + '/restore/' + id, method: 'PUT', }); // 通用增删改查 export const CRUD = ( url, methods = ['list', 'detail', 'add', 'edit', 'delete', 'export'], options = {}, ) => { const apis = {}; if (methods.includes('list')) apis.list = (params, pageInParams = true) => LIST(url, params, pageInParams); if (methods.includes('detail')) apis.detail = (id) => DETAIL(url, id); if (methods.includes('add')) apis.add = (data) => ADD(url, data); if (methods.includes('edit')) apis.edit = (id, data) => EDIT(url, id, data); if (methods.includes('delete')) apis.delete = (id) => DELETE(url, id); if (methods.includes('report')) apis.report = (params, filename) => REPORT(url, params, filename, 'report', options.reportMethod); if (methods.includes('export')) apis.export = (params, filename) => REPORT(url, params, filename, 'export', options.exportMethod); return apis; }; // 通用回收站 export const RECYCLE = (url) => { return { recyclebin: (params) => RECYCLE_BIN(url, params), restore: (id) => RESTORE(url, id), destroy: (id) => DESTROY(url, id), }; }; // 导出报表 - 需要超级管理员权限 export const REPORT = async ( url, params, filename = '导出数据', typeName = 'report', method = null, ) => { // 获取用户信息进行权限验证 const userInfo = $storage.get('userInfo'); // 检查用户是否为超级管理员 if (!userInfo || userInfo.roleName !== '超级管理员') { ElMessage.error('只有超级管理员可以导出'); return Promise.reject(new Error('权限不足:只有超级管理员可以导出')); } // 确定HTTP方法:优先使用传入的method参数,否则使用默认逻辑 const httpMethod = method || (typeName == 'report' ? 'GET' : 'POST'); let response = null; try { // 发送导出请求 response = await request({ url: url + `/${typeName}`, method: httpMethod, ...(httpMethod === 'GET' ? { params } : { data: params }), responseType: 'blob', // 用于文件下载 headers: { Accept: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/octet-stream, */*', }, options: { showSuccessMessage: false, }, }); // 检查响应状态和内容类型 if (response.status === 200 && response.headers['content-type']?.includes('excel')) { // 成功响应,处理文件下载 const blob = response.data; // 从响应对象中获取 Blob 数据 const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; // 优先从响应头的 content-disposition 中获取文件名 let finalFilename = `${filename}_${new Date().toISOString().slice(0, 10)}.xlsx`; // 尝试多种方式获取 content-disposition const contentDisposition = response.headers['content-disposition'] || response.headers['Content-Disposition'] || response.headers.get?.('content-disposition') || response.headers.get?.('Content-Disposition'); if (contentDisposition) { // 尝试从 content-disposition 中提取文件名 const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); if (filenameMatch && filenameMatch[1]) { let extractedFilename = filenameMatch[1].replace(/['"]/g, ''); // 处理 URL 编码的文件名 try { extractedFilename = decodeURIComponent(extractedFilename); } catch (e) { // 如果解码失败,使用原始文件名 } if (extractedFilename) { finalFilename = extractedFilename; } } } link.download = finalFilename; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(downloadUrl); ElMessage.success('导出成功'); return Promise.resolve(); } else { // 如果不是成功的文件响应,说明返回的是错误信息 let errorData; try { // 尝试解析 Blob 中的 JSON 错误信息 const text = await response.data.text(); errorData = JSON.parse(text); } catch (parseError) { // 如果解析失败,使用默认错误信息 errorData = { code: '500', message: '导出失败' }; } // 检查返回的 code // if (errorData.code !== '200') { // const errorMessage = errorData.message || '导出失败'; // ElMessage.error(errorMessage); // return Promise.reject(new Error(errorMessage)); // } } } catch (error) { console.error('导出失败:', error); // 如果是网络错误或其他异常 if (error.response) { // 有响应但状态码不是 2xx const errorMessage = error.response.data?.message || '服务器错误'; ElMessage.error(errorMessage); } else if (error.message?.includes('权限不足')) { // 权限错误已经在上面处理了,不需要重复提示 } else { // 其他错误 ElMessage.error('导出失败,请稍后重试'); } return Promise.reject(error); } }; // add, list, delete, edit, detail, select, recyclebin, restore, destroy, report