feat(i18n): migrate login, dashboard, navbar, sidebar, user/role pages to vue-i18n with language switcher on login page

This commit is contained in:
2026-06-24 13:33:44 +08:00
parent fbb7f8215e
commit 822414c228
9 changed files with 1003 additions and 331 deletions

View File

@@ -1,4 +1,14 @@
{
"navbar": {
"helpCenter": "Help Center",
"themeSettings": "Theme Settings",
"profile": "Profile",
"lockScreen": "Lock Screen",
"logout": "Logout",
"switchDepartment": "Switch Department",
"switchDepartmentConfirm": "Are you sure to switch to department \"{name}\"?",
"logoutConfirm": "Are you sure to logout and exit the system?"
},
"nav": {
"dashboard": "Dashboard",
"system": "System Settings",
@@ -30,7 +40,35 @@
"noTenant": "No tenant selection needed",
"loginSuccess": "Login successful",
"logoutSuccess": "Logged out",
"pleaseSelectTenant": "Please select tenant"
"pleaseSelectTenant": "Please select tenant",
"systemSubtitle": "Information Management System",
"featureSecure": "Secure & Reliable",
"featureSecureDesc": "Comprehensive data security protection",
"featureEfficient": "Efficient & Convenient",
"featureEfficientDesc": "Intelligent medical business processes",
"featureCollab": "Collaborative Office",
"featureCollabDesc": "Seamless collaboration across departments and roles",
"techSupport": "Technical Support: Shanghai Jingchuang Helian Information Technology Co., Ltd.",
"welcomeBack": "Welcome Back",
"loginDesc": "Please log in securely with your account and password",
"account": "Username",
"placeholderAccount": "Enter your account",
"hide": "Hide",
"show": "Show",
"medicalInstitution": "Medical Institution",
"placeholderMedicalInstitution": "Select medical institution",
"connectMedicalInsurance": "Connect Medical Insurance",
"loginButtonText": "Log In",
"loggingIn": "Logging in...",
"connectingInsurance": "Connecting insurance...",
"frontendVersion": "Frontend",
"backendVersion": "Backend",
"copyrightSystem": " Information Management System",
"validationUsername": "Please enter your username",
"validationPassword": "Please enter your password",
"validationCaptcha": "Please enter verification code",
"forgotPasswordTip": "Forgot password feature is under development",
"signInFailed": "Medical insurance sign-in failed"
},
"common": {
"add": "Add",
@@ -111,7 +149,71 @@
"enable": "Enable",
"authRole": "Assign Roles",
"importTemplate": "Download Template",
"selectDept": "Select Department"
"selectDept": "Select Department",
"userAccount": "User Account",
"userPassword": "Password",
"responsibilityDept": "Department",
"birthDate": "Birth Date",
"address": "Address",
"medicalInsuranceCode": "Insurance Code",
"role": "Role",
"titleCode": "Title Code",
"signatureImage": "Signature Image",
"qualificationCertNo": "Qualification No.",
"visitDept": "Visit Department",
"manageWarehouse": "Manage Warehouse",
"managePharmacy": "Manage Pharmacy",
"manageDept": "Manage Department",
"manageWard": "Manage Ward",
"userInfo": "User Info",
"remarks": "Remarks",
"clickToUpload": "Click to upload",
"dragOrClick": "Drag file here, or <em>click to upload</em>",
"updateExisting": "Update existing user data?",
"importFormatTip": "Only xls, xlsx files are allowed.",
"downloadTemplate": "Download Template",
"userImport": "User Import",
"importResult": "Import Result",
"uploadOneImage": "Only one image allowed, please delete the existing one first!",
"fileFormatError": "Invalid format, please upload image files (JPG, PNG).",
"imageSizeLimit": "Image size cannot exceed 2MB!",
"selectImageFile": "Please select an image file!",
"enterDeptName": "Enter department name",
"enterUserAccount": "Enter user account",
"enterPhone": "Enter phone number",
"userStatus": "User Status",
"enterUserName": "Enter user name",
"selectRespDept": "Select department",
"enterEmail": "Enter email",
"enterPassword": "Enter password",
"selectDate": "Select date",
"enterAddress": "Enter address",
"enterMedicalCode": "Enter insurance code",
"selectTitleCode": "Select title code",
"enterQualCertNo": "Enter qualification number",
"selectVisitDept": "Select visit department",
"selectWarehouse": "Select warehouse",
"selectPharmacy": "Select pharmacy",
"selectManageDept": "Select department",
"selectWard": "Select ward",
"enterContent": "Enter content",
"deleteConfirm": "Are you sure to delete user \"{id}\"?",
"statusConfirm": "Are you sure to \"{action}\" user \"{username}\"?",
"operationFailed": "Operation failed, please try again",
"resetPwdPrompt": "Enter new password for \"{username}\"",
"resetPwdSuccess": "Password updated, new password: {pwd}",
"addUser": "Add User",
"editUser": "Edit User",
"valAccountRequired": "User account cannot be empty",
"valAccountLength": "User account must be 2-20 characters",
"valNameRequired": "User name cannot be empty",
"valDeptRequired": "Department cannot be empty",
"valRoleRequired": "Role cannot be empty",
"valPasswordRequired": "Password cannot be empty",
"valPasswordLength": "Password must be 5-20 characters",
"valPasswordChars": "Cannot contain illegal characters: < > \" ' \\ |",
"valEmail": "Please enter a valid email",
"valPhone": "Please enter a valid phone number"
},
"role": {
"roleId": "Role ID",
@@ -125,7 +227,37 @@
"customData": "Custom Data",
"deptdata": "Dept Data",
"deptAndChildrenData": "Dept & Sub-dept",
"selfData": "Self Only"
"selfData": "Self Only",
"assignUser": "Assign Users",
"assignUserBatch": "Batch Assign",
"enterRoleName": "Enter role name",
"enterRoleKey": "Enter role key",
"roleStatus": "Role Status",
"startDate": "Start Date",
"endDate": "End Date",
"roleNumber": "Role Number",
"displayOrder": "Display Order",
"expandCollapse": "Expand/Collapse",
"selectAll": "Select All/None",
"parentChildLink": "Parent-Child Link",
"loadingPleaseWait": "Loading, please wait",
"permissionChar": "Permission Key",
"permissionTooltip": "Permission key defined in controller, e.g.: @PreAuthorize(`@ss.hasRole('admin')`)",
"roleOrder": "Role Order",
"addRole": "Add Role",
"editRole": "Edit Role",
"assignDataPermission": "Assign Data Permission",
"deleteConfirm": "Are you sure to delete role \"{id}\"?",
"valNameRequired": "Role name cannot be empty",
"valKeyRequired": "Role key cannot be empty",
"valSortRequired": "Role order cannot be empty",
"allDataPermission": "All Data Permission",
"customDataPermission": "Custom Data Permission",
"deptDataPermission": "Department Data Permission",
"deptAndChildrenPermission": "Dept & Sub-dept Permission",
"selfDataPermission": "Self Only Permission",
"dataPermission": "Data Permission",
"permissionScope": "Permission Scope"
},
"menu": {
"menuId": "Menu ID",
@@ -196,6 +328,73 @@
"copySuccess": "Copied successfully",
"copyFailed": "Copy failed"
},
"dashboard": {
"title": "System Dashboard",
"realtimeConnected": "● Real-time Connected",
"offline": "○ Offline",
"systemInfo": "System Info",
"version": "Version",
"env": "Environment",
"devEnv": "Development",
"realtimeAlert": "⚠️ Real-time Alerts",
"totalRevenue": "Total Revenue (10K)",
"totalProfit": "Total Profit (10K)",
"totalPatients": "Total Patients",
"drgCases": "DRG Cases",
"featureModules": "Feature Modules",
"quickActions": "Quick Actions",
"recentOperations": "Recent Operations",
"justNow": "Just now",
"enterModule": "Enter module",
"navigateTo": "Navigate to",
"dbTables": "DB Tables",
"apiInterfaces": "API Interfaces",
"modules": "Modules",
"menuCount": "Menus",
"onlineUsers": "Online Users",
"todayOps": "Today's Ops",
"outpatientMgmt": "Outpatient",
"outpatientDesc": "Register/Billing/Prescription",
"inpatientMgmt": "Inpatient",
"inpatientDesc": "Admit/Discharge/Order",
"pharmacyMgmt": "Pharmacy",
"pharmacyDesc": "Dispense/Stock/Trace",
"nursingMgmt": "Nursing",
"nursingDesc": "Assess/Execute/QA",
"labMgmt": "Laboratory",
"labDesc": "Specimen/Report/History",
"imagingMgmt": "Imaging",
"imagingDesc": "Exam/Report/Compare",
"anesthesiaMgmt": "Anesthesia",
"anesthesiaDesc": "Record/Follow-up/QC",
"surgeryMgmt": "Surgery",
"surgeryDesc": "Schedule/Safety/Record",
"infectionMgmt": "Infection Control",
"infectionDesc": "Monitor/Alert/Report",
"qualityMgmt": "Quality Control",
"qualityDesc": "Chart/Nursing/Runtime",
"tcmMgmt": "TCM",
"tcmDesc": "Formula/Constitution/Rx",
"consultMgmt": "Consultation",
"consultDesc": "Request/Confirm/Feedback",
"actionRegister": "Register",
"actionPrescribe": "Prescribe",
"actionDispense": "Dispense",
"actionLab": "Lab",
"actionQuality": "QC",
"actionReport": "Reports",
"systemName": "System Name",
"versionNumber": "Version",
"runEnv": "Environment",
"backendPort": "Backend Port",
"dbTableCount": "DB Tables",
"apiCount": "API Count",
"moduleCount": "Modules",
"startTime": "Start Time"
},
"sidebar": {
"defaultTitle": "Hospital Management System"
},
"table": {
"index": "#",
"action": "Action",

View File

@@ -1,4 +1,14 @@
{
"navbar": {
"helpCenter": "Trung Tâm Trợ Giúp",
"themeSettings": "Cài Đặt Giao Diện",
"profile": "Hồ Sơ Cá Nhân",
"lockScreen": "Khóa Màn Hình",
"logout": "Đăng Xuất",
"switchDepartment": "Chuyển Khoa",
"switchDepartmentConfirm": "Bạn có chắc chắn muốn chuyển đến khoa \"{name}\"?",
"logoutConfirm": "Bạn có chắc chắn muốn đăng xuất và thoát hệ thống?"
},
"nav": {
"dashboard": "Bảng Điều Khiển",
"system": "Cài Đặt Hệ Thống",
@@ -30,7 +40,35 @@
"noTenant": "Không cần chọn thuê bao",
"loginSuccess": "Đăng nhập thành công",
"logoutSuccess": "Đã đăng xuất",
"pleaseSelectTenant": "Vui lòng chọn thuê bao"
"pleaseSelectTenant": "Vui lòng chọn thuê bao",
"systemSubtitle": "Hệ Thống Quản Lý Thông Tin",
"featureSecure": "An Toàn & Đáng Tin Cậy",
"featureSecureDesc": "Bảo mật dữ liệu toàn diện",
"featureEfficient": "Hiệu Quả & Tiện Lợi",
"featureEfficientDesc": "Quy trình nghiệp vụ y tế thông minh",
"featureCollab": "Làm Việc Cộng Tác",
"featureCollabDesc": "Cộng tác liền mạch giữa các khoa và vai trò",
"techSupport": "Hỗ trợ kỹ thuật: Shanghai Jingchuang Helian Information Technology Co., Ltd.",
"welcomeBack": "Chào Mừng Trở Lại",
"loginDesc": "Vui lòng đăng nhập an toàn bằng tài khoản và mật khẩu",
"account": "Tên Đăng Nhập",
"placeholderAccount": "Nhập tài khoản",
"hide": "Ẩn",
"show": "Hiện",
"medicalInstitution": "Cơ Sở Y Tế",
"placeholderMedicalInstitution": "Chọn cơ sở y tế",
"connectMedicalInsurance": "Kết Nối Bảo Hiểm Y Tế",
"loginButtonText": "Đăng Nhập",
"loggingIn": "Đang đăng nhập...",
"connectingInsurance": "Đang kết nối bảo hiểm...",
"frontendVersion": "Frontend",
"backendVersion": "Backend",
"copyrightSystem": " Hệ Thống Quản Lý Thông Tin",
"validationUsername": "Vui lòng nhập tên đăng nhập",
"validationPassword": "Vui lòng nhập mật khẩu",
"validationCaptcha": "Vui lòng nhập mã xác minh",
"forgotPasswordTip": "Tính năng quên mật khẩu đang được phát triển",
"signInFailed": "Đăng ký bảo hiểm y tế thất bại"
},
"common": {
"add": "Thêm",
@@ -111,7 +149,71 @@
"enable": "Kích Hoạt",
"authRole": "Phân Vai Trò",
"importTemplate": "Tải Mẫu",
"selectDept": "Chọn Bộ Phận"
"selectDept": "Chọn Bộ Phận",
"userAccount": "Tài Khoản",
"userPassword": "Mật Khẩu",
"responsibilityDept": "Khoa Phụ Trách",
"birthDate": "Ngày Sinh",
"address": "Địa Chỉ",
"medicalInsuranceCode": "Mã BHYT",
"role": "Vai Trò",
"titleCode": "Mã Chức Danh",
"signatureImage": "Ảnh Chữ Ký",
"qualificationCertNo": "Số Chứng Chỉ",
"visitDept": "Khoa Khám Bệnh",
"manageWarehouse": "Quản Lý Kho",
"managePharmacy": "Quản Lý Nhà Thuốc",
"manageDept": "Quản Lý Khoa",
"manageWard": "Quản Lý Khu",
"userInfo": "Thông Tin Người Dùng",
"remarks": "Ghi Chú",
"clickToUpload": "Nhấn để tải lên",
"dragOrClick": "Kéo tệp vào đây, hoặc <em>nhấn để tải lên</em>",
"updateExisting": "Cập nhật dữ liệu người dùng đã tồn tại?",
"importFormatTip": "Chỉ cho phép tệp xls, xlsx.",
"downloadTemplate": "Tải Mẫu",
"userImport": "Nhập Người Dùng",
"importResult": "Kết Quả Nhập",
"uploadOneImage": "Chỉ được tải lên một ảnh, vui lòng xóa ảnh hiện tại trước!",
"fileFormatError": "Sai định dạng, vui lòng tải lên tệp ảnh (JPG, PNG).",
"imageSizeLimit": "Kích thước ảnh không được vượt quá 2MB!",
"selectImageFile": "Vui lòng chọn tệp ảnh!",
"enterDeptName": "Nhập tên khoa",
"enterUserAccount": "Nhập tài khoản",
"enterPhone": "Nhập số điện thoại",
"userStatus": "Trạng Thái TK",
"enterUserName": "Nhập tên người dùng",
"selectRespDept": "Chọn khoa phụ trách",
"enterEmail": "Nhập email",
"enterPassword": "Nhập mật khẩu",
"selectDate": "Chọn ngày",
"enterAddress": "Nhập địa chỉ",
"enterMedicalCode": "Nhập mã BHYT",
"selectTitleCode": "Chọn mã chức danh",
"enterQualCertNo": "Nhập số chứng chỉ",
"selectVisitDept": "Chọn khoa khám bệnh",
"selectWarehouse": "Chọn kho",
"selectPharmacy": "Chọn nhà thuốc",
"selectManageDept": "Chọn khoa quản lý",
"selectWard": "Chọn khu vực",
"enterContent": "Nhập nội dung",
"deleteConfirm": "Bạn có chắc chắn muốn xóa người dùng \"{id}\"?",
"statusConfirm": "Bạn có chắc chắn muốn \"{action}\" người dùng \"{username}\"?",
"operationFailed": "Thao tác thất bại, vui lòng thử lại",
"resetPwdPrompt": "Nhập mật khẩu mới cho \"{username}\"",
"resetPwdSuccess": "Đã cập nhật mật khẩu, mật khẩu mới: {pwd}",
"addUser": "Thêm Người Dùng",
"editUser": "Sửa Người Dùng",
"valAccountRequired": "Tài khoản không được để trống",
"valAccountLength": "Tài khoản phải từ 2-20 ký tự",
"valNameRequired": "Tên người dùng không được để trống",
"valDeptRequired": "Khoa không được để trống",
"valRoleRequired": "Vai trò không được để trống",
"valPasswordRequired": "Mật khẩu không được để trống",
"valPasswordLength": "Mật khẩu phải từ 5-20 ký tự",
"valPasswordChars": "Không được chứa ký tự bất hợp pháp: < > \" ' \\ |",
"valEmail": "Vui lòng nhập email hợp lệ",
"valPhone": "Vui lòng nhập số điện thoại hợp lệ"
},
"role": {
"roleId": "ID Vai Trò",
@@ -125,7 +227,37 @@
"customData": "Tùy Chỉnh",
"deptdata": "Dữ Liệu Bộ Phận",
"deptAndChildrenData": "Bộ Phận & Cấp Dưới",
"selfData": "Chỉ Bản Thân"
"selfData": "Chỉ Bản Thân",
"assignUser": "Phân Bổ Người Dùng",
"assignUserBatch": "Phân Bổ Hàng Loạt",
"enterRoleName": "Nhập tên vai trò",
"enterRoleKey": "Nhập mã vai trò",
"roleStatus": "Trạng Thái Vai Trò",
"startDate": "Ngày Bắt Đầu",
"endDate": "Ngày Kết Thúc",
"roleNumber": "Số Vai Trò",
"displayOrder": "Thứ Tự Hiển Thị",
"expandCollapse": "Mở Rộng/Thu Gọn",
"selectAll": "Chọn Tất Cả/Bỏ Chọn",
"parentChildLink": "Liên Kết Cha-Con",
"loadingPleaseWait": "Đang tải, vui lòng đợi",
"permissionChar": "Mã Quyền",
"permissionTooltip": "Mã quyền được định nghĩa trong controller, ví dụ: @PreAuthorize(`@ss.hasRole('admin')`)",
"roleOrder": "Thứ Tự Vai Trò",
"addRole": "Thêm Vai Trò",
"editRole": "Sửa Vai Trò",
"assignDataPermission": "Phân Quyền Dữ Liệu",
"deleteConfirm": "Bạn có chắc chắn muốn xóa vai trò \"{id}\"?",
"valNameRequired": "Tên vai trò không được để trống",
"valKeyRequired": "Mã vai trò không được để trống",
"valSortRequired": "Thứ tự vai trò không được để trống",
"allDataPermission": "Quyền Tất Cả Dữ Liệu",
"customDataPermission": "Quyền Dữ Liệu Tùy Chỉnh",
"deptDataPermission": "Quyền Dữ Liệu Bộ Phận",
"deptAndChildrenPermission": "Quyền Bộ Phận & Cấp Dưới",
"selfDataPermission": "Quyền Chỉ Bản Thân",
"dataPermission": "Quyền Dữ Liệu",
"permissionScope": "Phạm Vi Quyền"
},
"menu": {
"menuId": "ID Menu",
@@ -196,6 +328,73 @@
"copySuccess": "Sao chép thành công",
"copyFailed": "Sao chép thất bại"
},
"dashboard": {
"title": "Bảng Điều Khiển Hệ Thống",
"realtimeConnected": "● Đã Kết Nối Thời Gian Thực",
"offline": "○ Ngoại Tuyến",
"systemInfo": "Thông Tin Hệ Thống",
"version": "Phiên Bản",
"env": "Môi Trường",
"devEnv": "Phát Triển",
"realtimeAlert": "⚠️ Cảnh Báo Thời Gian Thực",
"totalRevenue": "Tổng Doanh Thu (10K)",
"totalProfit": "Tổng Lợi Nhuận (10K)",
"totalPatients": "Tổng Bệnh Nhân",
"drgCases": "Ca DRG",
"featureModules": "Chức Năng",
"quickActions": "Thao Tác Nhanh",
"recentOperations": "Thao Tác Gần Đây",
"justNow": "Vừa xong",
"enterModule": "Vào module",
"navigateTo": "Chuyển đến",
"dbTables": "Bảng DB",
"apiInterfaces": "API",
"modules": "Chức Năng",
"menuCount": "Menu",
"onlineUsers": "Trực Tuyến",
"todayOps": "Hôm Nay",
"outpatientMgmt": "Ngoại Trú",
"outpatientDesc": "ĐK/Thuốc/Đơn",
"inpatientMgmt": "Nội Trú",
"inpatientDesc": "Nhập/Xuất/Y Lệnh",
"pharmacyMgmt": "Nhà Thuốc",
"pharmacyDesc": "Phát/Tồn/Truy Xuất",
"nursingMgmt": "Điều Dưỡng",
"nursingDesc": "Đánh Giá/Thực Hiện/CL",
"labMgmt": "Xét Nghiệm",
"labDesc": "Mẫu/Báo Cáo/Lịch Sử",
"imagingMgmt": "Chẩn Đoán Hình Ảnh",
"imagingDesc": "Khám/BC/So Sánh",
"anesthesiaMgmt": "Gây Mê",
"anesthesiaDesc": "Ghi Nhận/Tái Khám/CL",
"surgeryMgmt": "Phẫu Thuật",
"surgeryDesc": "Lịch/An Toàn/Ghi Nhận",
"infectionMgmt": "Kiểm Soát Nhiễm Trùng",
"infectionDesc": "Giám Sát/Cảnh Báo/BC",
"qualityMgmt": "Kiểm Soát Chất Lượng",
"qualityDesc": "Bệnh Án/ĐD/Vận Hành",
"tcmMgmt": "Y Học Cổ Truyền",
"tcmDesc": "Thang/Thể Chất/Đơn",
"consultMgmt": "Hội Chẩn",
"consultDesc": "Yêu Cầu/Xác Nhận/Phản Hồi",
"actionRegister": "Đăng Ký",
"actionPrescribe": "Kê Đơn",
"actionDispense": "Phát Thuốc",
"actionLab": "Xét Nghiệm",
"actionQuality": "Kiểm Soát CL",
"actionReport": "Báo Cáo",
"systemName": "Tên Hệ Thống",
"versionNumber": "Phiên Bản",
"runEnv": "Môi Trường",
"backendPort": "Cổng Backend",
"dbTableCount": "Bảng DB",
"apiCount": "Số API",
"moduleCount": "Chức Năng",
"startTime": "Thời Gian Khởi Động"
},
"sidebar": {
"defaultTitle": "Hệ Thống Quản Lý Bệnh Viện"
},
"table": {
"index": "#",
"action": "Hành Động",

View File

@@ -1,4 +1,14 @@
{
"navbar": {
"helpCenter": "帮助中心",
"themeSettings": "主题设置",
"profile": "个人中心",
"lockScreen": "锁定屏幕",
"logout": "退出登录",
"switchDepartment": "切换科室",
"switchDepartmentConfirm": "确定要切换到科室\"{name}\"吗?",
"logoutConfirm": "确定注销并退出系统吗?"
},
"nav": {
"dashboard": "系统仪表盘",
"system": "系统设置",
@@ -30,7 +40,35 @@
"noTenant": "无需选择租户",
"loginSuccess": "登录成功",
"logoutSuccess": "退出成功",
"pleaseSelectTenant": "请选择租户"
"pleaseSelectTenant": "请选择租户",
"systemSubtitle": "信息管理系统",
"featureSecure": "安全可靠",
"featureSecureDesc": "全方位数据安全保障",
"featureEfficient": "高效便捷",
"featureEfficientDesc": "智能化医疗业务流程",
"featureCollab": "协同办公",
"featureCollabDesc": "多科室多角色无缝协作",
"techSupport": "技术支持:上海经创贺联信息技术有限公司",
"welcomeBack": "欢迎回来",
"loginDesc": "请使用您的账号密码安全登录系统",
"account": "用户名",
"placeholderAccount": "请输入账号",
"hide": "隐藏",
"show": "显示",
"medicalInstitution": "医疗机构",
"placeholderMedicalInstitution": "请选择医疗机构",
"connectMedicalInsurance": "连接医保",
"loginButtonText": "登 录",
"loggingIn": "登录中...",
"connectingInsurance": "连接医保中...",
"frontendVersion": "前端",
"backendVersion": "后端",
"copyrightSystem": "信息管理系统",
"validationUsername": "请输入您的账号",
"validationPassword": "请输入您的密码",
"validationCaptcha": "请输入验证码",
"forgotPasswordTip": "忘记密码功能正在开发中",
"signInFailed": "医保签到失败"
},
"common": {
"add": "新增",
@@ -111,7 +149,71 @@
"enable": "启用",
"authRole": "授权角色",
"importTemplate": "下载模板",
"selectDept": "请选择部门"
"selectDept": "请选择部门",
"userAccount": "用户账号",
"userPassword": "用户密码",
"responsibilityDept": "责任科室",
"birthDate": "出生日期",
"address": "地址",
"medicalInsuranceCode": "医保码",
"role": "角色",
"titleCode": "职称编码",
"signatureImage": "签名图片",
"qualificationCertNo": "职业资格证编号",
"visitDept": "出诊科室",
"manageWarehouse": "管理药库",
"managePharmacy": "管理药房",
"manageDept": "管理科室",
"manageWard": "管理病区",
"userInfo": "用户信息",
"remarks": "备注",
"clickToUpload": "点击上传图片",
"dragOrClick": "将文件拖到此处,或<em>点击上传</em>",
"updateExisting": "是否更新已经存在的用户数据",
"importFormatTip": "仅允许导入xls、xlsx格式文件。",
"downloadTemplate": "下载模板",
"userImport": "用户导入",
"importResult": "导入结果",
"uploadOneImage": "只能上传一张图片,请先删除已上传的图片!",
"fileFormatError": "文件格式错误,请上传图片类型,如JPGPNG后缀的文件。",
"imageSizeLimit": "图片大小不能超过2MB",
"selectImageFile": "请选择图片文件!",
"enterDeptName": "请输入部门名称",
"enterUserAccount": "请输入用户账号",
"enterPhone": "请输入手机号码",
"userStatus": "用户状态",
"enterUserName": "请输入用户姓名",
"selectRespDept": "请选择责任科室",
"enterEmail": "请输入邮箱",
"enterPassword": "请输入用户密码",
"selectDate": "选择日期",
"enterAddress": "请输入地址",
"enterMedicalCode": "请输入医保码",
"selectTitleCode": "请选择职称编码",
"enterQualCertNo": "请输入职业资格证编号",
"selectVisitDept": "请选择出诊科室",
"selectWarehouse": "请选择管理药库",
"selectPharmacy": "请选择管理药房",
"selectManageDept": "请选择管理科室",
"selectWard": "请选择管理病区",
"enterContent": "请输入内容",
"deleteConfirm": "是否确认删除用户编号为\"{id}\"的数据项?",
"statusConfirm": "确认要\"{action}\"\"{username}\"用户吗?",
"operationFailed": "操作失败,请重试",
"resetPwdPrompt": "请输入\"{username}\"的新密码",
"resetPwdSuccess": "修改成功,新密码是:{pwd}",
"addUser": "添加用户",
"editUser": "修改用户",
"valAccountRequired": "用户账号不能为空",
"valAccountLength": "用户账号长度必须介于 2 和 20 之间",
"valNameRequired": "用户姓名不能为空",
"valDeptRequired": "责任科室不能为空",
"valRoleRequired": "角色不能为空",
"valPasswordRequired": "用户密码不能为空",
"valPasswordLength": "用户密码长度必须介于 5 和 20 之间",
"valPasswordChars": "不能包含非法字符:< > \" ' \\ |",
"valEmail": "请输入正确的邮箱地址",
"valPhone": "请输入正确的手机号码"
},
"role": {
"roleId": "角色ID",
@@ -127,7 +229,35 @@
"deptAndChildrenData": "本部门及下级数据",
"selfData": "仅本人数据",
"assignUser": "分配用户",
"assignUserBatch": "批量分配"
"assignUserBatch": "批量分配",
"enterRoleName": "请输入角色名称",
"enterRoleKey": "请输入权限字符",
"roleStatus": "角色状态",
"startDate": "开始日期",
"endDate": "结束日期",
"roleNumber": "角色编号",
"displayOrder": "显示顺序",
"expandCollapse": "展开/折叠",
"selectAll": "全选/全不选",
"parentChildLink": "父子联动",
"loadingPleaseWait": "加载中,请稍候",
"permissionChar": "权限字符",
"permissionTooltip": "控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)",
"roleOrder": "角色顺序",
"addRole": "添加角色",
"editRole": "修改角色",
"assignDataPermission": "分配数据权限",
"deleteConfirm": "是否确认删除角色编号为\"{id}\"的数据项?",
"valNameRequired": "角色名称不能为空",
"valKeyRequired": "权限字符不能为空",
"valSortRequired": "角色顺序不能为空",
"allDataPermission": "全部数据权限",
"customDataPermission": "自定数据权限",
"deptDataPermission": "本部门数据权限",
"deptAndChildrenPermission": "本部门及以下数据权限",
"selfDataPermission": "仅本人数据权限",
"dataPermission": "数据权限",
"permissionScope": "权限范围"
},
"menu": {
"menuId": "菜单ID",
@@ -198,6 +328,73 @@
"copySuccess": "复制成功",
"copyFailed": "复制失败"
},
"dashboard": {
"title": "系统仪表盘",
"realtimeConnected": "● 实时连接",
"offline": "○ 离线",
"systemInfo": "系统信息",
"version": "版本",
"env": "环境",
"devEnv": "开发环境",
"realtimeAlert": "⚠️ 实时预警",
"totalRevenue": "总收入(万)",
"totalProfit": "总利润(万)",
"totalPatients": "总患者数",
"drgCases": "DRG病例数",
"featureModules": "功能模块",
"quickActions": "快捷操作",
"recentOperations": "最近操作",
"justNow": "刚刚",
"enterModule": "进入模块",
"navigateTo": "跳转",
"dbTables": "数据库表",
"apiInterfaces": "API接口",
"modules": "功能模块",
"menuCount": "菜单数",
"onlineUsers": "在线用户",
"todayOps": "今日操作",
"outpatientMgmt": "门诊管理",
"outpatientDesc": "挂号/收费/处方",
"inpatientMgmt": "住院管理",
"inpatientDesc": "入院/出院/医嘱",
"pharmacyMgmt": "药房管理",
"pharmacyDesc": "发药/库存/追溯",
"nursingMgmt": "护理管理",
"nursingDesc": "评估/执行/质量",
"labMgmt": "检验管理",
"labDesc": "标本/报告/历史",
"imagingMgmt": "影像管理",
"imagingDesc": "检查/报告/对比",
"anesthesiaMgmt": "麻醉管理",
"anesthesiaDesc": "记录/随访/质控",
"surgeryMgmt": "手术管理",
"surgeryDesc": "排班/安全/记录",
"infectionMgmt": "院感管理",
"infectionDesc": "监测/预警/报告",
"qualityMgmt": "质控管理",
"qualityDesc": "病历/护理/运行",
"tcmMgmt": "中医管理",
"tcmDesc": "方剂/体质/处方",
"consultMgmt": "会诊管理",
"consultDesc": "申请/确认/反馈",
"actionRegister": "挂号",
"actionPrescribe": "开方",
"actionDispense": "发药",
"actionLab": "检验",
"actionQuality": "质控",
"actionReport": "报表",
"systemName": "系统名称",
"versionNumber": "版本号",
"runEnv": "运行环境",
"backendPort": "后端端口",
"dbTableCount": "数据库表",
"apiCount": "API接口",
"moduleCount": "功能模块",
"startTime": "启动时间"
},
"sidebar": {
"defaultTitle": "医院管理系统"
},
"table": {
"index": "#",
"action": "操作",

View File

@@ -21,7 +21,7 @@
</template>
<!-- 帮助中心按钮 -->
<el-tooltip
content="帮助中心"
:content="$t('navbar.helpCenter')"
placement="bottom"
>
<div
@@ -33,7 +33,7 @@
</el-tooltip>
<!-- 主题/布局设置 -->
<el-tooltip
content="主题设置"
:content="$t('navbar.themeSettings')"
placement="bottom"
>
<div
@@ -76,19 +76,19 @@
<template #dropdown>
<el-dropdown-menu>
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>{{ $t('navbar.profile') }}</el-dropdown-item>
</router-link>
<el-dropdown-item
divided
command="lockScreen"
>
<span>锁定屏幕</span>
<span>{{ $t('navbar.lockScreen') }}</span>
</el-dropdown-item>
<el-dropdown-item
divided
command="logout"
>
<span>退出登录</span>
<span>{{ $t('navbar.logout') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
@@ -121,7 +121,7 @@
</div>
<el-dialog
v-model="showDialog"
title="切换科室"
:title="$t('navbar.switchDepartment')"
width="400px"
teleported
destroy-on-close
@@ -144,10 +144,10 @@
type="primary"
@click="submit"
>
确定
{{ $t('common.confirm') }}
</el-button>
<el-button @click="showDialog = false">
取消
{{ $t('common.cancel') }}
</el-button>
</div>
</template>
@@ -166,7 +166,9 @@ import useUserStore from '@/store/modules/user';
import useLockStore from '@/store/modules/lock';
import usePermissionStore from '@/store/modules/permission';
import {getOrg, switchOrg} from '@/api/login';
import {useI18n} from 'vue-i18n';
const {t} = useI18n();
const appStore = useAppStore();
const userStore = useUserStore();
const lockStore = useLockStore();
@@ -213,10 +215,10 @@ async function loadOrgList() {
async function handleOrgSwitch(val) {
const selectedOrg = orgOptions.value.find(item => item.orgId === val);
const orgName = selectedOrg ? selectedOrg.orgName : '该科室';
ElMessageBox.confirm(`确定要切换到科室"${orgName}"吗?`, '切换科室', {
confirmButtonText: '确定',
cancelButtonText: '取消',
const orgName = selectedOrg ? selectedOrg.orgName : t('navbar.switchDepartment');
ElMessageBox.confirm(t('navbar.switchDepartmentConfirm', {name: orgName}), t('navbar.switchDepartment'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning'
}).then(async () => {
try {
@@ -233,9 +235,9 @@ function submit() {
}
function logout() {
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
ElMessageBox.confirm(t('navbar.logoutConfirm'), t('common.tip'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning'
}).then(() => {
userStore.logOut().then(() => {

View File

@@ -40,6 +40,9 @@ import variables from '@/assets/styles/variables.module.scss';
import useSettingsStore from '@/store/modules/settings';
import useUserStore from '@/store/modules/user';
import {computed} from 'vue';
import {useI18n} from 'vue-i18n';
const {t} = useI18n();
defineProps({
collapse: {
@@ -48,7 +51,7 @@ defineProps({
},
});
const title = import.meta.env.VITE_APP_TITLE || '医院管理系统';
const title = computed(() => import.meta.env.VITE_APP_TITLE || t('sidebar.defaultTitle'));
const settingsStore = useSettingsStore();
const userStore = useUserStore();
const sideTheme = computed(() => settingsStore.sideTheme);

View File

@@ -1,16 +1,16 @@
<template>
<div style="padding:16px">
<div style="margin-bottom:16px;display:flex;justify-content:space-between;align-items:center">
<span style="font-size:18px;font-weight:bold">系统仪表盘</span>
<span style="font-size:18px;font-weight:bold">{{ $t('dashboard.title') }}</span>
<div>
<el-tag v-if="wsConnected" type="success" size="small" style="margin-right:8px">
实时连接
{{ $t('dashboard.realtimeConnected') }}
</el-tag>
<el-tag v-else type="danger" size="small" style="margin-right:8px">
离线
{{ $t('dashboard.offline') }}
</el-tag>
<el-button type="primary" @click="loadData">刷新</el-button>
<el-button type="info" @click="showSystemInfo = true">系统信息</el-button>
<el-button type="primary" @click="loadData">{{ $t('common.refresh') }}</el-button>
<el-button type="info" @click="showSystemInfo = true">{{ $t('dashboard.systemInfo') }}</el-button>
</div>
</div>
@@ -21,7 +21,7 @@
{{ overview.systemName || 'HealthLink-HIS' }}
</h2>
<p style="color:#666;margin:8px 0;font-size:14px">
版本: {{ overview.version || 'v2.0' }} | 环境: {{ overview.env || '开发环境' }}
{{ $t('dashboard.version') }}: {{ overview.version || 'v2.0' }} | {{ $t('dashboard.env') }}: {{ overview.env || $t('dashboard.devEnv') }}
</p>
</div>
</el-card>
@@ -50,7 +50,7 @@
<el-col :span="24">
<el-card shadow="never">
<template #header>
<span style="color:#F56C6C"> 实时预警</span>
<span style="color:#F56C6C">{{ $t('dashboard.realtimeAlert') }}</span>
</template>
<el-alert
v-for="alert in alerts"
@@ -71,7 +71,7 @@
<el-card shadow="hover" :body-style="{padding:'12px'}">
<div style="text-align:center">
<div style="font-size:20px;font-weight:bold;color:#409eff">{{ formatMoney(dashData.totalRevenue) }}</div>
<div style="font-size:12px;color:#999">总收入()</div>
<div style="font-size:12px;color:#999">{{ $t('dashboard.totalRevenue') }}</div>
</div>
</el-card>
</el-col>
@@ -79,7 +79,7 @@
<el-card shadow="hover" :body-style="{padding:'12px'}">
<div style="text-align:center">
<div style="font-size:20px;font-weight:bold;color:#67c23a">{{ formatMoney(dashData.totalProfit) }}</div>
<div style="font-size:12px;color:#999">总利润()</div>
<div style="font-size:12px;color:#999">{{ $t('dashboard.totalProfit') }}</div>
</div>
</el-card>
</el-col>
@@ -87,7 +87,7 @@
<el-card shadow="hover" :body-style="{padding:'12px'}">
<div style="text-align:center">
<div style="font-size:20px;font-weight:bold;color:#e6a23c">{{ dashData.totalPatients || 0 }}</div>
<div style="font-size:12px;color:#999">总患者数</div>
<div style="font-size:12px;color:#999">{{ $t('dashboard.totalPatients') }}</div>
</div>
</el-card>
</el-col>
@@ -95,7 +95,7 @@
<el-card shadow="hover" :body-style="{padding:'12px'}">
<div style="text-align:center">
<div style="font-size:20px;font-weight:bold;color:#f56c6c">{{ dashData.totalDrgCases || 0 }}</div>
<div style="font-size:12px;color:#999">DRG病例数</div>
<div style="font-size:12px;color:#999">{{ $t('dashboard.drgCases') }}</div>
</div>
</el-card>
</el-col>
@@ -103,7 +103,7 @@
<!-- 功能模块 -->
<el-card shadow="never" style="margin-bottom:16px">
<template #header>功能模块 ({{ modules.length }})</template>
<template #header>{{ $t('dashboard.featureModules') }} ({{ modules.length }})</template>
<el-row :gutter="12">
<el-col v-for="mod in modules" :key="mod.name" :span="4">
<el-card shadow="hover" style="text-align:center;margin-bottom:12px;cursor:pointer" @click="handleModuleClick(mod)">
@@ -119,7 +119,7 @@
<el-row :gutter="16" style="margin-bottom:16px">
<el-col :span="12">
<el-card shadow="never">
<template #header>快捷操作</template>
<template #header>{{ $t('dashboard.quickActions') }}</template>
<div style="display:flex;flex-wrap:wrap;gap:8px">
<el-button v-for="action in quickActions" :key="action.label" :type="action.type" @click="handleAction(action)">
{{ action.icon }} {{ action.label }}
@@ -129,7 +129,7 @@
</el-col>
<el-col :span="12">
<el-card shadow="never">
<template #header>最近操作</template>
<template #header>{{ $t('dashboard.recentOperations') }}</template>
<el-timeline style="padding-left:10px">
<el-timeline-item v-for="(log, index) in recentLogs" :key="index" :timestamp="log.time" placement="top" :type="log.type">
{{ log.content }}
@@ -142,71 +142,78 @@
<!-- 系统信息弹窗 -->
<el-dialog
v-model="showSystemInfo"
title="系统信息"
:title="$t('dashboard.systemInfo')"
width="600px"
append-to-body
>
<el-descriptions :column="2" border>
<el-descriptions-item label="系统名称">{{ overview.systemName || 'HealthLink-HIS' }}</el-descriptions-item>
<el-descriptions-item label="版本号">{{ overview.version || 'v2.0' }}</el-descriptions-item>
<el-descriptions-item label="运行环境">{{ overview.env || '开发环境' }}</el-descriptions-item>
<el-descriptions-item label="后端端口">{{ overview.backendPort || '18082' }}</el-descriptions-item>
<el-descriptions-item label="数据库表">{{ overview.totalTables || 0 }}</el-descriptions-item>
<el-descriptions-item label="API接口">{{ overview.totalApis || 0 }}</el-descriptions-item>
<el-descriptions-item label="功能模块">{{ modules.length }}</el-descriptions-item>
<el-descriptions-item label="启动时间">{{ overview.startTime || '-' }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.systemName')">{{ overview.systemName || 'HealthLink-HIS' }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.versionNumber')">{{ overview.version || 'v2.0' }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.runEnv')">{{ overview.env || $t('dashboard.devEnv') }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.backendPort')">{{ overview.backendPort || '18082' }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.dbTableCount')">{{ overview.totalTables || 0 }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.apiCount')">{{ overview.totalApis || 0 }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.moduleCount')">{{ modules.length }}</el-descriptions-item>
<el-descriptions-item :label="$t('dashboard.startTime')">{{ overview.startTime || '-' }}</el-descriptions-item>
</el-descriptions>
<template #footer>
<el-button @click="showSystemInfo = false">关闭</el-button>
<el-button @click="showSystemInfo = false">{{ $t('common.close') }}</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {ref, onMounted, onUnmounted} from 'vue'
import {ref, computed, onMounted, onUnmounted} from 'vue'
import {useI18n} from 'vue-i18n'
import {ElMessage} from 'element-plus'
import {Top, Bottom} from '@element-plus/icons-vue'
import {getDashboardOverview, getDashboardData} from './api'
const {t} = useI18n()
const overview = ref({})
const dashData = ref({})
const showSystemInfo = ref(false)
const wsConnected = ref(false)
const alerts = ref([])
const statsData = ref({
totalTables: 0, totalApis: 0, totalMenus: 0,
onlineUsers: 0, todayOperations: 0
})
let ws = null
const statCards = ref([
{label:'数据库表', value:0, color:'#409eff', trend:0, alert:''},
{label:'API接口', value:0, color:'#67c23a', trend:0, alert:''},
{label:'功能模块', value:0, color:'#e6a23c', trend:0, alert:''},
{label:'菜单数', value:0, color:'#f56c6c', trend:0, alert:''},
{label:'在线用户', value:0, color:'#909399', trend:0, alert:''},
{label:'今日操作', value:0, color:'#409eff', trend:0, alert:''}
const statCards = computed(() => [
{label: t('dashboard.dbTables'), value: statsData.value.totalTables, color: '#409eff', trend: 0, alert: ''},
{label: t('dashboard.apiInterfaces'), value: statsData.value.totalApis, color: '#67c23a', trend: 0, alert: ''},
{label: t('dashboard.modules'), value: statsData.value.moduleCount, color: '#e6a23c', trend: 0, alert: ''},
{label: t('dashboard.menuCount'), value: statsData.value.totalMenus, color: '#f56c6c', trend: 0, alert: ''},
{label: t('dashboard.onlineUsers'), value: statsData.value.onlineUsers, color: '#909399', trend: 0, alert: ''},
{label: t('dashboard.todayOps'), value: statsData.value.todayOperations, color: '#409eff', trend: 0, alert: ''}
])
const modules = ref([
{name:'门诊管理', icon:'🏥', desc:'挂号/收费/处方'},
{name:'住院管理', icon:'🛏️', desc:'入院/出院/医嘱'},
{name:'药房管理', icon:'💊', desc:'发药/库存/追溯'},
{name:'护理管理', icon:'💉', desc:'评估/执行/质量'},
{name:'检验管理', icon:'🔬', desc:'标本/报告/历史'},
{name:'影像管理', icon:'📷', desc:'检查/报告/对比'},
{name:'麻醉管理', icon:'💉', desc:'记录/随访/质控'},
{name:'手术管理', icon:'🔪', desc:'排班/安全/记录'},
{name:'院感管理', icon:'🦠', desc:'监测/预警/报告'},
{name:'质控管理', icon:'📊', desc:'病历/护理/运行'},
{name:'中医管理', icon:'🌿', desc:'方剂/体质/处方'},
{name:'会诊管理', icon:'👥', desc:'申请/确认/反馈'}
const modules = computed(() => [
{name: t('dashboard.outpatientMgmt'), icon: '🏥', desc: t('dashboard.outpatientDesc')},
{name: t('dashboard.inpatientMgmt'), icon: '🛏️', desc: t('dashboard.inpatientDesc')},
{name: t('dashboard.pharmacyMgmt'), icon: '💊', desc: t('dashboard.pharmacyDesc')},
{name: t('dashboard.nursingMgmt'), icon: '💉', desc: t('dashboard.nursingDesc')},
{name: t('dashboard.labMgmt'), icon: '🔬', desc: t('dashboard.labDesc')},
{name: t('dashboard.imagingMgmt'), icon: '📷', desc: t('dashboard.imagingDesc')},
{name: t('dashboard.anesthesiaMgmt'), icon: '💉', desc: t('dashboard.anesthesiaDesc')},
{name: t('dashboard.surgeryMgmt'), icon: '🔪', desc: t('dashboard.surgeryDesc')},
{name: t('dashboard.infectionMgmt'), icon: '🦠', desc: t('dashboard.infectionDesc')},
{name: t('dashboard.qualityMgmt'), icon: '📊', desc: t('dashboard.qualityDesc')},
{name: t('dashboard.tcmMgmt'), icon: '🌿', desc: t('dashboard.tcmDesc')},
{name: t('dashboard.consultMgmt'), icon: '👥', desc: t('dashboard.consultDesc')}
])
const quickActions = ref([
{label:'挂号', icon:'📋', type:'primary', path:'/charge/cliniccharge'},
{label:'开方', icon:'💊', type:'success', path:'/doctorstation'},
{label:'发药', icon:'💉', type:'warning', path:'/pharmacyManagement'},
{label:'检验', icon:'🔬', type:'info', path:'/inspection'},
{label:'质控', icon:'📊', type:'danger', path:'/qualityenhanced'},
{label:'报表', icon:'📈', type:'', path:'/businessanalytics'}
const quickActions = computed(() => [
{label: t('dashboard.actionRegister'), icon: '📋', type: 'primary', path: '/charge/cliniccharge'},
{label: t('dashboard.actionPrescribe'), icon: '💊', type: 'success', path: '/doctorstation'},
{label: t('dashboard.actionDispense'), icon: '💉', type: 'warning', path: '/pharmacyManagement'},
{label: t('dashboard.actionLab'), icon: '🔬', type: 'info', path: '/inspection'},
{label: t('dashboard.actionQuality'), icon: '📊', type: 'danger', path: '/qualityenhanced'},
{label: t('dashboard.actionReport'), icon: '📈', type: '', path: '/businessanalytics'}
])
const recentLogs = ref([])
@@ -221,12 +228,14 @@ async function loadData() {
const [r, d] = await Promise.all([getDashboardOverview(), getDashboardData()])
overview.value = r.data || {}
dashData.value = d.data || {}
statCards.value[0].value = overview.value.totalTables || 0
statCards.value[1].value = overview.value.totalApis || 0
statCards.value[2].value = modules.value.length
statCards.value[3].value = overview.value.totalMenus || 0
statCards.value[4].value = overview.value.onlineUsers || 0
statCards.value[5].value = overview.value.todayOperations || 0
statsData.value = {
totalTables: overview.value.totalTables || 0,
totalApis: overview.value.totalApis || 0,
moduleCount: modules.value.length,
totalMenus: overview.value.totalMenus || 0,
onlineUsers: overview.value.onlineUsers || 0,
todayOperations: overview.value.todayOperations || 0
}
} catch(e) {}
}
@@ -253,20 +262,20 @@ function initWebSocket() {
wsConnected.value = false
}
} catch (e) {
console.error('WebSocket连接失败:', e)
console.error('WebSocket connection failed:', e)
}
}
function handleRealtimeUpdate(data) {
if (data.type === 'STATISTICS') {
if (data.onlineUsers !== undefined) {
const prev = statCards.value[4].value
statCards.value[4].value = data.onlineUsers
const prev = statsData.value.onlineUsers
statsData.value = {...statsData.value, onlineUsers: data.onlineUsers}
statCards.value[4].trend = data.onlineUsers - prev
}
if (data.todayOperations !== undefined) {
const prev = statCards.value[5].value
statCards.value[5].value = data.todayOperations
const prev = statsData.value.todayOperations
statsData.value = {...statsData.value, todayOperations: data.todayOperations}
statCards.value[5].trend = data.todayOperations - prev
}
} else if (data.type === 'ALERT') {
@@ -282,7 +291,7 @@ function handleRealtimeUpdate(data) {
} else if (data.type === 'RECENT_LOG') {
recentLogs.value.unshift({
content: data.content,
time: data.time || '刚刚',
time: data.time || t('dashboard.justNow'),
type: data.logType || 'primary'
})
if (recentLogs.value.length > 10) {
@@ -292,11 +301,11 @@ function handleRealtimeUpdate(data) {
}
function handleModuleClick(mod) {
ElMessage.info('进入模块: ' + mod.name)
ElMessage.info(t('dashboard.enterModule') + ': ' + mod.name)
}
function handleAction(action) {
ElMessage.info('跳转: ' + action.label)
ElMessage.info(t('dashboard.navigateTo') + ': ' + action.label)
}
onMounted(() => {

View File

@@ -18,7 +18,7 @@
{{ currentTenantName || settings.systemName }}
</h1>
<p class="brand-subtitle">
信息管理系统
{{ $t('login.systemSubtitle') }}
</p>
<div class="brand-features">
<div class="feature-item">
@@ -37,8 +37,8 @@
</svg>
</div>
<div class="feature-text">
<span class="feature-label">安全可靠</span>
<span class="feature-desc">全方位数据安全保障</span>
<span class="feature-label">{{ $t('login.featureSecure') }}</span>
<span class="feature-desc">{{ $t('login.featureSecureDesc') }}</span>
</div>
</div>
<div class="feature-item">
@@ -57,8 +57,8 @@
</svg>
</div>
<div class="feature-text">
<span class="feature-label">高效便捷</span>
<span class="feature-desc">智能化医疗业务流程</span>
<span class="feature-label">{{ $t('login.featureEfficient') }}</span>
<span class="feature-desc">{{ $t('login.featureEfficientDesc') }}</span>
</div>
</div>
<div class="feature-item">
@@ -77,26 +77,45 @@
</svg>
</div>
<div class="feature-text">
<span class="feature-label">协同办公</span>
<span class="feature-desc">多科室多角色无缝协作</span>
<span class="feature-label">{{ $t('login.featureCollab') }}</span>
<span class="feature-desc">{{ $t('login.featureCollabDesc') }}</span>
</div>
</div>
</div>
</div>
<div class="brand-footer">
<p>技术支持上海经创贺联信息技术有限公司</p>
<p>{{ $t('login.techSupport') }}</p>
</div>
</div>
<!-- 右侧登录区 -->
<div class="login-panel">
<div class="lang-switcher">
<el-dropdown @command="handleLangChange">
<span class="lang-trigger">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="lang-icon">
<path d="M12 21a9 9 0 100-18 9 9 0 000 18z" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.6 9h16.8M3.6 15h16.8M12 3a15.3 15.3 0 014 9 15.3 15.3 0 01-4 9 15.3 15.3 0 01-4-9 15.3 15.3 0 014-9z" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="lang-label">{{ langLabel }}</span>
<el-icon><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="zh-CN" :class="{ 'is-active': currentLang === 'zh-CN' }">简体中文</el-dropdown-item>
<el-dropdown-item command="en" :class="{ 'is-active': currentLang === 'en' }">English</el-dropdown-item>
<el-dropdown-item command="vi" :class="{ 'is-active': currentLang === 'vi' }">Tiếng Việt</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div class="login-card">
<div class="login-header">
<h2 class="login-title">
欢迎回来
{{ $t('login.welcomeBack') }}
</h2>
<p class="login-desc">
请使用您的账号密码安全登录系统
{{ $t('login.loginDesc') }}
</p>
</div>
@@ -108,12 +127,12 @@
size="large"
>
<el-form-item prop="username">
<label class="field-label">用户名</label>
<label class="field-label">{{ $t('login.account') }}</label>
<el-input
v-model="loginForm.username"
type="text"
auto-complete="off"
placeholder="请输入账号"
:placeholder="$t('login.placeholderAccount')"
class="premium-input"
@input="handleUsernameChange"
>
@@ -127,12 +146,12 @@
</el-form-item>
<el-form-item prop="password">
<label class="field-label">密码</label>
<label class="field-label">{{ $t('login.password') }}</label>
<el-input
v-model="loginForm.password"
:type="passwordVisible ? 'text' : 'password'"
auto-complete="off"
placeholder="请输入密码"
:placeholder="$t('login.placeholderPassword')"
class="premium-input"
@keyup.enter="handleLogin"
>
@@ -147,17 +166,17 @@
class="password-toggle"
@click="togglePasswordVisibility"
>
{{ passwordVisible ? '隐藏' : '显示' }}
{{ passwordVisible ? $t('login.hide') : $t('login.show') }}
</span>
</template>
</el-input>
</el-form-item>
<el-form-item prop="tenantId">
<label class="field-label">医疗机构</label>
<label class="field-label">{{ $t('login.medicalInstitution') }}</label>
<el-select
v-model="loginForm.tenantId"
placeholder="请选择医疗机构"
:placeholder="$t('login.placeholderMedicalInstitution')"
clearable
filterable
class="premium-select"
@@ -173,7 +192,7 @@
<el-form-item class="switch-item">
<div class="switch-row">
<span class="switch-label">连接医保</span>
<span class="switch-label">{{ $t('login.connectMedicalInsurance') }}</span>
<el-switch
v-model="loginForm.invokeYb"
@change="topNavChange"
@@ -191,26 +210,26 @@
<span
v-if="!loading"
class="btn-text"
> </span>
>{{ $t('login.loginButtonText') }}</span>
<span
v-else-if="!signIng"
class="btn-text"
>登录中...</span>
>{{ $t('login.loggingIn') }}</span>
<span
v-else
class="btn-text"
>连接医保中...</span>
>{{ $t('login.connectingInsurance') }}</span>
</el-button>
</el-form-item>
</el-form>
<div class="login-footer-info">
<p class="version-info">
前端 v{{ formattedFrontendVersion }}
<span v-if="backendVersion">&nbsp;·&nbsp;后端 v{{ formattedBackendVersion }}</span>
{{ $t('login.frontendVersion') }} v{{ formattedFrontendVersion }}
<span v-if="backendVersion">&nbsp;·&nbsp;{{ $t('login.backendVersion') }} v{{ formattedBackendVersion }}</span>
</p>
<p class="copyright">
&copy; 2025 {{ currentTenantName || settings.systemName }}信息管理系统
&copy; 2025 {{ currentTenantName || settings.systemName }}{{ $t('login.copyrightSystem') }}
</p>
</div>
</div>
@@ -219,8 +238,10 @@
</template>
<script setup>
import {computed, getCurrentInstance, onMounted, ref, watch, nextTick} from 'vue';
import {useI18n} from 'vue-i18n';
import settings from '@/settings';
import {getCodeImg, getUserBindTenantList, sign} from '@/api/login';
import {changeLocale} from '@/i18n';
import {invokeYbPlugin5001} from '@/api/public';
import Cookies from 'js-cookie';
import {decrypt, encrypt} from '@/utils/jsencrypt';
@@ -233,6 +254,16 @@ const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const { proxy } = getCurrentInstance();
const { t, locale } = useI18n();
const currentLang = ref(locale.value);
const langLabel = computed(() => {
const map = { 'zh-CN': '中文', 'en': 'English', 'vi': 'Tiếng Việt' }
return map[currentLang.value] || '中文'
});
const handleLangChange = async (lang) => {
currentLang.value = lang;
await changeLocale(lang);
};
const env = import.meta.env.MODE;
const loginVersion = import.meta.env.VITE_APP_BUILD_VERSION;
const backendVersion = ref('');
@@ -272,11 +303,11 @@ const loginForm = ref({
const tenantOptions = ref([]);
const currentTenantName = ref('');
const loginRules = {
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
code: [{ required: true, trigger: 'change', message: '请输入验证码' }],
};
const loginRules = computed(() => ({
username: [{ required: true, trigger: 'blur', message: t('login.validationUsername') }],
password: [{ required: true, trigger: 'blur', message: t('login.validationPassword') }],
code: [{ required: true, trigger: 'change', message: t('login.validationCaptcha') }],
}));
const codeUrl = ref('');
const loading = ref(false);
@@ -297,7 +328,7 @@ function handleForgotPassword() {
// 这里可以添加忘记密码的逻辑,例如跳转到忘记密码页面或显示忘记密码弹窗
// 目前先显示一个提示
ElMessage({
message: '忘记密码功能正在开发中',
message: t('login.forgotPasswordTip'),
type: 'info'
});
}
@@ -550,7 +581,7 @@ async function signIn(mac, ip) {
userStore.logOut();
signIng.value = false;
loading.value = false;
proxy.$message.error('医保签到失败');
proxy.$message.error(t('login.signInFailed'));
console.error('签到失败:', error);
}
}
@@ -754,6 +785,34 @@ html, body {
padding-top: 32px;
p { margin: 0; }
}
.lang-switcher {
position: absolute;
top: 20px;
right: 20px;
z-index: 10;
.lang-trigger {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
padding: 6px 12px;
border-radius: 8px;
color: #606266;
font-size: 13px;
transition: all 0.2s;
&:hover {
background: rgba(0, 0, 0, 0.04);
color: #409eff;
}
.lang-icon {
width: 16px;
height: 16px;
}
.lang-label {
font-weight: 500;
}
}
}
.login-panel {
flex: 0 0 45%;
display: flex;

View File

@@ -1,4 +1,4 @@
<template>
<template>
<div class="app-container">
<el-form
v-show="showSearch"
@@ -9,36 +9,36 @@
class="query-form"
>
<el-form-item
label="角色名称"
:label="$t('system.role.roleName')"
prop="roleName"
>
<el-input
v-model="queryParams.roleName"
placeholder="请输入角色名称"
:placeholder="$t('system.role.enterRoleName')"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item
label="权限字符"
:label="$t('system.role.roleKey')"
prop="roleKey"
>
<el-input
v-model="queryParams.roleKey"
placeholder="请输入权限字符"
:placeholder="$t('system.role.enterRoleKey')"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item
label="状态"
:label="$t('common.status')"
prop="status"
>
<el-select
v-model="queryParams.status"
placeholder="角色状态"
:placeholder="$t('system.role.roleStatus')"
clearable
style="width: 240px"
>
@@ -51,7 +51,7 @@
</el-select>
</el-form-item>
<el-form-item
label="创建时间"
:label="$t('common.createTime')"
style="width: 308px"
>
<el-date-picker
@@ -59,8 +59,8 @@
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:start-placeholder="$t('system.role.startDate')"
:end-placeholder="$t('system.role.endDate')"
/>
</el-form-item>
<el-form-item class="search-buttons">
@@ -69,13 +69,13 @@
icon="Search"
@click="handleQuery"
>
搜索
{{ $t('common.search') }}
</el-button>
<el-button
icon="Refresh"
@click="resetQuery"
>
重置
{{ $t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
@@ -91,7 +91,7 @@
icon="Plus"
@click="handleAdd"
>
新增
{{ $t('common.add') }}
</el-button>
</el-col>
<el-col :span="1.5">
@@ -103,7 +103,7 @@
:disabled="single"
@click="handleUpdate"
>
修改
{{ $t('common.edit') }}
</el-button>
</el-col>
<el-col :span="1.5">
@@ -115,7 +115,7 @@
:disabled="multiple"
@click="handleDelete"
>
删除
{{ $t('common.delete') }}
</el-button>
</el-col>
<el-col :span="1.5">
@@ -126,7 +126,7 @@
icon="Download"
@click="handleExport"
>
导出
{{ $t('common.export') }}
</el-button>
</el-col>
<right-toolbar
@@ -147,29 +147,29 @@
align="center"
/>
<vxe-column
title="角色编号"
:title="$t('system.role.roleId')"
field="roleId"
width="120"
/>
<vxe-column
title="角色名称"
:title="$t('system.role.roleName')"
field="roleName"
show-overflow="title"
width="150"
/>
<vxe-column
title="权限字符"
:title="$t('system.role.roleKey')"
field="roleKey"
show-overflow="title"
width="150"
/>
<vxe-column
title="显示顺序"
:title="$t('system.role.roleSort')"
field="roleSort"
width="100"
/>
<vxe-column
title="状态"
:title="$t('common.status')"
align="center"
width="100"
>
@@ -183,7 +183,7 @@
</template>
</vxe-column>
<vxe-column
title="创建时间"
:title="$t('common.createTime')"
align="center"
field="createTime"
>
@@ -192,14 +192,14 @@
</template>
</vxe-column>
<vxe-column
title="操作"
:title="$t('common.operation')"
align="center"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-tooltip
v-if="scope.row.roleId !== 1"
content="修改"
:content="$t('common.edit')"
placement="top"
>
<el-button
@@ -213,7 +213,7 @@
</el-tooltip>
<el-tooltip
v-if="scope.row.roleId !== 1"
content="删除"
:content="$t('common.delete')"
placement="top"
>
<el-button
@@ -227,7 +227,7 @@
</el-tooltip>
<el-tooltip
v-if="scope.row.roleId !== 1"
content="数据权限"
:content="$t('system.role.dataScope')"
placement="top"
>
<el-button
@@ -241,7 +241,7 @@
</el-tooltip>
<el-tooltip
v-if="scope.row.roleId !== 1"
content="分配用户"
:content="$t('system.role.assignUser')"
placement="top"
>
<el-button
@@ -281,33 +281,33 @@
label-width="100px"
>
<el-form-item
label="角色名称"
:label="$t('system.role.roleName')"
prop="roleName"
>
<el-input
v-model="form.roleName"
placeholder="请输入角色名称"
:placeholder="$t('system.role.enterRoleName')"
/>
</el-form-item>
<el-form-item prop="roleKey">
<template #label>
<span>
<el-tooltip
content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)"
:content="$t('system.role.permissionTooltip')"
placement="top"
>
<el-icon><question-filled /></el-icon>
</el-tooltip>
权限字符
{{ $t('system.role.permissionChar') }}
</span>
</template>
<el-input
v-model="form.roleKey"
placeholder="请输入权限字符"
:placeholder="$t('system.role.enterRoleKey')"
/>
</el-form-item>
<el-form-item
label="角色顺序"
:label="$t('system.role.roleOrder')"
prop="roleSort"
>
<el-input-number
@@ -316,7 +316,7 @@
:min="0"
/>
</el-form-item>
<el-form-item label="状态">
<el-form-item :label="$t('common.status')">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
@@ -327,24 +327,24 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单权限">
<el-form-item :label="$t('system.role.menuPermission')">
<el-checkbox
v-model="menuExpand"
@change="handleCheckedTreeExpand($event, 'menu')"
>
展开/折叠
{{ $t('system.role.expandCollapse') }}
</el-checkbox>
<el-checkbox
v-model="menuNodeAll"
@change="handleCheckedTreeNodeAll($event, 'menu')"
>
全选/全不选
{{ $t('system.role.selectAll') }}
</el-checkbox>
<el-checkbox
v-model="form.menuCheckStrictly"
@change="handleCheckedTreeConnect($event, 'menu')"
>
父子联动
{{ $t('system.role.parentChildLink') }}
</el-checkbox>
<el-tree
ref="menuRef"
@@ -353,15 +353,15 @@
show-checkbox
node-key="id"
:check-strictly="!form.menuCheckStrictly"
empty-text="加载中请稍候"
:empty-text="$t('system.role.loadingPleaseWait')"
:props="{ label: 'label', children: 'children' }"
/>
</el-form-item>
<el-form-item label="备注">
<el-form-item :label="$t('common.remark')">
<el-input
v-model="form.remark"
type="textarea"
placeholder="请输入内容"
:placeholder="$t('system.user.enterContent')"
/>
</el-form-item>
</el-form>
@@ -371,10 +371,10 @@
type="primary"
@click="submitForm"
>
{{ $t('common.confirm') }}
</el-button>
<el-button @click="cancel">
{{ $t('common.cancel') }}
</el-button>
</div>
</template>
@@ -391,19 +391,19 @@
:model="form"
label-width="80px"
>
<el-form-item label="角色名称">
<el-form-item :label="$t('system.role.roleName')">
<el-input
v-model="form.roleName"
:disabled="true"
/>
</el-form-item>
<el-form-item label="权限字符">
<el-form-item :label="$t('system.role.roleKey')">
<el-input
v-model="form.roleKey"
:disabled="true"
/>
</el-form-item>
<el-form-item label="权限范围">
<el-form-item :label="$t('system.role.permissionScope')">
<el-select
v-model="form.dataScope"
@change="dataScopeSelectChange"
@@ -418,25 +418,25 @@
</el-form-item>
<el-form-item
v-show="form.dataScope == 2"
label="数据权限"
:label="$t('system.role.dataPermission')"
>
<el-checkbox
v-model="deptExpand"
@change="handleCheckedTreeExpand($event, 'dept')"
>
展开/折叠
{{ $t('system.role.expandCollapse') }}
</el-checkbox>
<el-checkbox
v-model="deptNodeAll"
@change="handleCheckedTreeNodeAll($event, 'dept')"
>
全选/全不选
{{ $t('system.role.selectAll') }}
</el-checkbox>
<el-checkbox
v-model="form.deptCheckStrictly"
@change="handleCheckedTreeConnect($event, 'dept')"
>
父子联动
{{ $t('system.role.parentChildLink') }}
</el-checkbox>
<el-tree
ref="deptRef"
@@ -446,7 +446,7 @@
default-expand-all
node-key="id"
:check-strictly="!form.deptCheckStrictly"
empty-text="加载中请稍候"
:empty-text="$t('system.role.loadingPleaseWait')"
:props="{ label: 'label', children: 'children' }"
/>
</el-form-item>
@@ -457,10 +457,10 @@
type="primary"
@click="submitDataScope"
>
{{ $t('common.confirm') }}
</el-button>
<el-button @click="cancelDataScope">
{{ $t('common.cancel') }}
</el-button>
</div>
</template>
@@ -480,8 +480,10 @@ import {
updateRole
} from "@/api/system/role";
import {roleMenuTreeselect, treeselect as menuTreeselect} from "@/api/system/menu";
import { useI18n } from 'vue-i18n';
const router = useRouter();
const { t } = useI18n();
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
@@ -506,12 +508,12 @@ const menuRef = ref(null);
const deptRef = ref(null);
/** 数据范围选项*/
const dataScopeOptions = ref([
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
const dataScopeOptions = computed(() => [
{ value: "1", label: t('system.role.allDataPermission') },
{ value: "2", label: t('system.role.customDataPermission') },
{ value: "3", label: t('system.role.deptDataPermission') },
{ value: "4", label: t('system.role.deptAndChildrenPermission') },
{ value: "5", label: t('system.role.selfDataPermission') }
]);
const data = reactive({
@@ -523,14 +525,15 @@ const data = reactive({
roleKey: undefined,
status: undefined
},
rules: {
roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
},
});
const { queryParams, form, rules } = toRefs(data);
const { queryParams, form } = toRefs(data);
const rules = computed(() => ({
roleName: [{ required: true, message: t('system.role.valNameRequired'), trigger: "blur" }],
roleKey: [{ required: true, message: t('system.role.valKeyRequired'), trigger: "blur" }],
roleSort: [{ required: true, message: t('system.role.valSortRequired'), trigger: "blur" }]
}));
/** 查询角色列表 */
function getList() {
@@ -555,11 +558,11 @@ function resetQuery() {
/** 删除按钮操作 */
function handleDelete(row) {
const roleIds = row.roleId || ids.value;
proxy.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function () {
proxy.$modal.confirm(t('system.role.deleteConfirm', { id: roleIds })).then(function () {
return delRole(roleIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
proxy.$modal.msgSuccess(t('message.deleteSuccess'));
}).catch(() => {});
}
/** 导出按钮操作 */
@@ -576,11 +579,11 @@ function handleSelectionChange(selection) {
}
/** 角色状态修改 */
function handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
let text = row.status === "0" ? t('common.enabled') : t('common.disabled');
proxy.$modal.confirm(t('system.user.statusConfirm', { action: text, username: row.roleName })).then(function () {
return changeRoleStatus(row.roleId, row.status);
}).then(() => {
proxy.$modal.msgSuccess(text + "成功");
proxy.$modal.msgSuccess(text + t('common.success'));
}).catch(function () {
row.status = row.status === "0" ? "1" : "0";
});
@@ -645,7 +648,7 @@ function handleAdd() {
reset();
getMenuTreeselect();
open.value = true;
title.value = "添加角色";
title.value = t('system.role.addRole');
}
/** 修改角色 */
function handleUpdate(row) {
@@ -666,7 +669,7 @@ function handleUpdate(row) {
});
});
});
title.value = "修改角色";
title.value = t('system.role.editRole');
});
}
/** 根据角色ID查询菜单树结构 */
@@ -729,14 +732,14 @@ function submitForm() {
if (form.value.roleId != undefined) {
form.value.menuIds = getMenuAllCheckedKeys();
updateRole(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
proxy.$modal.msgSuccess(t('message.editSuccess'));
open.value = false;
getList();
});
} else {
form.value.menuIds = getMenuAllCheckedKeys();
addRole(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
proxy.$modal.msgSuccess(t('message.addSuccess'));
open.value = false;
getList();
});
@@ -771,7 +774,7 @@ function handleDataScope(row) {
});
});
});
title.value = "分配数据权限";
title.value = t('system.role.assignDataPermission');
});
}
/** 提交按钮(数据权限) */
@@ -779,7 +782,7 @@ function submitDataScope() {
if (form.value.roleId != undefined) {
form.value.deptIds = getDeptAllCheckedKeys();
dataScope(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
proxy.$modal.msgSuccess(t('message.editSuccess'));
openDataScope.value = false;
getList();
});

View File

@@ -1,4 +1,4 @@
<template>
<template>
<div class="app-container">
<el-row :gutter="20">
<!--部门数据-->
@@ -9,7 +9,7 @@
<div class="head-container">
<el-input
v-model="deptName"
placeholder="请输入部门名称"
:placeholder="$t('system.user.enterDeptName')"
clearable
prefix-icon="Search"
style="margin-bottom: 20px"
@@ -47,36 +47,36 @@
class="query-form"
>
<el-form-item
label="用户账号"
:label="$t('system.user.userAccount')"
prop="searchKey"
>
<el-input
v-model="queryParams.searchKey"
placeholder="请输入用户账号"
:placeholder="$t('system.user.enterUserAccount')"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item
label="手机号码"
:label="$t('system.user.phone')"
prop="phonenumber"
>
<el-input
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
:placeholder="$t('system.user.enterPhone')"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item
label="状态"
:label="$t('common.status')"
prop="status"
>
<el-select
v-model="queryParams.status"
placeholder="用户状态"
:placeholder="$t('system.user.userStatus')"
clearable
style="width: 240px"
>
@@ -94,13 +94,13 @@
icon="Search"
@click="handleQuery"
>
搜索
{{ $t('common.search') }}
</el-button>
<el-button
icon="Refresh"
@click="resetQuery"
>
重置
{{ $t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
@@ -117,7 +117,7 @@
icon="Plus"
@click="handleAdd"
>
新增
{{ $t('common.add') }}
</el-button>
</el-col>
<el-col :span="1.5">
@@ -129,7 +129,7 @@
:disabled="single"
@click="handleUpdate"
>
修改
{{ $t('common.edit') }}
</el-button>
</el-col>
<el-col :span="1.5">
@@ -141,7 +141,7 @@
:disabled="multiple"
@click="handleDelete"
>
删除
{{ $t('common.delete') }}
</el-button>
</el-col>
<el-col :span="1.5">
@@ -152,7 +152,7 @@
icon="Upload"
@click="handleImport"
>
导入
{{ $t('common.import') }}
</el-button>
</el-col>
<el-col :span="1.5">
@@ -163,7 +163,7 @@
icon="Download"
@click="handleExport"
>
导出
{{ $t('common.export') }}
</el-button>
</el-col>
<right-toolbar
@@ -186,14 +186,14 @@
<vxe-column
v-if="columns[0].visible"
key="userId"
title="用户编号"
:title="$t('system.user.userId')"
align="center"
field="userId"
/>
<vxe-column
v-if="columns[1].visible"
key="userName"
title="用户账号"
:title="$t('system.user.userAccount')"
align="center"
field="userName"
show-overflow="title"
@@ -201,7 +201,7 @@
<vxe-column
v-if="columns[2].visible"
key="nickName"
title="用户姓名"
:title="$t('system.user.nickName')"
align="center"
field="nickName"
show-overflow="title"
@@ -209,7 +209,7 @@
<vxe-column
v-if="columns[3].visible"
key="orgId_dictText"
title="部门"
:title="$t('system.user.deptId')"
align="center"
field="orgId_dictText"
show-overflow="title"
@@ -217,7 +217,7 @@
<vxe-column
v-if="columns[4].visible"
key="phonenumber"
title="手机号码"
:title="$t('system.user.phone')"
align="center"
field="phonenumber"
width="120"
@@ -225,7 +225,7 @@
<vxe-column
v-if="columns[5].visible"
key="status"
title="状态"
:title="$t('common.status')"
align="center"
>
<template #default="scope">
@@ -239,7 +239,7 @@
</vxe-column>
<vxe-column
v-if="columns[6].visible"
title="创建时间"
:title="$t('common.createTime')"
align="center"
field="createTime"
width="160"
@@ -249,7 +249,7 @@
</template>
</vxe-column>
<vxe-column
title="操作"
:title="$t('common.operation')"
align="center"
width="150"
class-name="small-padding fixed-width"
@@ -257,7 +257,7 @@
<template #default="scope">
<el-tooltip
v-if="scope.row.userId !== 1"
content="修改"
:content="$t('common.edit')"
placement="top"
>
<el-button
@@ -271,7 +271,7 @@
</el-tooltip>
<el-tooltip
v-if="scope.row.userId !== 1"
content="删除"
:content="$t('common.delete')"
placement="top"
>
<el-button
@@ -285,7 +285,7 @@
</el-tooltip>
<el-tooltip
v-if="scope.row.userId !== 1"
content="重置密码"
:content="$t('system.user.resetPwd')"
placement="top"
>
<el-button
@@ -299,7 +299,7 @@
</el-tooltip>
<el-tooltip
v-if="scope.row.userId !== 1"
content="分配角色"
:content="$t('system.user.authRole')"
placement="top"
>
<el-button
@@ -340,24 +340,24 @@
label-width="120px"
>
<div class="form-subtitle">
用户信息
{{ $t('system.user.userInfo') }}
</div>
<el-row>
<el-col :span="12">
<el-form-item
label="用户姓名"
:label="$t('system.user.nickName')"
prop="nickName"
>
<el-input
v-model="form.nickName"
placeholder="请输入用户姓名"
:placeholder="$t('system.user.enterUserName')"
maxlength="30"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="责任科室"
:label="$t('system.user.responsibilityDept')"
prop="responsibilityOrgDtoList"
style="width: 100%"
>
@@ -368,7 +368,7 @@
:data="deptOptions"
:props="{ value: 'id', label: 'name', children: 'children' }"
value-key="id"
placeholder="请选择责任科室"
:placeholder="$t('system.user.selectRespDept')"
default-expand-all
check-strictly
@change="handleChange"
@@ -379,24 +379,24 @@
<el-row>
<el-col :span="12">
<el-form-item
label="手机号码"
:label="$t('system.user.phone')"
prop="phonenumber"
>
<el-input
v-model="form.phonenumber"
placeholder="请输入手机号码"
:placeholder="$t('system.user.enterPhone')"
maxlength="11"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="邮箱"
:label="$t('system.user.email')"
prop="email"
>
<el-input
v-model="form.email"
placeholder="请输入邮箱"
:placeholder="$t('system.user.enterEmail')"
maxlength="50"
/>
</el-form-item>
@@ -406,12 +406,12 @@
<el-col :span="12">
<el-form-item
v-if="form.userId == undefined"
label="用户账号"
:label="$t('system.user.userAccount')"
prop="userName"
>
<el-input
v-model="form.userName"
placeholder="请输入用户账号"
:placeholder="$t('system.user.enterUserAccount')"
maxlength="30"
/>
</el-form-item>
@@ -419,12 +419,12 @@
<el-col :span="12">
<el-form-item
v-if="form.userId == undefined"
label="用户密码"
:label="$t('system.user.userPassword')"
prop="password"
>
<el-input
v-model="form.password"
placeholder="请输入用户密码"
:placeholder="$t('system.user.enterPassword')"
type="password"
maxlength="20"
show-password
@@ -434,10 +434,10 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="用户性别">
<el-form-item :label="$t('system.user.sex')">
<el-select
v-model="form.sex"
placeholder="请选择"
:placeholder="$t('common.pleaseSelect')"
>
<el-option
v-for="dict in sys_user_sex"
@@ -449,7 +449,7 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-form-item :label="$t('common.status')">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
@@ -464,11 +464,11 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="出生日期">
<el-form-item :label="$t('system.user.birthDate')">
<el-date-picker
v-model="form.birthDate"
type="date"
placeholder="选择日期"
:placeholder="$t('system.user.selectDate')"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
@@ -476,38 +476,38 @@
</el-col>
<el-col :span="12">
<el-form-item
label="地址"
:label="$t('system.user.address')"
prop="address"
>
<el-input
v-model="form.address"
placeholder="请输入地址"
:placeholder="$t('system.user.enterAddress')"
maxlength="30"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="医保码"
:label="$t('system.user.medicalInsuranceCode')"
prop="ybNo"
>
<el-input
v-model="form.ybNo"
placeholder="请输入医保码"
:placeholder="$t('system.user.enterMedicalCode')"
maxlength="30"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="角色"
:label="$t('system.user.role')"
prop="practitionerRolesDtoListIds"
style="width: 100%"
>
<el-select
v-model="form.practitionerRolesDtoListIds"
multiple
placeholder="请选择"
:placeholder="$t('common.pleaseSelect')"
style="width: 100%"
@change="handleRoleChange"
>
@@ -523,12 +523,12 @@
</el-col>
<el-col :span="12">
<el-form-item
label="职称编码"
:label="$t('system.user.titleCode')"
prop="drProfttlCode"
>
<el-select
v-model="form.drProfttlCode"
placeholder="请选择职称编码"
:placeholder="$t('system.user.selectTitleCode')"
>
<el-option
v-for="dict in drord_dr_profttl"
@@ -541,7 +541,7 @@
</el-col>
<el-col :span="12">
<el-form-item
label="签名图片"
:label="$t('system.user.signatureImage')"
prop="signature"
>
<!-- 上传区域 -->
@@ -558,7 +558,7 @@
>
<div class="upload-placeholder">
<el-icon><Plus /></el-icon>
<p>点击上传图片</p>
<p>{{ $t('system.user.clickToUpload') }}</p>
</div>
</div>
@@ -586,19 +586,19 @@
<el-row>
<el-col :span="24">
<el-form-item
label="职业资格证编号"
:label="$t('system.user.qualificationCertNo')"
prop="pharPracCertNo"
>
<el-input
v-model="form.pharPracCertNo"
placeholder="请输入职业资格证编号"
:placeholder="$t('system.user.enterQualCertNo')"
maxlength="200"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="出诊科室"
:label="$t('system.user.visitDept')"
style="width: 100%"
>
<el-tree-select
@@ -610,7 +610,7 @@
:props="{ value: 'id', label: 'name', children: 'children' }"
value-key="id"
default-expand-all
placeholder="请选择出诊科室"
:placeholder="$t('system.user.selectVisitDept')"
check-strictly
@change="handleLOrgDtoChange"
/>
@@ -618,7 +618,7 @@
</el-col>
<el-col :span="24">
<el-form-item
label="管理药库"
:label="$t('system.user.manageWarehouse')"
style="width: 100%"
>
<el-tree-select
@@ -629,7 +629,7 @@
:data="locationOptions"
:props="{ value: 'id', label: 'name', children: 'children' }"
value-key="id"
placeholder="请选择管理药库"
:placeholder="$t('system.user.selectWarehouse')"
check-strictly
@change="handleLocationChange"
/>
@@ -637,7 +637,7 @@
</el-col>
<el-col :span="24">
<el-form-item
label="管理药房"
:label="$t('system.user.managePharmacy')"
style="width: 100%"
>
<el-tree-select
@@ -648,7 +648,7 @@
:data="pharmacyOptions"
:props="{ value: 'id', label: 'name', children: 'children' }"
value-key="id"
placeholder="请选择管理药房"
:placeholder="$t('system.user.selectPharmacy')"
check-strictly
@change="handlePharmacyChange"
/>
@@ -658,7 +658,7 @@
<el-row>
<el-col :span="12">
<el-form-item
label="管理科室"
:label="$t('system.user.manageDept')"
style="width: 100%"
>
<el-tree-select
@@ -669,7 +669,7 @@
:data="deptOptions"
:props="{ value: 'id', label: 'name', children: 'children' }"
value-key="id"
placeholder="请选择管理科室"
:placeholder="$t('system.user.selectManageDept')"
check-strictly
@change="handleOrgChange"
/>
@@ -677,14 +677,14 @@
</el-col>
<el-col :span="12">
<el-form-item
label="管理病区"
:label="$t('system.user.manageWard')"
style="width: 100%"
>
<el-select
v-model="form.manageWardLocationDtoListIds"
:disabled="nurseShow"
multiple
placeholder="请选择"
:placeholder="$t('common.pleaseSelect')"
style="width: 100%"
@change="handleWardChange"
>
@@ -701,14 +701,14 @@
</el-row>
<el-row>
<div class="form-subtitle">
备注
{{ $t('system.user.remarks') }}
</div>
<el-col :span="24">
<el-form-item label="备注">
<el-form-item :label="$t('common.remark')">
<el-input
v-model="form.remark"
type="textarea"
placeholder="请输入内容"
:placeholder="$t('system.user.enterContent')"
/>
</el-form-item>
</el-col>
@@ -720,10 +720,10 @@
type="primary"
@click="submitForm"
>
{{ $t('common.confirm') }}
</el-button>
<el-button @click="cancel">
{{ $t('common.cancel') }}
</el-button>
</div>
</template>
@@ -751,22 +751,21 @@
<el-icon class="el-icon--upload">
<upload-filled />
</el-icon>
<div class="el-upload__text">
将文件拖到此处<em>点击上传</em>
<div class="el-upload__text" v-html="$t('system.user.dragOrClick')">
</div>
<template #tip>
<div class="el-upload__tip text-center">
<div class="el-upload__tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
<el-checkbox v-model="upload.updateSupport" />{{ $t('system.user.updateExisting') }}
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<span>{{ $t('system.user.importFormatTip') }}</span>
<el-link
type="primary"
:underline="false"
style="font-size: 12px; vertical-align: baseline"
@click="importTemplate"
>
下载模板
{{ $t('system.user.downloadTemplate') }}
</el-link>
</div>
</template>
@@ -777,10 +776,10 @@
type="primary"
@click="submitFileForm"
>
{{ $t('common.confirm') }}
</el-button>
<el-button @click="upload.open = false">
{{ $t('common.cancel') }}
</el-button>
</div>
</template>
@@ -805,8 +804,10 @@ import {
wardList,
} from '@/api/system/user';
import {ref} from 'vue';
import { useI18n } from 'vue-i18n';
const router = useRouter();
const { t } = useI18n();
const { proxy } = getCurrentInstance();
const { sys_normal_disable, sys_user_sex, drord_dr_profttl } = proxy.useDict('sys_normal_disable', 'sys_user_sex', 'drord_dr_profttl');
@@ -852,13 +853,13 @@ const upload = reactive({
});
// 列显隐信息
const columns = ref([
{ key: 0, label: `用户编号`, visible: true },
{ key: 1, label: `用户账号`, visible: true },
{ key: 2, label: `用户姓名`, visible: true },
{ key: 3, label: `部门`, visible: true },
{ key: 4, label: `手机号码`, visible: true },
{ key: 5, label: `状态`, visible: true },
{ key: 6, label: `创建时间`, visible: true },
{ key: 0, label: `system.user.userId`, visible: true },
{ key: 1, label: `system.user.userAccount`, visible: true },
{ key: 2, label: `system.user.nickName`, visible: true },
{ key: 3, label: `system.user.deptId`, visible: true },
{ key: 4, label: `system.user.phone`, visible: true },
{ key: 5, label: `common.status`, visible: true },
{ key: 6, label: `common.createTime`, visible: true },
]);
const data = reactive({
@@ -871,27 +872,28 @@ const data = reactive({
status: undefined,
orgId: undefined,
},
rules: {
userName: [
{ required: true, message: '用户账号不能为空', trigger: 'blur' },
{ min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' },
],
nickName: [{ required: true, message: '用户姓名不能为空', trigger: 'blur' }],
responsibilityOrgDtoList: [{ required: true, message: '责任科室不能为空', trigger: 'blur' }],
practitionerRolesDtoListIds: [{ required: true, message: '角色不能为空', trigger: 'blur' }],
password: [
{ required: true, message: '用户密码不能为空', trigger: 'blur' },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' },
],
email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
phonenumber: [
{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' },
],
},
});
const { queryParams, form, rules } = toRefs(data);
const { queryParams, form } = toRefs(data);
const rules = computed(() => ({
userName: [
{ required: true, message: t('system.user.valAccountRequired'), trigger: 'blur' },
{ min: 2, max: 20, message: t('system.user.valAccountLength'), trigger: 'blur' },
],
nickName: [{ required: true, message: t('system.user.valNameRequired'), trigger: 'blur' }],
responsibilityOrgDtoList: [{ required: true, message: t('system.user.valDeptRequired'), trigger: 'blur' }],
practitionerRolesDtoListIds: [{ required: true, message: t('system.user.valRoleRequired'), trigger: 'blur' }],
password: [
{ required: true, message: t('system.user.valPasswordRequired'), trigger: 'blur' },
{ min: 5, max: 20, message: t('system.user.valPasswordLength'), trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: t('system.user.valPasswordChars'), trigger: 'blur' },
],
email: [{ type: 'email', message: t('system.user.valEmail'), trigger: ['blur', 'change'] }],
phonenumber: [
{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: t('system.user.valPhone'), trigger: 'blur' },
],
}));
/** 通过条件过滤节点 */
const filterNode = (value, data) => {
@@ -961,13 +963,13 @@ function resetQuery() {
function handleDelete(row) {
const userIds = row.userId || ids.value;
proxy.$modal
.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?')
.confirm(t('system.user.deleteConfirm', { id: userIds }))
.then(function () {
return delUser(userIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess('删除成功');
proxy.$modal.msgSuccess(t('message.deleteSuccess'));
})
.catch(() => {});
}
@@ -989,20 +991,19 @@ function handleExport() {
4. 批量操作:测试批量修改状态是否也只改变状态不改变角色
*/
function handleStatusChange(row) {
let text = row.status === '0' ? '启用' : '停用';
let text = row.status === '0' ? t('common.enabled') : t('common.disabled');
proxy.$modal
.confirm('确认要"' + text + '""' + row.userName + '"用户吗?')
.confirm(t('system.user.statusConfirm', { action: text, username: row.userName }))
.then(function () {
// 只更新用户状态,不修改用户角色
return changeUserStatus(row.userId, row.status);
})
.then(() => {
getList(); // 刷新列表,确保显示最新的用户信息
proxy.$modal.msgSuccess(text + '并设置为' + roleText + '成功');
getList();
proxy.$modal.msgSuccess(text + t('common.success'));
})
.catch(function () {
row.status = row.status === '0' ? '1' : '0';
proxy.$modal.msgError('操作失败,请重试');
proxy.$modal.msgError(t('system.user.operationFailed'));
});
}
/** 更多操作 */
@@ -1026,21 +1027,21 @@ function handleAuthRole(row) {
/** 重置密码按钮操作 */
function handleResetPwd(row) {
proxy
.$prompt('请输入"' + row.userName + '"的新密码', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
.$prompt(t('system.user.resetPwdPrompt', { username: row.userName }), t('common.tip'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: '用户密码长度必须介于 5 和 20 之间',
inputErrorMessage: t('system.user.valPasswordLength'),
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return '不能包含非法字符:< > " \' \\ |';
return t('system.user.valPasswordChars');
}
},
})
.then(({ value }) => {
resetUserPwd(row.userId, value).then((response) => {
proxy.$modal.msgSuccess('修改成功,新密码是:' + value);
proxy.$modal.msgSuccess(t('system.user.resetPwdSuccess', { pwd: value }));
});
})
.catch(() => {});
@@ -1053,7 +1054,7 @@ function handleSelectionChange(selection) {
}
/** 导入按钮操作 */
function handleImport() {
upload.title = '用户导入';
upload.title = t('system.user.userImport');
upload.open = true;
}
/** 下载模板操作 */
@@ -1073,7 +1074,7 @@ const handleFileSuccess = (response, file, fileList) => {
"<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
response.msg +
'</div>',
'导入结果',
t('system.user.importResult'),
{ dangerouslyUseHTMLString: true }
);
getList();
@@ -1131,7 +1132,7 @@ function handleAdd() {
doctorShow.value = true;
locationAdminShow.value = true;
pharmacyShow.value = true;
title.value = '添加用户';
title.value = t('system.user.addUser');
// 强制赋值初始密码(覆盖原逻辑,确保一定生效)
form.value.password = initPassword.value; // 这里会将123456赋值给密码输入框
});
@@ -1180,7 +1181,7 @@ function handleUpdate(row) {
nurseShow.value = !hasNurseRole;
open.value = true;
title.value = '修改用户';
title.value = t('system.user.editUser');
form.password = '';
});
getRole().then((response) => {
@@ -1328,7 +1329,7 @@ function validateUniqueRole(rule, value, callback) {
const roleCodes = form.value.childList.map((child) => child.roleCode);
const duplicates = roleCodes.filter((item, index) => roleCodes.indexOf(item) !== index);
if (duplicates.length > 0) {
callback(new Error('角色不能重复'));
callback(new Error(t('system.user.valRoleRequired')));
} else {
callback();
}
@@ -1340,7 +1341,7 @@ function requestUpload() {}
/** 上传预处理 */
function beforeUpload(file) {
if (file.type.indexOf("image/") == -1) {
proxy.$modal.msgError("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
proxy.$modal.msgError(t('system.user.fileFormatError'));
} else {
const reader = new FileReader();
reader.readAsDataURL(file);
@@ -1358,13 +1359,13 @@ function submitForm() {
if (valid) {
if (form.value.userId != undefined) {
updateUser(form.value).then((response) => {
proxy.$modal.msgSuccess('修改成功');
proxy.$modal.msgSuccess(t('message.editSuccess'));
open.value = false;
getList();
});
} else {
addUser(form.value).then((response) => {
proxy.$modal.msgSuccess('新增成功');
proxy.$modal.msgSuccess(t('message.addSuccess'));
open.value = false;
getList();
});
@@ -1388,12 +1389,12 @@ function handleBeforeUpload(file) {
console.log(file)
// 检查是否已有一张图片,如果有则不允许继续上传
if (fileList.value.length >= limit.value) {
proxy.$modal.msgWarning("只能上传一张图片,请先删除已上传的图片!");
proxy.$modal.msgWarning(t('system.user.uploadOneImage'));
return false;
}
if (file.type.indexOf("image/") == -1) {
proxy.$modal.msgError("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
proxy.$modal.msgError(t('system.user.fileFormatError'));
return false;
} else {
const reader = new FileReader();
@@ -1430,13 +1431,13 @@ function handleFileSelect(event) {
// 检查文件类型
if (!file.type.startsWith('image/')) {
proxy.$modal.msgError("请选择图片文件!");
proxy.$modal.msgError(t('system.user.selectImageFile'));
return;
}
// 检查文件大小限制为2MB
if (file.size > 2 * 1024 * 1024) {
proxy.$modal.msgError("图片大小不能超过2MB");
proxy.$modal.msgError(t('system.user.imageSizeLimit'));
return;
}
@@ -1464,14 +1465,14 @@ function handleFileChange(file, fileList) {
// 检查文件类型
if (!currentFile.type.startsWith('image/')) {
proxy.$modal.msgError("请选择图片文件!");
proxy.$modal.msgError(t('system.user.selectImageFile'));
proxy.$refs.uploadRef.clearFiles();
return;
}
// 检查文件大小限制为2MB
if (currentFile.size > 2 * 1024 * 1024) {
proxy.$modal.msgError("图片大小不能超过2MB");
proxy.$modal.msgError(t('system.user.imageSizeLimit'));
proxy.$refs.uploadRef.clearFiles();
return;
}