feat(i18n): translate backend error messages, dict labels auto-translate, add 150+ medical dict terms
This commit is contained in:
@@ -260,7 +260,96 @@ const translationDict = {
|
||||
"ESB": "ESB",
|
||||
"FHIR": "FHIR",
|
||||
"LIS": "LIS",
|
||||
"PACS": "PACS"
|
||||
"PACS": "PACS",
|
||||
// 常见字典标签
|
||||
"一类": "Type I", "二类": "Type II", "三类": "Type III", "四类": "Type IV",
|
||||
"全麻": "General Anesthesia", "局麻": "Local Anesthesia", "椎管内麻醉": "Spinal Anesthesia",
|
||||
"神经阻滞": "Nerve Block", "复合麻醉": "Combined Anesthesia",
|
||||
"甲": "Class A", "乙": "Class B", "丙": "Class C",
|
||||
"自费": "Self-Pay", "公费": "Public Funded", "医保": "Medical Insurance",
|
||||
"现金": "Cash", "微信": "WeChat", "支付宝": "Alipay", "银行卡": "Bank Card",
|
||||
"医保卡": "Insurance Card", "扫码支付": "QR Payment",
|
||||
"初诊": "First Visit", "复诊": "Follow-up Visit", "急诊": "Emergency",
|
||||
"普通号": "Regular", "专家号": "Specialist",
|
||||
"门诊": "Outpatient", "住院": "Inpatient",
|
||||
"待诊": "Waiting", "就诊中": "In Consultation", "已完成": "Completed",
|
||||
"已签到": "Checked In", "已预约": "Booked", "已退号": "Cancelled",
|
||||
"男性": "Male", "女性": "Female",
|
||||
"已婚": "Married", "未婚": "Single", "离异": "Divorced", "丧偶": "Widowed",
|
||||
"汉族": "Han", "回族": "Hui", "藏族": "Tibetan", "维吾尔族": "Uyghur",
|
||||
"A型": "Type A", "B型": "Type B", "AB型": "Type AB", "O型": "Type O",
|
||||
"Rh阳性": "Rh+", "Rh阴性": "Rh-",
|
||||
"抗生素": "Antibiotic", "非抗生素": "Non-Antibiotic",
|
||||
"限制使用": "Restricted", "非限制使用": "Unrestricted", "特殊使用": "Special Use",
|
||||
"口服": "Oral", "注射": "Injection", "外用": "Topical", "吸入": "Inhalation",
|
||||
"静脉注射": "IV", "肌肉注射": "IM", "皮下注射": "SC", "静脉滴注": "IV Drip",
|
||||
"每日一次": "Once Daily", "每日两次": "Twice Daily", "每日三次": "Three Times Daily",
|
||||
"必要时": "As Needed", "立即": "Immediately", "每晚": "Every Night",
|
||||
"急诊手术": "Emergency Surgery", "择期手术": "Elective Surgery",
|
||||
"一级手术": "Grade I", "二级手术": "Grade II", "三级手术": "Grade III", "四级手术": "Grade IV",
|
||||
"Ⅰ级": "Grade I", "Ⅱ级": "Grade II", "Ⅲ级": "Grade III", "Ⅳ级": "Grade IV",
|
||||
"切口甲级": "Grade A Incision", "切口乙级": "Grade B Incision", "切口丙级": "Grade C Incision",
|
||||
"甲级愈合": "Grade A Healing", "乙级愈合": "Grade B Healing", "丙级愈合": "Grade C Healing",
|
||||
"清醒": "Awake", "嗜睡": "Drowsy", "昏迷": "Coma", "模糊": "Confused",
|
||||
"普通病房": "General Ward", "ICU": "ICU", "手术室": "Operating Room",
|
||||
"已入院": "Admitted", "已出院": "Discharged", "转科": "Transfer",
|
||||
"待执行": "Pending", "执行中": "In Progress", "已执行": "Executed", "已停止": "Stopped",
|
||||
"长期医嘱": "Long-term Order", "临时医嘱": "Temporary Order",
|
||||
"待签发": "Pending Sign", "已签发": "Signed", "待校对": "Pending Proofread", "已校对": "Proofread",
|
||||
"阳性": "Positive", "阴性": "Negative",
|
||||
"合格": "Qualified", "不合格": "Unqualified",
|
||||
"空气中": "Air", "物体表面": "Surface", "手卫生": "Hand Hygiene",
|
||||
"消毒液": "Disinfectant", "医疗器械": "Medical Device",
|
||||
"红细胞悬液": "RBC Suspension", "血浆": "Plasma", "血小板": "Platelet", "冷沉淀": "Cryoprecipitate", "全血": "Whole Blood",
|
||||
"输血前": "Pre-Transfusion", "输血中": "During Transfusion", "输血后": "Post-Transfusion",
|
||||
"一级预警": "Level 1 Alert", "二级预警": "Level 2 Alert", "三级预警": "Level 3 Alert",
|
||||
"黄色预警": "Yellow Alert", "红色预警": "Red Alert",
|
||||
"呼吸道传染病": "Respiratory", "肠道传染病": "Intestinal", "血源性传染病": "Blood-borne",
|
||||
"轻度": "Mild", "中度": "Moderate", "重度": "Severe",
|
||||
"待处理": "Pending", "处理中": "Processing", "已处理": "Handled", "已排除": "Excluded",
|
||||
"未隔离": "Not Isolated", "已隔离": "Isolated", "已解除": "Released",
|
||||
"Ⅰ级 濒死": "Level I Critical", "Ⅱ级 危重": "Level II Emergent",
|
||||
"Ⅲ级 急症": "Level III Urgent", "Ⅳ级 亚急": "Level IV Less Urgent", "Ⅴ级 非紧急": "Level V Non-Urgent",
|
||||
"抢救区": "Rescue Zone", "留观区": "Observation Zone", "诊室": "Consult Room", "普通区": "General Zone",
|
||||
"成功": "Success", "失败": "Failed", "进行中": "In Progress",
|
||||
"住院": "Admit", "出院": "Discharge", "转科": "Transfer", "死亡": "Death",
|
||||
"达标": "Achieved", "未达标": "Not Achieved",
|
||||
"空气": "Air", "表面": "Surface", "手": "Hand",
|
||||
"一级愈合": "Grade A", "二级愈合": "Grade B", "三级愈合": "Grade C",
|
||||
"已挂号": "Registered", "进行中": "In Progress", "已退号": "Cancelled",
|
||||
"日班": "Day Shift", "夜班": "Night Shift", "值班": "On Duty",
|
||||
"主任医师": "Chief Physician", "副主任医师": "Associate Chief Physician",
|
||||
"主治医师": "Attending Physician", "住院医师": "Resident",
|
||||
"实习医师": "Intern", "进修医师": "Fellow",
|
||||
"护士长": "Head Nurse", "主管护师": "Supervisor Nurse", "护师": "Nurse", "护士": "Junior Nurse",
|
||||
"药品": "Drug", "诊疗": "Treatment", "耗材": "Consumable", "其他": "Other",
|
||||
"西药": "Western Medicine", "中成药": "Chinese Patent Medicine", "中草药": "Chinese Herbal Medicine",
|
||||
"注射液": "Injection", "片剂": "Tablet", "胶囊": "Capsule", "颗粒": "Granule",
|
||||
"口服液": "Oral Liquid", "软膏": "Ointment", "滴眼液": "Eye Drops",
|
||||
"国产": "Domestic", "进口": "Imported",
|
||||
"甲类": "Class A", "乙类": "Class B", "丙类": "Class C",
|
||||
"医保内": "Insurance Covered", "医保外": "Not Covered",
|
||||
"集中采购": "Centralized Procurement", "自主采购": "Self Procurement",
|
||||
"紧急采购": "Emergency Procurement", "常规采购": "Routine Procurement",
|
||||
"入库": "Inbound", "出库": "Outbound", "调拨": "Transfer", "盘点": "Stocktaking",
|
||||
"盈": "Profit", "亏": "Loss", "损": "Damage",
|
||||
"门诊收费": "OPD Charge", "住院收费": "IPD Charge", "预交金": "Prepayment",
|
||||
"已收费": "Charged", "未收费": "Uncharged", "已退费": "Refunded",
|
||||
"待审批": "Pending Approval", "已审批": "Approved", "已驳回": "Rejected",
|
||||
"电子处方": "E-Prescription", "纸质处方": "Paper Prescription",
|
||||
"门诊处方": "OPD Prescription", "住院处方": "IPD Prescription",
|
||||
"药品不良反应": "Drug ADR", "医疗器械不良事件": "Medical Device Adverse Event",
|
||||
"新发": "New", "在治": "Under Treatment", "治愈": "Cured", "好转": "Improved", "未愈": "Not Cured", "死亡": "Death",
|
||||
"门诊会诊": "OPD Consultation", "院内会诊": "In-hospital Consultation", "院际会诊": "Inter-hospital Consultation",
|
||||
"急会诊": "Urgent Consultation", "普通会诊": "Routine Consultation",
|
||||
"传染病报告": "Infectious Disease Report", "死亡报告": "Death Report",
|
||||
"出生报告": "Birth Report", "肿瘤报告": "Tumor Report",
|
||||
"Ⅰ类切口": "Class I Incision", "Ⅱ类切口": "Class II Incision", "Ⅲ类切口": "Class III Incision",
|
||||
"无菌物品": "Sterile Items", "消毒物品": "Disinfected Items",
|
||||
"手卫生依从": "HH Compliance", "手卫生不依从": "HH Non-Compliance",
|
||||
"接触患者前": "Before Patient Contact", "接触患者后": "After Patient Contact",
|
||||
"无菌操作前": "Before Aseptic Procedure", "体液暴露后": "After Body Fluid Exposure",
|
||||
"接触患者周围环境后": "After Contact with Patient Environment"
|
||||
},
|
||||
'vi': {
|
||||
"新增": "Thêm",
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import useDictStore from '@/store/modules/dict'
|
||||
import {getDicts} from '@/api/system/dict/data'
|
||||
import {autoTranslate} from '@/i18n/autoTranslate'
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
/**
|
||||
* 获取字典数据
|
||||
* 获取字典数据(支持多语言自动翻译)
|
||||
*/
|
||||
export function useDict(...args) {
|
||||
const res = ref({});
|
||||
@@ -14,7 +16,14 @@ export function useDict(...args) {
|
||||
res.value[dictType] = dicts;
|
||||
} else {
|
||||
getDicts(dictType).then(resp => {
|
||||
res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass, remark: p.remark }))
|
||||
const lang = Cookies.get('lang') || localStorage.getItem('lang') || 'zh-CN'
|
||||
res.value[dictType] = resp.data.map(p => ({
|
||||
label: lang === 'zh-CN' ? p.dictLabel : autoTranslate(p.dictLabel),
|
||||
value: p.dictValue,
|
||||
elTagType: p.listClass,
|
||||
elTagClass: p.cssClass,
|
||||
remark: p.remark
|
||||
}))
|
||||
useDictStore().setDict(dictType, res.value[dictType]);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,3 +4,19 @@ export default {
|
||||
'404': '访问资源不存在',
|
||||
'default': '系统未知错误,请反馈给管理员'
|
||||
}
|
||||
|
||||
// English translations for error codes
|
||||
export const errorCodeEn = {
|
||||
'401': 'Authentication failed, cannot access system resources',
|
||||
'403': 'No permission for current operation',
|
||||
'404': 'Requested resource not found',
|
||||
'default': 'Unknown system error, please contact administrator'
|
||||
}
|
||||
|
||||
// Vietnamese translations for error codes
|
||||
export const errorCodeVi = {
|
||||
'401': 'Xác thực thất bại, không thể truy cập tài nguyên hệ thống',
|
||||
'403': 'Không có quyền cho thao tác hiện tại',
|
||||
'404': 'Tài nguyên yêu cầu không tồn tại',
|
||||
'default': 'Lỗi hệ thống không xác định, vui lòng liên hệ quản trị viên'
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import axios from 'axios'
|
||||
import {ElLoading, ElMessage, ElMessageBox, ElNotification} from 'element-plus'
|
||||
import {getToken} from '@/utils/auth'
|
||||
import errorCode from '@/utils/errorCode'
|
||||
import errorCode, {errorCodeEn, errorCodeVi} from '@/utils/errorCode'
|
||||
import {blobValidate, tansParams} from '@/utils/his'
|
||||
import cache from '@/plugins/cache'
|
||||
import {saveAs} from 'file-saver'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import JSONBig from 'json-bigint'
|
||||
import {autoTranslate} from '@/i18n/autoTranslate'
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
// 初始化json-bigint,配置大数字转字符串(关键:storeAsString: true)
|
||||
const jsonBig = JSONBig({ storeAsString: true })
|
||||
@@ -141,8 +143,14 @@ service.interceptors.request.use(config => {
|
||||
service.interceptors.response.use(res => {
|
||||
// 未设置状态码则默认成功状态
|
||||
const code = res.data.code || 200;
|
||||
// 获取错误信息
|
||||
const msg = errorCode[code] || res.data.msg || errorCode['default']
|
||||
// 获取错误信息(支持多语言)
|
||||
const lang = Cookies.get('lang') || localStorage.getItem('lang') || 'zh-CN'
|
||||
const errorDict = lang === 'en' ? errorCodeEn : lang === 'vi' ? errorCodeVi : errorCode
|
||||
let msg = errorDict[code] || res.data.msg || errorDict['default']
|
||||
// 后端返回的中文错误消息自动翻译
|
||||
if (lang !== 'zh-CN' && /[\u4e00-\u9fff]/.test(msg)) {
|
||||
msg = autoTranslate(msg)
|
||||
}
|
||||
// 二进制数据则直接返回
|
||||
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
|
||||
return res.data
|
||||
@@ -160,11 +168,12 @@ service.interceptors.request.use(config => {
|
||||
}).catch(() => {
|
||||
isRelogin.show = false;
|
||||
});
|
||||
return Promise.reject('登录已过期,请重新登录。')
|
||||
return Promise.reject(lang === 'zh-CN' ? '登录已过期,请重新登录。' : lang === 'en' ? 'Session expired, please log in again.' : 'Phiên hết hạn, vui lòng đăng nhập lại.')
|
||||
}
|
||||
|
||||
// 其他页面:显示提示后自动跳转
|
||||
ElMessage.warning('登录已过期,正在跳转到登录页面...');
|
||||
const expiredMsg = lang === 'zh-CN' ? '登录已过期,正在跳转到登录页面...' : lang === 'en' ? 'Session expired, redirecting to login...' : 'Phiên hết hạn, đang chuyển đến trang đăng nhập...'
|
||||
ElMessage.warning(expiredMsg);
|
||||
useUserStore().logOut().then(() => {
|
||||
isRelogin.show = false;
|
||||
// 跳转到登录页,保留当前路径作为redirect参数
|
||||
@@ -204,13 +213,15 @@ service.interceptors.request.use(config => {
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
const lang = Cookies.get('lang') || localStorage.getItem('lang') || 'zh-CN'
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "后端接口连接异常";
|
||||
message = lang === 'zh-CN' ? '后端接口连接异常' : lang === 'en' ? 'Backend API connection error' : 'Lỗi kết nối API backend';
|
||||
} else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
message = lang === 'zh-CN' ? '系统接口请求超时' : lang === 'en' ? 'API request timeout' : 'Yêu cầu API hết thời gian';
|
||||
} else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
const code = message.substr(message.length - 3)
|
||||
message = lang === 'zh-CN' ? '系统接口' + code + '异常' : lang === 'en' ? 'API error ' + code : 'Lỗi API ' + code;
|
||||
}
|
||||
// 检查是否需要跳过错误提示
|
||||
if (!error.config?.skipErrorMsg) {
|
||||
@@ -221,7 +232,9 @@ service.interceptors.request.use(config => {
|
||||
|
||||
// 通用下载方法
|
||||
export function download(url, params, filename, config) {
|
||||
downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
|
||||
const lang = Cookies.get('lang') || localStorage.getItem('lang') || 'zh-CN'
|
||||
const dlMsg = lang === 'zh-CN' ? '正在下载数据,请稍候' : lang === 'en' ? 'Downloading data, please wait' : 'Đang tải dữ liệu, vui lòng đợi'
|
||||
downloadLoadingInstance = ElLoading.service({ text: dlMsg, 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' },
|
||||
@@ -235,20 +248,25 @@ export function download(url, params, filename, config) {
|
||||
} else {
|
||||
const resText = await data.text();
|
||||
const rspObj = JSON.parse(resText);
|
||||
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
|
||||
const errorDict = lang === 'en' ? errorCodeEn : lang === 'vi' ? errorCodeVi : errorCode
|
||||
let errMsg = errorDict[rspObj.code] || rspObj.msg || errorDict['default']
|
||||
if (lang !== 'zh-CN' && /[\u4e00-\u9fff]/.test(errMsg)) errMsg = autoTranslate(errMsg)
|
||||
ElMessage.error(errMsg);
|
||||
}
|
||||
downloadLoadingInstance.close();
|
||||
}).catch((r) => {
|
||||
console.error(r)
|
||||
ElMessage.error('下载文件出现错误,请联系管理员!')
|
||||
const dlErr = lang === 'zh-CN' ? '下载文件出现错误,请联系管理员!' : lang === 'en' ? 'Download error, please contact administrator!' : 'Lỗi tải xuống, vui lòng liên hệ quản trị viên!'
|
||||
ElMessage.error(dlErr)
|
||||
downloadLoadingInstance.close();
|
||||
})
|
||||
}
|
||||
|
||||
// 添加GET方式下载方法
|
||||
export function downloadGet(url, params, filename, config) {
|
||||
downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
|
||||
const lang2 = Cookies.get('lang') || localStorage.getItem('lang') || 'zh-CN'
|
||||
const dlMsg2 = lang2 === 'zh-CN' ? '正在下载数据,请稍候' : lang2 === 'en' ? 'Downloading data, please wait' : 'Đang tải dữ liệu, vui lòng đợi'
|
||||
downloadLoadingInstance = ElLoading.service({ text: dlMsg2, background: "rgba(0, 0, 0, 0.7)", })
|
||||
return service.get(url, {
|
||||
params: params,
|
||||
responseType: 'blob',
|
||||
@@ -261,13 +279,16 @@ export function downloadGet(url, params, filename, config) {
|
||||
} else {
|
||||
const resText = await data.text();
|
||||
const rspObj = JSON.parse(resText);
|
||||
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
|
||||
const errorDict2 = lang2 === 'en' ? errorCodeEn : lang2 === 'vi' ? errorCodeVi : errorCode
|
||||
let errMsg = errorDict2[rspObj.code] || rspObj.msg || errorDict2['default']
|
||||
if (lang2 !== 'zh-CN' && /[\u4e00-\u9fff]/.test(errMsg)) errMsg = autoTranslate(errMsg)
|
||||
ElMessage.error(errMsg);
|
||||
}
|
||||
downloadLoadingInstance.close();
|
||||
}).catch((r) => {
|
||||
console.error(r)
|
||||
ElMessage.error('下载文件出现错误,请联系管理员!')
|
||||
const dlErr2 = lang2 === 'zh-CN' ? '下载文件出现错误,请联系管理员!' : lang2 === 'en' ? 'Download error, please contact administrator!' : 'Lỗi tải xuống, vui lòng liên hệ quản trị viên!'
|
||||
ElMessage.error(dlErr2)
|
||||
downloadLoadingInstance.close();
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user