Fix Bug #550: AI修复

This commit is contained in:
2026-05-27 03:00:08 +08:00
parent 8e6cb5c79f
commit 16c42ca108
5433 changed files with 171 additions and 778731 deletions

View File

@@ -1,275 +0,0 @@
import axios from 'axios'
import {ElLoading, ElMessage, ElMessageBox, ElNotification} from 'element-plus'
import {getToken} from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import {blobValidate, tansParams} from '@/utils/openhis'
import cache from '@/plugins/cache'
import {saveAs} from 'file-saver'
import useUserStore from '@/store/modules/user'
import JSONBig from 'json-bigint'
// 初始化json-bigint配置大数字转字符串关键storeAsString: true
const jsonBig = JSONBig({ storeAsString: true })
// 🔧 Bug Fix #281: 转换所有ID字段为字符串防止BigInt精度丢失
const convertIdsToString = (obj) => {
if (obj === null || obj === undefined) return obj
if (typeof obj === 'number' && obj > 9007199254740991) {
// 如果是超过安全范围的数字,转为字符串
return String(obj)
}
if (typeof obj === 'object') {
if (Array.isArray(obj)) {
return obj.map(item => convertIdsToString(item))
} else {
const newObj = {}
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const value = obj[key]
// 如果key以Id结尾或者是id且值是数字转为字符串
if ((key === 'id' || key.endsWith('Id') || key.endsWith('ID')) && typeof value === 'number') {
newObj[key] = String(value)
} else {
newObj[key] = convertIdsToString(value)
}
}
}
return newObj
}
}
return obj
}
let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = { show: false };
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 从环境变量读取租户ID如果没有则使用默认值'1'
axios.defaults.headers['X-Tenant-ID'] = import.meta.env.VITE_APP_TENANT_ID || '1'
axios.defaults.headers['Request-Method-Name'] = 'login'
// 创建axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 120000, // 增加到120秒配合后端超时设置
// 新增:重写响应解析逻辑,大数字自动转字符串(移到这里!)
transformResponse: [
function (data) {
if (!data) return {}
// 如果是 Blob 或 ArrayBuffer直接返回不进行 JSON 解析
if (data instanceof Blob || data instanceof ArrayBuffer) {
return data
}
try {
return jsonBig.parse(data)
} catch (err) {
return JSON.parse(data)
}
}
],
// 可选请求体序列化使用json-bigint处理大数字
transformRequest: [
function (data) {
if (!data) return data
// 🔧 Bug Fix #281: 使用json-bigint序列化保留大数字精度
return jsonBig.stringify(data)
}
]
})
// request拦截器
service.interceptors.request.use(config => {
// 🔧 Bug Fix #281: 转换请求数据中的ID字段为字符串
if (config.data && typeof config.data === 'object') {
config.data = convertIdsToString(config.data)
}
// 是否需要设置 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' ? jsonBig.stringify(config.data) : config.data,
time: new Date().getTime()
}
// 🔧 Bug Fix #281: 使用json-bigint计算大小
const requestSize = Object.keys(jsonBig.stringify(requestObj)).length; // 请求数据大小
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制无法进行防重复提交验证。')
return config;
}
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;
// 判断是否在登录页面
const isLoginPage = window.location.pathname === '/login' || window.location.pathname === '/';
if (isLoginPage) {
// 登录页面直接清理token不弹窗
useUserStore().logOut().then(() => {
isRelogin.show = false;
}).catch(() => {
isRelogin.show = false;
});
return Promise.reject('登录已过期,请重新登录。')
}
// 其他页面:显示提示后自动跳转
ElMessage.warning('登录已过期,正在跳转到登录页面...');
useUserStore().logOut().then(() => {
isRelogin.show = false;
// 跳转到登录页保留当前路径作为redirect参数
const currentPath = window.location.pathname;
const redirectUrl = currentPath !== '/login' ? `/login?redirect=${encodeURIComponent(currentPath)}` : '/login';
location.href = redirectUrl;
}).catch(() => {
isRelogin.show = false;
location.href = '/login';
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
// 检查是否需要跳过错误提示(静默请求:返回响应让.then()处理)
if (res.config?.skipErrorMsg) {
return Promise.resolve(res.data)
}
ElMessage({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
// 检查是否需要跳过错误提示(静默请求:返回响应让.then()处理)
if (res.config?.skipErrorMsg) {
return Promise.resolve(res.data)
}
ElMessage({ message: msg, type: 'warning' })
return Promise.reject(new Error(msg))
} else if (code !== 200) {
// 检查是否需要跳过错误提示(静默请求:返回响应让.then()处理)
if (res.config?.skipErrorMsg) {
return Promise.resolve(res.data)
}
ElNotification.error({ title: msg })
return Promise.reject('error')
} else {
return Promise.resolve(res.data)
}
},
error => {
console.log('err' + error)
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
// 检查是否需要跳过错误提示
if (!error.config?.skipErrorMsg) {
ElMessage({ message: message, type: 'error', duration: 5 * 1000 })
}
return Promise.reject(error)
})
// 通用下载方法
export function download(url, params, filename, config) {
downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
return service.post(url, params, {
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',
...config
}).then(async (data) => {
const isBlob = blobValidate(data);
if (isBlob) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
}).catch((r) => {
console.error(r)
ElMessage.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close();
})
}
// 添加GET方式下载方法
export function downloadGet(url, params, filename, config) {
downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
return service.get(url, {
params: params,
responseType: 'blob',
...config
}).then(async (data) => {
const isBlob = blobValidate(data);
if (isBlob) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
}).catch((r) => {
console.error(r)
ElMessage.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close();
})
}
export default service