import { getToken } from '@/utils/auth'; import errorCode from '@/utils/errorCode'; import { tansParams } from '@/utils/common'; import config from '@/config'; import { getCurrentPage } from '@/utils/public'; import { useInfoStore } from '@/store'; interface UploadConfig { url: string; filePath: string; name?: string; header?: Record; headers?: Record; formData?: Record; params?: Record; timeout?: number; } interface UploadResult { code: number; data?: any; msg?: string; } const timeout = 10000; const { baseUrl, clientId, appid } = config; const upload = (uploadConfig: UploadConfig): Promise => { // 是否需要设置 token const isToken = (uploadConfig.headers || {}).isToken === false; uploadConfig.header = uploadConfig.header || {}; if (getToken() && !isToken) { uploadConfig.header['Authorization'] = 'Bearer ' + getToken(); } uploadConfig.header['Clientid'] = clientId; // 默认值 uploadConfig.header['xid'] = appid; // 默认值 // get请求映射params参数 if (uploadConfig.params) { let url = uploadConfig.url + '?' + tansParams(uploadConfig.params); url = url.slice(0, -1); uploadConfig.url = url; } return new Promise((resolve, reject) => { uni.uploadFile({ timeout: uploadConfig.timeout || timeout, url: baseUrl + uploadConfig.url, filePath: uploadConfig.filePath, name: uploadConfig.name || 'file', header: uploadConfig.header, formData: uploadConfig.formData, success: (res) => { const result: UploadResult = JSON.parse(res.data); const code = result.code || 200; const msg = errorCode[code.toString()] || result.msg || errorCode['default']; if (code === 200) { resolve(result); } else if (code === 401) { uni.hideLoading(); // 跳转到登录页面 uni.$u.route({ type: 'reLaunch', url: '/pages/login/login', params: { redirect: getCurrentPage()?.route || '', }, }); reject('无效的会话,或者会话已过期,请重新登录。'); } else if (code === 500) { uni.showToast({ title: msg, icon: 'none', }); reject('500'); } else if (code !== 200) { uni.showToast({ title: msg, icon: 'none', }); reject(code); } }, fail: (error) => { console.log(error); let message = '上传失败'; if (error.errMsg) { if (error.errMsg.includes('timeout')) { message = '系统接口请求超时'; } else if (error.errMsg.includes('fail')) { message = '网络连接异常'; } } uni.showToast({ title: message, icon: 'none', }); reject(error); }, }); }); }; /** * 获取文件扩展名 * @param {string} url - 文件 URL * @param {object} [result] - 响应结果对象 * @param {object} [result.header] - 响应头 * @returns {string|null} 文件扩展名(不带点),找不到则返回 null */ const getFileType = (url: string, result?: { header?: Record }): string | null => { // 1. 首先尝试从 URL 获取扩展名 if (url) { // 获取 URL 中最后一个斜杠后的文件名 const filenameFromUrl = url.split('/').pop(); // 提取扩展名(处理可能存在的查询参数) const urlExt = filenameFromUrl?.includes('.') ? filenameFromUrl.split('.').pop()?.split(/[?#]/)[0] : null; if (urlExt) return urlExt.toLowerCase() || 'pdf'; } // 2. 如果 URL 中没有扩展名,尝试从 Content-Disposition 头获取 if (result?.header?.['content-disposition']) { try { const disposition = result.header['content-disposition']; // 匹配 filename="file.ext" 或 filename*=UTF-8''file.ext 格式 const filenameMatch = disposition.match(/filename\*?=(?:UTF-8''|")?([^;"\n]*)/i); if (filenameMatch && filenameMatch[1]) { const filename = filenameMatch[1].replace(/['"]/g, ''); if (filename.includes('.')) { const ext = filename.split('.').pop()?.split(/[?#]/)[0]; return ext?.toLowerCase() || 'pdf'; } } } catch (e) { console.warn('解析 Content-Disposition 失败:', e); } } // 3. 都找不到则返回 pdf 作为默认值 return 'pdf'; }; // 导出数据函数(按照 handleDownload 规范完善) export const exportDataFn = (config: { url: string; fileName?: string; params?: Record; timeout?: number }, showTitle?: string): Promise => new Promise((resolve, reject) => { // 判断是否为完整 URL(以 http://或 https://开头) const isFullUrl = config.url.startsWith('http://') || config.url.startsWith('https://'); // 获取基础 URL 并拼接完整路径 const baseUrl = isFullUrl ? '' : import.meta.env.VITE_API_BASE_URL || config.url.split('/').slice(0, 3).join('/'); const downloadUrl = baseUrl + config.url; // 获取 token const token = useInfoStore().token; // 设置请求头 const header = { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, xid: appid, clientId: clientId, }; uni.showLoading({ title: showTitle || '正在导出数据...', mask: true, }); uni.downloadFile({ url: downloadUrl, header: header, success: (res) => { uni.hideLoading(); if (res.statusCode === 200) { // 直接打开文件 uni.openDocument({ filePath: res.tempFilePath, showMenu: true, fileType: getFileType(config.fileName || config.url, res as any) as any, success: () => { resolve(); }, fail: (err) => { console.log('打开文档失败:', err); uni.showToast({ title: '打开文件失败', icon: 'none', }); reject(err); }, }); } else { uni.showToast({ title: '下载失败', icon: 'none', }); reject(res); } }, fail: () => { uni.hideLoading(); uni.showToast({ title: '下载失败', icon: 'none', }); reject(); }, }); }); export default upload;