From d3dfc4507434f3af99d91c235ced45349326ac39 Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 16 Apr 2026 11:14:06 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E9=A6=96=E9=A1=B5=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BB=BB=E5=8A=A1=E3=80=81=E4=BA=A7=E5=93=81=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.js | 5 +- src/locales/en-US.js | 371 ++++++++++ src/locales/index.js | 690 +------------------ src/locales/zh-CN.js | 371 ++++++++++ src/pages.json | 6 + src/pages/index.vue | 705 ++++++++++++++++---- src/pages_function/pages/planList/index.vue | 219 ++++++ src/utils/format.js | 39 ++ vite.config.js | 4 +- 9 files changed, 1581 insertions(+), 829 deletions(-) create mode 100644 src/locales/en-US.js create mode 100644 src/locales/zh-CN.js create mode 100644 src/pages_function/pages/planList/index.vue create mode 100644 src/utils/format.js diff --git a/src/config.js b/src/config.js index f58dd08..dd37825 100644 --- a/src/config.js +++ b/src/config.js @@ -1,7 +1,8 @@ // 应用全局配置 const config = { // baseUrl: 'http://47.106.185.127:48080',127.0.0.1 - baseUrl: 'https://besure.ngsk.tech:7001', + // baseUrl: 'https://besure.ngsk.tech:7001', + baseUrl: 'http://192.168.5.167:48081', // 应用信息 appInfo: { // 应用名称 @@ -25,4 +26,4 @@ const config = { } } - export default config \ No newline at end of file + export default config diff --git a/src/locales/en-US.js b/src/locales/en-US.js new file mode 100644 index 0000000..da128b1 --- /dev/null +++ b/src/locales/en-US.js @@ -0,0 +1,371 @@ +export default { + common: { + submit: 'Submit', + close: 'Close', + exit: 'Exit', + notice: 'Notice', + moduleBuilding: 'This module is under construction', + updateSuccess: 'Updated successfully', + confirmLogout: 'Are you sure you want to log out?', + languageSwitched: 'Language switched' + }, + tab: { + home: 'Home', + report: 'Reports', + work: 'Manage', + mine: 'Mine' + }, + nav: { + home: 'Home', + mine: 'Profile', + avatar: 'Edit Avatar', + info: 'Profile', + editInfo: 'Edit Profile', + pwd: 'Change Password', + setting: 'App Settings', + help: 'FAQ', + about: 'About' + }, + dashboard: { + welcome: 'Welcome to', + subtitle: 'Besure Digital Intelligent Control Platform', + functionNav: 'Function Navigation', + productionOverview: 'Production Overview', + productionPlan: 'Production Plans', + collapseList: 'Collapse', + viewMore: 'View More ›', + productName: 'Product', + pipeline: 'Production Line', + planNumber: 'Planned Qty', + planStart: 'Start', + planEnd: 'End', + back: 'Back', + todoTitle: 'To-do Tasks', + noTodo: 'No pending tasks', + taskCode: 'Task Code: {value}', + taskType: 'Task Type: {value}', + taskTarget: 'Target: {value}', + createTime: 'Created At: {value}', + all: 'Total', + pending: 'Pending', + running: 'In Progress', + finished: 'Done', + mold: 'Mold', + equipment: 'Equipment', + keypart: 'Key Part', + spare: 'Spare Part', + product: 'Product Material', + statusScheduled: 'Scheduled', + statusTrial: 'Trial', + statusMass: 'Mass', + statusPause: 'Paused', + statusWaitStockIn: 'Waiting Stock-in', + viewPlan: 'View Plan: {code}', + filterTask: 'Task', + filterProduct: 'Product', + dateRange: 'Date Range', + startDate: 'Start Time', + endDate: 'End Time', + baogongNum: 'Reported', + passNum: 'Qualified', + noPassNum: 'Unqualified', + passRate: 'Pass Rate', + trendChart: 'Trend', + taskPlaceholder: 'Task mode under development', + totalTask: 'Total Tasks', + waitingProduction: 'Waiting', + producing: 'Producing', + completed: 'Completed', + taskTrend: 'Task Trend', + rangeYear: 'Last Year', + rangeMonth: 'This Month', + rangeWeek: 'This Week', + rangeToday: 'Today', + rangeCustom: 'Custom', + monday: 'Mon', + tuesday: 'Tue', + wednesday: 'Wed', + thursday: 'Thu', + friday: 'Fri', + saturday: 'Sat', + sunday: 'Sun' + }, + functionCommon: { + search: 'Search', + cancel: 'Cancel', + save: 'Save', + loading: 'Loading...', + loadingMore: 'Loading more...', + noMoreData: 'No more data', + noIdView: 'Missing ID, cannot view details', + noIdEdit: 'Missing ID, cannot edit', + noIdDelete: 'Missing ID, cannot delete', + loadFailed: 'Load failed', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + saveFailed: 'Save failed', + createSuccess: 'Created successfully', + updateSuccess: 'Updated successfully', + confirmDelete: 'Confirm deletion', + uploading: 'Uploading', + uploadImageFailed: 'Image upload failed', + yes: 'Yes', + no: 'No' + }, + moldGet: { + moduleName: 'Mold Stock-out', + subTitle: 'Filter quickly by no and status', + detailTitle: 'Mold Stock-out Detail', + basicInfo: 'Basic Info', + outNo: 'Stock-out No', + outType: 'Stock-out Type', + outTime: 'Stock-out Time', + outTimeSingle: 'Stock-out Date', + outTimePlaceholder: 'Select stock-out date', + warehouse: 'Warehouse', + allWarehouse: 'All Warehouses', + warehousePlaceholder: 'Select warehouse', + creator: 'Creator', + status: 'Status', + allStatus: 'All Status', + remark: 'Remark', + itemRemark: 'Item Remark', + attachment: 'Attachment', + fileUrlPlaceholder: 'Enter attachment URL', + remarkPlaceholder: 'Enter remark', + moldName: 'Mold', + moldCode: 'Mold Code', + moldStatus: 'Mold Status', + moldUseTime: 'Use Time', + machineName: 'Machine', + isEnable: 'Enabled', + createTime: 'Created At', + searchNo: 'Enter stock-out no', + searchMold: 'Enter mold code or name', + searchCode: 'Enter mold code', + searchName: 'Enter mold name', + itemListTitle: 'Item List', + selectMold: 'Select Mold', + noItems: 'No items', + count: 'Count', + noAuto: 'Generated automatically', + createTitle: 'Create Mold Stock-out', + editTitle: 'Edit Mold Stock-out', + edit: 'Edit', + delete: 'Delete', + approve: 'Approve', + empty: 'No mold stock-out data', + noMoldData: 'No mold options', + loadEditFailed: 'Failed to load edit data', + validatorOutTimeRequired: 'Stock-out date is required', + validatorWarehouseRequired: 'Warehouse is required', + validatorItemRequired: 'Select at least one mold', + validatorCountRequired: 'Count must be greater than 0', + confirmDelete: 'Delete stock-out {no}?', + confirmApprove: 'Approve stock-out {no}?', + approveSuccess: 'Approved successfully' + }, + moldReturn: { + moduleName: 'Mold Stock-in', + subTitle: 'Filter quickly by no and status', + detailTitle: 'Mold Stock-in Detail', + basicInfo: 'Basic Info', + inNo: 'Stock-in No', + inType: 'Stock-in Type', + inTime: 'Stock-in Time', + inTimeSingle: 'Stock-in Date', + inTimePlaceholder: 'Select stock-in date', + warehouse: 'Warehouse', + allWarehouse: 'All Warehouses', + warehousePlaceholder: 'Select warehouse', + creator: 'Creator', + status: 'Status', + allStatus: 'All Status', + remark: 'Remark', + itemRemark: 'Item Remark', + attachment: 'Attachment', + fileUrlPlaceholder: 'Enter attachment URL', + remarkPlaceholder: 'Enter remark', + moldName: 'Mold', + moldCode: 'Mold Code', + moldStatus: 'Mold Status', + moldUseTime: 'Use Time', + searchNo: 'Enter stock-in no', + searchCode: 'Enter mold code', + searchName: 'Enter mold name', + itemListTitle: 'Item List', + selectMold: 'Select Mold', + noItems: 'No items', + count: 'Count', + noAuto: 'Generated automatically', + createTitle: 'Create Mold Stock-in', + editTitle: 'Edit Mold Stock-in', + approve: 'Approve', + empty: 'No mold stock-in data', + noMoldData: 'No mold options', + loadEditFailed: 'Failed to load edit data', + validatorInTimeRequired: 'Stock-in date is required', + validatorWarehouseRequired: 'Warehouse is required', + validatorItemRequired: 'Select at least one mold', + validatorCountRequired: 'Count must be greater than 0', + confirmDelete: 'Delete stock-in {no}?', + confirmApprove: 'Approve stock-in {no}?', + approveSuccess: 'Approved successfully' + }, + moldOperate: { + moduleName: 'Mold Operate', + subTitle: 'Mold mounting and dismounting records', + detailTitle: 'Mold Operate Detail', + basicInfo: 'Basic Info', + tabUp: 'Mount', + tabDown: 'Dismount', + operateType: 'Operation Type', + mold: 'Mold', + lowerMold: 'Dismount Mold', + selectMold: 'Select Mold', + noSelectedMold: 'No selected molds', + allMold: 'All Molds', + searchRemark: 'Enter remark keyword', + searchCode: 'Enter mold code', + searchName: 'Enter mold name', + moldCode: 'Mold Code', + moldName: 'Mold Name', + device: 'Device', + deviceName: 'Device Name', + creatorName: 'Creator', + remark: 'Remark', + createTime: 'Created At', + createTitle: 'Create Mold Operate', + editTitle: 'Edit Mold Operate', + empty: 'No mold operate data', + noMoldData: 'No mold options', + placeholderDevice: 'Select device', + placeholderRemark: 'Enter remark', + validatorOperateTypeRequired: 'Operation type is required', + validatorDeviceRequired: 'Device is required', + validatorMoldRequired: 'Select at least one mold for mounting', + validatorLowerMoldRequired: 'Select at least one mold for dismounting', + loadEditFailed: 'Failed to load edit data', + confirmDelete: 'Confirm delete this mold operate record?' + }, + moldInspectionItems: { + moduleName: 'Inspection Items', + subTitle: 'Mold management inspection items', + detailTitle: 'Inspection Item Detail', + basicInfo: 'Basic Info', + code: 'Item Code', + name: 'Item Name', + inspectionMethod: 'Inspection Method', + valueType: 'Value Type', + isEnable: 'Enabled', + judgmentCriteria: 'Judgment Criteria', + creatorName: 'Creator', + createTime: 'Created At', + searchPlaceholder: 'Enter code/name/criteria', + createTitle: 'Create Inspection Item', + editTitle: 'Edit Inspection Item', + empty: 'No inspection items', + loadEditFailed: 'Failed to load edit data', + confirmDelete: 'Confirm delete this inspection item?', + placeholderCode: 'Enter item code', + placeholderName: 'Enter item name', + placeholderInspectionMethod: 'Select inspection method', + placeholderValueType: 'Select value type', + placeholderIsEnable: 'Select enabled status', + placeholderJudgmentCriteria: 'Enter judgment criteria', + validatorSubjectCodeRequired: 'Item code is required', + validatorSubjectNameRequired: 'Item name is required', + validatorInspectionMethodRequired: 'Inspection method is required', + validatorValueTypeRequired: 'Value type is required', + validatorIsEnableRequired: 'Enabled status is required', + validatorJudgmentCriteriaRequired: 'Judgment criteria is required' + }, + mine: { + clickLogin: 'Tap to sign in', + username: 'Username: {name}', + profile: 'Profile', + feedback: 'Feedback', + service: 'Support', + changePassword: 'Change Password', + logout: 'Log Out', + editProfile: 'Edit Profile', + faq: 'FAQ', + about: 'About', + appSettings: 'Settings' + }, + setting: { + language: 'System Language', + currentLanguage: 'Current: {language}', + switchLanguage: 'Switch Language', + checkUpdate: 'Check Updates', + cleanCache: 'Clear Cache', + logout: 'Log Out', + zhCN: 'Chinese', + enUS: 'English' + }, + about: { + appName: 'Besure Production System', + version: 'Version', + email: 'Official Email', + hotline: 'Service Hotline', + website: 'Website' + }, + help: { + appUserQuestion: 'App User Questions', + otherQuestion: 'Other Questions', + appFeatureQuestion: 'What business features are supported by the app?', + appFeatureAnswer: 'Plan start, production report, material feeding records, production records', + reportQuestion: 'How can I submit a production report?', + reportAnswer: 'You can submit it on the report page.', + planQuestion: 'How is plan management handled?', + planAnswer: 'Use the plan management module.', + materialQuestion: 'How to manage feeding records?', + materialAnswer: 'Use the feeding record module.', + logoutQuestion: 'How do I log out?', + logoutAnswer: 'Go to [Mine] - [App Settings] - [Log Out] to sign out.', + avatarQuestion: 'How do I change my avatar?', + avatarAnswer: 'Go to [Mine] - [Choose Avatar] - [Submit] to update your avatar.', + passwordQuestion: 'How do I change my login password?', + passwordAnswer: 'Go to [Mine] - [App Settings] - [Change Password] to update your password.' + }, + info: { + username: 'Username', + nickname: 'Nickname', + gender: 'Gender', + male: 'Male', + female: 'Female', + phone: 'Mobile', + email: 'Email', + createdAt: 'Created At' + }, + editInfo: { + nickname: 'Nickname', + nicknamePlaceholder: 'Enter nickname', + phone: 'Mobile', + phonePlaceholder: 'Enter mobile number', + email: 'Email', + emailPlaceholder: 'Enter email', + gender: 'Gender', + nicknameRequired: 'Nickname is required', + phoneRequired: 'Mobile number is required', + phoneInvalid: 'Please enter a valid mobile number', + emailRequired: 'Email is required', + emailInvalid: 'Please enter a valid email' + }, + pwd: { + oldPassword: 'Current Password', + newPassword: 'New Password', + confirmPassword: 'Confirm Password', + oldPasswordPlaceholder: 'Enter current password', + newPasswordPlaceholder: 'Enter new password', + confirmPasswordPlaceholder: 'Confirm new password', + oldPasswordRequired: 'Current password is required', + newPasswordRequired: 'New password is required', + passwordLength: 'Length must be between 6 and 20 characters', + confirmPasswordRequired: 'Please confirm password', + passwordNotMatch: 'The two passwords do not match' + }, + avatar: { + chooseAvatar: 'Choose Avatar' + } +} diff --git a/src/locales/index.js b/src/locales/index.js index 94ef39c..e88d680 100644 --- a/src/locales/index.js +++ b/src/locales/index.js @@ -1,696 +1,14 @@ import { createI18n } from 'vue-i18n' +import zhCN from './zh-CN' +import enUS from './en-US' const LOCALE_STORAGE_KEY = 'app_locale' const LOCALE_CHANGE_EVENT = 'app-locale-changed' const DEFAULT_LOCALE = 'zh-CN' const messages = { - 'zh-CN': { - common: { - submit: '提交', - close: '关闭', - exit: '退出', - notice: '通知', - moduleBuilding: '模块建设中~', - updateSuccess: '修改成功', - confirmLogout: '确定注销并退出系统吗', - languageSwitched: '语言已切换' - }, - tab: { - home: '首页', - report: '报表', - work: '管理', - mine: '我的' - }, - nav: { - home: '首页', - mine: '个人中心', - avatar: '修改头像', - info: '个人信息', - editInfo: '编辑资料', - pwd: '修改密码', - setting: '应用设置', - help: '常见问题', - about: '关于我们' - }, - dashboard: { - welcome: '欢迎您使用', - subtitle: '必硕数字化智能中控平台', - functionNav: '功能导航', - productionOverview: '生产整体概况', - productionPlan: '生产计划', - collapseList: '收起列表', - viewMore: '查看更多 ›', - productName: '产品名称', - pipeline: '生产线', - planNumber: '计划数量', - planStart: '计划开始', - planEnd: '计划结束', - back: '返回', - todoTitle: '待办任务', - noTodo: '暂无待办任务', - taskCode: '任务编号:{value}', - taskType: '任务类型:{value}', - taskTarget: '目标:{value}', - createTime: '创建时间:{value}', - all: '总数', - pending: '未开工', - running: '生产中', - finished: '完工', - mold: '模具', - equipment: '设备', - keypart: '关键件', - spare: '备件', - product: '产品物料', - statusScheduled: '已排产', - statusTrial: '试产', - statusMass: '量产', - statusPause: '暂停', - statusWaitStockIn: '待入库', - viewPlan: '查看计划: {code}' - }, - functionCommon: { - search: '查询', - cancel: '取消', - save: '保存', - loading: '加载中...', - loadingMore: '正在加载更多...', - noMoreData: '没有更多数据了', - noIdView: '缺少ID,无法查看详情', - noIdEdit: '缺少ID,无法编辑', - noIdDelete: '缺少ID,无法删除', - loadFailed: '加载失败', - deleteSuccess: '删除成功', - deleteFailed: '删除失败', - saveFailed: '保存失败', - createSuccess: '新增成功', - updateSuccess: '更新成功', - confirmDelete: '确认删除', - uploading: '上传中', - uploadImageFailed: '图片上传失败', - yes: '是', - no: '否' - }, - moldGet: { - moduleName: '模具出库', - subTitle: '按出库单号与状态快速筛选', - detailTitle: '模具出库详情', - basicInfo: '基础信息', - outNo: '出库单号', - outType: '出库类型', - outTime: '出库时间', - outTimeSingle: '出库日期', - outTimePlaceholder: '请选择出库日期', - warehouse: '仓库', - allWarehouse: '全部仓库', - warehousePlaceholder: '请选择仓库', - creator: '创建人', - status: '状态', - allStatus: '全部状态', - remark: '备注', - itemRemark: '明细备注', - attachment: '附件', - fileUrlPlaceholder: '请输入附件地址', - remarkPlaceholder: '请输入备注', - moldName: '模具', - moldCode: '模具编码', - moldStatus: '模具状态', - moldUseTime: '使用次数', - machineName: '使用设备', - isEnable: '是否启用', - createTime: '创建时间', - searchNo: '请输入出库单号', - searchMold: '请输入模具编码或名称', - searchCode: '请输入模具编码', - searchName: '请输入模具名称', - itemListTitle: '出库明细', - selectMold: '选择模具', - noItems: '暂无出库明细', - count: '数量', - noAuto: '系统自动生成', - createTitle: '新增模具出库', - editTitle: '编辑模具出库', - edit: '编辑', - delete: '删除', - approve: '审批', - empty: '暂无模具出库数据', - noMoldData: '暂无可选模具', - loadEditFailed: '加载编辑数据失败', - validatorOutTimeRequired: '出库日期不能为空', - validatorWarehouseRequired: '仓库不能为空', - validatorItemRequired: '请至少选择一个模具', - validatorCountRequired: '数量必须大于0', - confirmDelete: '确认删除出库单 {no} 吗?', - confirmApprove: '确认审批出库单 {no} 吗?', - approveSuccess: '审批成功' - }, - moldReturn: { - moduleName: '模具入库', - subTitle: '按入库单号与状态快速筛选', - detailTitle: '模具入库详情', - basicInfo: '基础信息', - inNo: '入库单号', - inType: '入库类型', - inTime: '入库时间', - inTimeSingle: '入库日期', - inTimePlaceholder: '请选择入库日期', - warehouse: '仓库', - allWarehouse: '全部仓库', - warehousePlaceholder: '请选择仓库', - creator: '创建人', - status: '状态', - allStatus: '全部状态', - remark: '备注', - itemRemark: '明细备注', - attachment: '附件', - fileUrlPlaceholder: '请输入附件地址', - remarkPlaceholder: '请输入备注', - moldName: '模具', - moldCode: '模具编码', - moldStatus: '模具状态', - moldUseTime: '使用次数', - searchNo: '请输入入库单号', - searchCode: '请输入模具编码', - searchName: '请输入模具名称', - itemListTitle: '入库明细', - selectMold: '选择模具', - noItems: '暂无入库明细', - count: '数量', - noAuto: '系统自动生成', - createTitle: '新增模具入库', - editTitle: '编辑模具入库', - approve: '审批', - empty: '暂无模具入库数据', - noMoldData: '暂无可选模具', - loadEditFailed: '加载编辑数据失败', - validatorInTimeRequired: '入库日期不能为空', - validatorWarehouseRequired: '仓库不能为空', - validatorItemRequired: '请至少选择一个模具', - validatorCountRequired: '数量必须大于0', - confirmDelete: '确认删除入库单 {no} 吗?', - confirmApprove: '确认审批入库单 {no} 吗?', - approveSuccess: '审批成功' - }, - moldOperate: { - moduleName: '上下模', - subTitle: '模具上模/下模操作记录', - detailTitle: '上下模详情', - basicInfo: '基础信息', - tabUp: '上模', - tabDown: '下模', - operateType: '操作类型', - mold: '模具', - lowerMold: '下模模具', - selectMold: '选择模具', - noSelectedMold: '暂无已选模具', - allMold: '全部模具', - searchRemark: '请输入备注关键字', - searchCode: '请输入模具编码', - searchName: '请输入模具名称', - moldCode: '模具编码', - moldName: '模具名称', - device: '设备', - deviceName: '设备名称', - creatorName: '创建人', - remark: '备注', - createTime: '创建时间', - createTitle: '新增上下模', - editTitle: '编辑上下模', - empty: '暂无上下模数据', - noMoldData: '暂无可选模具', - placeholderDevice: '请选择设备', - placeholderRemark: '请输入备注', - validatorOperateTypeRequired: '操作类型不能为空', - validatorDeviceRequired: '设备不能为空', - validatorMoldRequired: '请至少选择一个上模模具', - validatorLowerMoldRequired: '请至少选择一个下模模具', - loadEditFailed: '加载编辑数据失败', - confirmDelete: '确认删除该上下模记录吗?' - }, - moldInspectionItems: { - moduleName: '点检项库', - subTitle: '模具管理点检项维护', - detailTitle: '点检项库详情', - basicInfo: '基础信息', - code: '项目编码', - name: '项目名称', - inspectionMethod: '检验方式', - valueType: '值类型', - isEnable: '是否启用', - judgmentCriteria: '判定基准', - creatorName: '创建人', - createTime: '创建时间', - searchPlaceholder: '请输入编码/名称/判定基准', - createTitle: '新增点检项', - editTitle: '编辑点检项', - empty: '暂无点检项数据', - loadEditFailed: '加载编辑数据失败', - confirmDelete: '确认删除该点检项吗?', - placeholderCode: '请输入项目编码', - placeholderName: '请输入项目名称', - placeholderInspectionMethod: '请选择检验方式', - placeholderValueType: '请选择值类型', - placeholderIsEnable: '请选择是否启用', - placeholderJudgmentCriteria: '请输入判定基准', - validatorSubjectCodeRequired: '项目编码不能为空', - validatorSubjectNameRequired: '项目名称不能为空', - validatorInspectionMethodRequired: '检验方式不能为空', - validatorValueTypeRequired: '值类型不能为空', - validatorIsEnableRequired: '是否启用不能为空', - validatorJudgmentCriteriaRequired: '判定基准不能为空' - }, - mine: { - clickLogin: '点击登录', - username: '用户名:{name}', - profile: '个人信息', - feedback: '反馈中心', - service: '在线客服', - changePassword: '修改密码', - logout: '退出登录', - editProfile: '编辑资料', - faq: '常见问题', - about: '关于我们', - appSettings: '应用设置' - }, - setting: { - language: '系统语言', - currentLanguage: '当前语言:{language}', - switchLanguage: '切换语言', - checkUpdate: '检查更新', - cleanCache: '清理缓存', - logout: '退出登录', - zhCN: '中文', - enUS: '英文' - }, - about: { - appName: '必硕生管系统', - version: '版本信息', - email: '官方邮箱', - hotline: '服务热线', - website: '公司网站' - }, - help: { - appUserQuestion: 'APP用户问题', - otherQuestion: '其他问题', - appFeatureQuestion: 'APP支持的功能业务有哪些?', - appFeatureAnswer: '计划开工、生产报工、投料记录、生产记录', - reportQuestion: '生产报工如何报工?', - reportAnswer: '可以', - planQuestion: '计划管理如何进行?', - planAnswer: '计划管理', - materialQuestion: '投料记录如何进行?', - materialAnswer: '投料记录', - logoutQuestion: '如何退出登录?', - logoutAnswer: '请点击[我的] - [应用设置] - [退出登录]即可退出登录', - avatarQuestion: '如何修改用户头像?', - avatarAnswer: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像', - passwordQuestion: '如何修改登录密码?', - passwordAnswer: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码' - }, - info: { - username: '用户名称', - nickname: '昵称', - gender: '性别', - male: '男', - female: '女', - phone: '手机号码', - email: '邮箱', - createdAt: '创建日期' - }, - editInfo: { - nickname: '用户昵称', - nicknamePlaceholder: '请输入昵称', - phone: '手机号码', - phonePlaceholder: '请输入手机号码', - email: '邮箱', - emailPlaceholder: '请输入邮箱', - gender: '性别', - nicknameRequired: '用户昵称不能为空', - phoneRequired: '手机号码不能为空', - phoneInvalid: '请输入正确的手机号码', - emailRequired: '邮箱地址不能为空', - emailInvalid: '请输入正确的邮箱地址' - }, - pwd: { - oldPassword: '旧密码', - newPassword: '新密码', - confirmPassword: '确认密码', - oldPasswordPlaceholder: '请输入旧密码', - newPasswordPlaceholder: '请输入新密码', - confirmPasswordPlaceholder: '请确认新密码', - oldPasswordRequired: '旧密码不能为空', - newPasswordRequired: '新密码不能为空', - passwordLength: '长度在 6 到 20 个字符', - confirmPasswordRequired: '确认密码不能为空', - passwordNotMatch: '两次输入的密码不一致' - }, - avatar: { - chooseAvatar: '选择头像' - } - }, - 'en-US': { - common: { - submit: 'Submit', - close: 'Close', - exit: 'Exit', - notice: 'Notice', - moduleBuilding: 'This module is under construction', - updateSuccess: 'Updated successfully', - confirmLogout: 'Are you sure you want to log out?', - languageSwitched: 'Language switched' - }, - tab: { - home: 'Home', - report: 'Reports', - work: 'Manage', - mine: 'Mine' - }, - nav: { - home: 'Home', - mine: 'Profile', - avatar: 'Edit Avatar', - info: 'Profile', - editInfo: 'Edit Profile', - pwd: 'Change Password', - setting: 'App Settings', - help: 'FAQ', - about: 'About' - }, - dashboard: { - welcome: 'Welcome to', - subtitle: 'Besure Digital Intelligent Control Platform', - functionNav: 'Function Navigation', - productionOverview: 'Production Overview', - productionPlan: 'Production Plans', - collapseList: 'Collapse', - viewMore: 'View More ›', - productName: 'Product', - pipeline: 'Production Line', - planNumber: 'Planned Qty', - planStart: 'Start', - planEnd: 'End', - back: 'Back', - todoTitle: 'To-do Tasks', - noTodo: 'No pending tasks', - taskCode: 'Task Code: {value}', - taskType: 'Task Type: {value}', - taskTarget: 'Target: {value}', - createTime: 'Created At: {value}', - all: 'Total', - pending: 'Pending', - running: 'In Progress', - finished: 'Done', - mold: 'Mold', - equipment: 'Equipment', - keypart: 'Key Part', - spare: 'Spare Part', - product: 'Product Material', - statusScheduled: 'Scheduled', - statusTrial: 'Trial', - statusMass: 'Mass', - statusPause: 'Paused', - statusWaitStockIn: 'Waiting Stock-in', - viewPlan: 'View Plan: {code}' - }, - functionCommon: { - search: 'Search', - cancel: 'Cancel', - save: 'Save', - loading: 'Loading...', - loadingMore: 'Loading more...', - noMoreData: 'No more data', - noIdView: 'Missing ID, cannot view details', - noIdEdit: 'Missing ID, cannot edit', - noIdDelete: 'Missing ID, cannot delete', - loadFailed: 'Load failed', - deleteSuccess: 'Deleted successfully', - deleteFailed: 'Delete failed', - saveFailed: 'Save failed', - createSuccess: 'Created successfully', - updateSuccess: 'Updated successfully', - confirmDelete: 'Confirm deletion', - uploading: 'Uploading', - uploadImageFailed: 'Image upload failed', - yes: 'Yes', - no: 'No' - }, - moldGet: { - moduleName: 'Mold Stock-out', - subTitle: 'Filter quickly by no and status', - detailTitle: 'Mold Stock-out Detail', - basicInfo: 'Basic Info', - outNo: 'Stock-out No', - outType: 'Stock-out Type', - outTime: 'Stock-out Time', - outTimeSingle: 'Stock-out Date', - outTimePlaceholder: 'Select stock-out date', - warehouse: 'Warehouse', - allWarehouse: 'All Warehouses', - warehousePlaceholder: 'Select warehouse', - creator: 'Creator', - status: 'Status', - allStatus: 'All Status', - remark: 'Remark', - itemRemark: 'Item Remark', - attachment: 'Attachment', - fileUrlPlaceholder: 'Enter attachment URL', - remarkPlaceholder: 'Enter remark', - moldName: 'Mold', - moldCode: 'Mold Code', - moldStatus: 'Mold Status', - moldUseTime: 'Use Time', - machineName: 'Machine', - isEnable: 'Enabled', - createTime: 'Created At', - searchNo: 'Enter stock-out no', - searchMold: 'Enter mold code or name', - searchCode: 'Enter mold code', - searchName: 'Enter mold name', - itemListTitle: 'Item List', - selectMold: 'Select Mold', - noItems: 'No items', - count: 'Count', - noAuto: 'Generated automatically', - createTitle: 'Create Mold Stock-out', - editTitle: 'Edit Mold Stock-out', - edit: 'Edit', - delete: 'Delete', - approve: 'Approve', - empty: 'No mold stock-out data', - noMoldData: 'No mold options', - loadEditFailed: 'Failed to load edit data', - validatorOutTimeRequired: 'Stock-out date is required', - validatorWarehouseRequired: 'Warehouse is required', - validatorItemRequired: 'Select at least one mold', - validatorCountRequired: 'Count must be greater than 0', - confirmDelete: 'Delete stock-out {no}?', - confirmApprove: 'Approve stock-out {no}?', - approveSuccess: 'Approved successfully' - }, - moldReturn: { - moduleName: 'Mold Stock-in', - subTitle: 'Filter quickly by no and status', - detailTitle: 'Mold Stock-in Detail', - basicInfo: 'Basic Info', - inNo: 'Stock-in No', - inType: 'Stock-in Type', - inTime: 'Stock-in Time', - inTimeSingle: 'Stock-in Date', - inTimePlaceholder: 'Select stock-in date', - warehouse: 'Warehouse', - allWarehouse: 'All Warehouses', - warehousePlaceholder: 'Select warehouse', - creator: 'Creator', - status: 'Status', - allStatus: 'All Status', - remark: 'Remark', - itemRemark: 'Item Remark', - attachment: 'Attachment', - fileUrlPlaceholder: 'Enter attachment URL', - remarkPlaceholder: 'Enter remark', - moldName: 'Mold', - moldCode: 'Mold Code', - moldStatus: 'Mold Status', - moldUseTime: 'Use Time', - searchNo: 'Enter stock-in no', - searchCode: 'Enter mold code', - searchName: 'Enter mold name', - itemListTitle: 'Item List', - selectMold: 'Select Mold', - noItems: 'No items', - count: 'Count', - noAuto: 'Generated automatically', - createTitle: 'Create Mold Stock-in', - editTitle: 'Edit Mold Stock-in', - approve: 'Approve', - empty: 'No mold stock-in data', - noMoldData: 'No mold options', - loadEditFailed: 'Failed to load edit data', - validatorInTimeRequired: 'Stock-in date is required', - validatorWarehouseRequired: 'Warehouse is required', - validatorItemRequired: 'Select at least one mold', - validatorCountRequired: 'Count must be greater than 0', - confirmDelete: 'Delete stock-in {no}?', - confirmApprove: 'Approve stock-in {no}?', - approveSuccess: 'Approved successfully' - }, - moldOperate: { - moduleName: 'Mold Operate', - subTitle: 'Mold mounting and dismounting records', - detailTitle: 'Mold Operate Detail', - basicInfo: 'Basic Info', - tabUp: 'Mount', - tabDown: 'Dismount', - operateType: 'Operation Type', - mold: 'Mold', - lowerMold: 'Dismount Mold', - selectMold: 'Select Mold', - noSelectedMold: 'No selected molds', - allMold: 'All Molds', - searchRemark: 'Enter remark keyword', - searchCode: 'Enter mold code', - searchName: 'Enter mold name', - moldCode: 'Mold Code', - moldName: 'Mold Name', - device: 'Device', - deviceName: 'Device Name', - creatorName: 'Creator', - remark: 'Remark', - createTime: 'Created At', - createTitle: 'Create Mold Operate', - editTitle: 'Edit Mold Operate', - empty: 'No mold operate data', - noMoldData: 'No mold options', - placeholderDevice: 'Select device', - placeholderRemark: 'Enter remark', - validatorOperateTypeRequired: 'Operation type is required', - validatorDeviceRequired: 'Device is required', - validatorMoldRequired: 'Select at least one mold for mounting', - validatorLowerMoldRequired: 'Select at least one mold for dismounting', - loadEditFailed: 'Failed to load edit data', - confirmDelete: 'Delete this mold operate record?' - }, - moldInspectionItems: { - moduleName: 'Inspection Items', - subTitle: 'Mold inspection item maintenance', - detailTitle: 'Inspection Item Detail', - basicInfo: 'Basic Info', - code: 'Item Code', - name: 'Item Name', - inspectionMethod: 'Inspection Method', - valueType: 'Value Type', - isEnable: 'Enabled', - judgmentCriteria: 'Judgment Criteria', - creatorName: 'Creator', - createTime: 'Created At', - searchPlaceholder: 'Enter code/name/criteria', - createTitle: 'Create Inspection Item', - editTitle: 'Edit Inspection Item', - empty: 'No inspection item data', - loadEditFailed: 'Failed to load edit data', - confirmDelete: 'Delete this inspection item?', - placeholderCode: 'Enter item code', - placeholderName: 'Enter item name', - placeholderInspectionMethod: 'Select inspection method', - placeholderValueType: 'Select value type', - placeholderIsEnable: 'Select enabled status', - placeholderJudgmentCriteria: 'Enter judgment criteria', - validatorSubjectCodeRequired: 'Item code is required', - validatorSubjectNameRequired: 'Item name is required', - validatorInspectionMethodRequired: 'Inspection method is required', - validatorValueTypeRequired: 'Value type is required', - validatorIsEnableRequired: 'Enabled status is required', - validatorJudgmentCriteriaRequired: 'Judgment criteria is required' - }, - mine: { - clickLogin: 'Tap to sign in', - username: 'Username: {name}', - profile: 'Profile', - feedback: 'Feedback', - service: 'Support', - changePassword: 'Change Password', - logout: 'Log Out', - editProfile: 'Edit Profile', - faq: 'FAQ', - about: 'About', - appSettings: 'Settings' - }, - setting: { - language: 'System Language', - currentLanguage: 'Current: {language}', - switchLanguage: 'Switch Language', - checkUpdate: 'Check Updates', - cleanCache: 'Clear Cache', - logout: 'Log Out', - zhCN: 'Chinese', - enUS: 'English' - }, - about: { - appName: 'Besure Production System', - version: 'Version', - email: 'Official Email', - hotline: 'Service Hotline', - website: 'Website' - }, - help: { - appUserQuestion: 'App User Questions', - otherQuestion: 'Other Questions', - appFeatureQuestion: 'What business features are supported by the app?', - appFeatureAnswer: 'Plan start, production report, material feeding records, production records', - reportQuestion: 'How can I submit a production report?', - reportAnswer: 'You can submit it on the report page.', - planQuestion: 'How is plan management handled?', - planAnswer: 'Use the plan management module.', - materialQuestion: 'How to manage feeding records?', - materialAnswer: 'Use the feeding record module.', - logoutQuestion: 'How do I log out?', - logoutAnswer: 'Go to [Mine] - [App Settings] - [Log Out] to sign out.', - avatarQuestion: 'How do I change my avatar?', - avatarAnswer: 'Go to [Mine] - [Choose Avatar] - [Submit] to update your avatar.', - passwordQuestion: 'How do I change my login password?', - passwordAnswer: 'Go to [Mine] - [App Settings] - [Change Password] to update your password.' - }, - info: { - username: 'Username', - nickname: 'Nickname', - gender: 'Gender', - male: 'Male', - female: 'Female', - phone: 'Mobile', - email: 'Email', - createdAt: 'Created At' - }, - editInfo: { - nickname: 'Nickname', - nicknamePlaceholder: 'Enter nickname', - phone: 'Mobile', - phonePlaceholder: 'Enter mobile number', - email: 'Email', - emailPlaceholder: 'Enter email', - gender: 'Gender', - nicknameRequired: 'Nickname is required', - phoneRequired: 'Mobile number is required', - phoneInvalid: 'Please enter a valid mobile number', - emailRequired: 'Email is required', - emailInvalid: 'Please enter a valid email' - }, - pwd: { - oldPassword: 'Current Password', - newPassword: 'New Password', - confirmPassword: 'Confirm Password', - oldPasswordPlaceholder: 'Enter current password', - newPasswordPlaceholder: 'Enter new password', - confirmPasswordPlaceholder: 'Confirm new password', - oldPasswordRequired: 'Current password is required', - newPasswordRequired: 'New password is required', - passwordLength: 'Length must be between 6 and 20 characters', - confirmPasswordRequired: 'Please confirm password', - passwordNotMatch: 'The two passwords do not match' - }, - avatar: { - chooseAvatar: 'Choose Avatar' - } - } + 'zh-CN': zhCN, + 'en-US': enUS } function normalizeLocale(locale) { diff --git a/src/locales/zh-CN.js b/src/locales/zh-CN.js new file mode 100644 index 0000000..9ddfd75 --- /dev/null +++ b/src/locales/zh-CN.js @@ -0,0 +1,371 @@ +export default { + common: { + submit: '提交', + close: '关闭', + exit: '退出', + notice: '通知', + moduleBuilding: '模块建设中~', + updateSuccess: '修改成功', + confirmLogout: '确定注销并退出系统吗', + languageSwitched: '语言已切换' + }, + tab: { + home: '首页', + report: '报表', + work: '管理', + mine: '我的' + }, + nav: { + home: '首页', + mine: '个人中心', + avatar: '修改头像', + info: '个人信息', + editInfo: '编辑资料', + pwd: '修改密码', + setting: '应用设置', + help: '常见问题', + about: '关于我们' + }, + dashboard: { + welcome: '欢迎您使用', + subtitle: '必硕数字化智能中控平台', + functionNav: '功能导航', + productionOverview: '生产整体概况', + productionPlan: '生产计划', + collapseList: '收起列表', + viewMore: '查看更多 ›', + productName: '产品名称', + pipeline: '生产线', + planNumber: '计划数量', + planStart: '计划开始', + planEnd: '计划结束', + back: '返回', + todoTitle: '待办任务', + noTodo: '暂无待办任务', + taskCode: '任务编号:{value}', + taskType: '任务类型:{value}', + taskTarget: '目标:{value}', + createTime: '创建时间:{value}', + all: '总数', + pending: '未开工', + running: '生产中', + finished: '完工', + mold: '模具', + equipment: '设备', + keypart: '关键件', + spare: '备件', + product: '产品物料', + statusScheduled: '已排产', + statusTrial: '试产', + statusMass: '量产', + statusPause: '暂停', + statusWaitStockIn: '待入库', + viewPlan: '查看计划: {code}', + filterTask: '任务', + filterProduct: '产品', + dateRange: '日期范围', + startDate: '开始时间', + endDate: '结束时间', + baogongNum: '报工数', + passNum: '合格数', + noPassNum: '不合格数', + passRate: '合格率', + trendChart: '趋势图', + taskPlaceholder: '任务模式开发中', + totalTask: '任务总数', + waitingProduction: '待生产', + producing: '生产中', + completed: '已完成', + taskTrend: '任务趋势', + rangeYear: '近一年', + rangeMonth: '本月', + rangeWeek: '本周', + rangeToday: '今日', + rangeCustom: '自定义', + monday: '周一', + tuesday: '周二', + wednesday: '周三', + thursday: '周四', + friday: '周五', + saturday: '周六', + sunday: '周日' + }, + functionCommon: { + search: '查询', + cancel: '取消', + save: '保存', + loading: '加载中...', + loadingMore: '正在加载更多...', + noMoreData: '没有更多数据了', + noIdView: '缺少ID,无法查看详情', + noIdEdit: '缺少ID,无法编辑', + noIdDelete: '缺少ID,无法删除', + loadFailed: '加载失败', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + saveFailed: '保存失败', + createSuccess: '新增成功', + updateSuccess: '更新成功', + confirmDelete: '确认删除', + uploading: '上传中', + uploadImageFailed: '图片上传失败', + yes: '是', + no: '否' + }, + moldGet: { + moduleName: '模具出库', + subTitle: '按出库单号与状态快速筛选', + detailTitle: '模具出库详情', + basicInfo: '基础信息', + outNo: '出库单号', + outType: '出库类型', + outTime: '出库时间', + outTimeSingle: '出库日期', + outTimePlaceholder: '请选择出库日期', + warehouse: '仓库', + allWarehouse: '全部仓库', + warehousePlaceholder: '请选择仓库', + creator: '创建人', + status: '状态', + allStatus: '全部状态', + remark: '备注', + itemRemark: '明细备注', + attachment: '附件', + fileUrlPlaceholder: '请输入附件地址', + remarkPlaceholder: '请输入备注', + moldName: '模具', + moldCode: '模具编码', + moldStatus: '模具状态', + moldUseTime: '使用次数', + machineName: '使用设备', + isEnable: '是否启用', + createTime: '创建时间', + searchNo: '请输入出库单号', + searchMold: '请输入模具编码或名称', + searchCode: '请输入模具编码', + searchName: '请输入模具名称', + itemListTitle: '出库明细', + selectMold: '选择模具', + noItems: '暂无出库明细', + count: '数量', + noAuto: '系统自动生成', + createTitle: '新增模具出库', + editTitle: '编辑模具出库', + edit: '编辑', + delete: '删除', + approve: '审批', + empty: '暂无模具出库数据', + noMoldData: '暂无可选模具', + loadEditFailed: '加载编辑数据失败', + validatorOutTimeRequired: '出库日期不能为空', + validatorWarehouseRequired: '仓库不能为空', + validatorItemRequired: '请至少选择一个模具', + validatorCountRequired: '数量必须大于0', + confirmDelete: '确认删除出库单 {no} 吗?', + confirmApprove: '确认审批出库单 {no} 吗?', + approveSuccess: '审批成功' + }, + moldReturn: { + moduleName: '模具入库', + subTitle: '按入库单号与状态快速筛选', + detailTitle: '模具入库详情', + basicInfo: '基础信息', + inNo: '入库单号', + inType: '入库类型', + inTime: '入库时间', + inTimeSingle: '入库日期', + inTimePlaceholder: '请选择入库日期', + warehouse: '仓库', + allWarehouse: '全部仓库', + warehousePlaceholder: '请选择仓库', + creator: '创建人', + status: '状态', + allStatus: '全部状态', + remark: '备注', + itemRemark: '明细备注', + attachment: '附件', + fileUrlPlaceholder: '请输入附件地址', + remarkPlaceholder: '请输入备注', + moldName: '模具', + moldCode: '模具编码', + moldStatus: '模具状态', + moldUseTime: '使用次数', + searchNo: '请输入入库单号', + searchCode: '请输入模具编码', + searchName: '请输入模具名称', + itemListTitle: '入库明细', + selectMold: '选择模具', + noItems: '暂无入库明细', + count: '数量', + noAuto: '系统自动生成', + createTitle: '新增模具入库', + editTitle: '编辑模具入库', + approve: '审批', + empty: '暂无模具入库数据', + noMoldData: '暂无可选模具', + loadEditFailed: '加载编辑数据失败', + validatorInTimeRequired: '入库日期不能为空', + validatorWarehouseRequired: '仓库不能为空', + validatorItemRequired: '请至少选择一个模具', + validatorCountRequired: '数量必须大于0', + confirmDelete: '确认删除入库单 {no} 吗?', + confirmApprove: '确认审批入库单 {no} 吗?', + approveSuccess: '审批成功' + }, + moldOperate: { + moduleName: '上下模', + subTitle: '模具上模/下模操作记录', + detailTitle: '上下模详情', + basicInfo: '基础信息', + tabUp: '上模', + tabDown: '下模', + operateType: '操作类型', + mold: '模具', + lowerMold: '下模模具', + selectMold: '选择模具', + noSelectedMold: '暂无已选模具', + allMold: '全部模具', + searchRemark: '请输入备注关键字', + searchCode: '请输入模具编码', + searchName: '请输入模具名称', + moldCode: '模具编码', + moldName: '模具名称', + device: '设备', + deviceName: '设备名称', + creatorName: '创建人', + remark: '备注', + createTime: '创建时间', + createTitle: '新增上下模', + editTitle: '编辑上下模', + empty: '暂无上下模数据', + noMoldData: '暂无可选模具', + placeholderDevice: '请选择设备', + placeholderRemark: '请输入备注', + validatorOperateTypeRequired: '操作类型不能为空', + validatorDeviceRequired: '设备不能为空', + validatorMoldRequired: '请至少选择一个上模模具', + validatorLowerMoldRequired: '请至少选择一个下模模具', + loadEditFailed: '加载编辑数据失败', + confirmDelete: '确认删除该上下模记录吗?' + }, + moldInspectionItems: { + moduleName: '点检项库', + subTitle: '模具管理点检项维护', + detailTitle: '点检项库详情', + basicInfo: '基础信息', + code: '项目编码', + name: '项目名称', + inspectionMethod: '检验方式', + valueType: '值类型', + isEnable: '是否启用', + judgmentCriteria: '判定基准', + creatorName: '创建人', + createTime: '创建时间', + searchPlaceholder: '请输入编码/名称/判定基准', + createTitle: '新增点检项', + editTitle: '编辑点检项', + empty: '暂无点检项数据', + loadEditFailed: '加载编辑数据失败', + confirmDelete: '确认删除该点检项吗?', + placeholderCode: '请输入项目编码', + placeholderName: '请输入项目名称', + placeholderInspectionMethod: '请选择检验方式', + placeholderValueType: '请选择值类型', + placeholderIsEnable: '请选择是否启用', + placeholderJudgmentCriteria: '请输入判定基准', + validatorSubjectCodeRequired: '项目编码不能为空', + validatorSubjectNameRequired: '项目名称不能为空', + validatorInspectionMethodRequired: '检验方式不能为空', + validatorValueTypeRequired: '值类型不能为空', + validatorIsEnableRequired: '是否启用不能为空', + validatorJudgmentCriteriaRequired: '判定基准不能为空' + }, + mine: { + clickLogin: '点击登录', + username: '用户名:{name}', + profile: '个人信息', + feedback: '反馈中心', + service: '在线客服', + changePassword: '修改密码', + logout: '退出登录', + editProfile: '编辑资料', + faq: '常见问题', + about: '关于我们', + appSettings: '应用设置' + }, + setting: { + language: '系统语言', + currentLanguage: '当前语言:{language}', + switchLanguage: '切换语言', + checkUpdate: '检查更新', + cleanCache: '清理缓存', + logout: '退出登录', + zhCN: '中文', + enUS: '英文' + }, + about: { + appName: '必硕生管系统', + version: '版本信息', + email: '官方邮箱', + hotline: '服务热线', + website: '公司网站' + }, + help: { + appUserQuestion: 'APP用户问题', + otherQuestion: '其他问题', + appFeatureQuestion: 'APP支持的功能业务有哪些?', + appFeatureAnswer: '计划开工、生产报工、投料记录、生产记录', + reportQuestion: '生产报工如何报工?', + reportAnswer: '可以', + planQuestion: '计划管理如何进行?', + planAnswer: '计划管理', + materialQuestion: '投料记录如何进行?', + materialAnswer: '投料记录', + logoutQuestion: '如何退出登录?', + logoutAnswer: '请点击[我的] - [应用设置] - [退出登录]即可退出登录', + avatarQuestion: '如何修改用户头像?', + avatarAnswer: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像', + passwordQuestion: '如何修改登录密码?', + passwordAnswer: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码' + }, + info: { + username: '用户名称', + nickname: '昵称', + gender: '性别', + male: '男', + female: '女', + phone: '手机号码', + email: '邮箱', + createdAt: '创建日期' + }, + editInfo: { + nickname: '用户昵称', + nicknamePlaceholder: '请输入昵称', + phone: '手机号码', + phonePlaceholder: '请输入手机号码', + email: '邮箱', + emailPlaceholder: '请输入邮箱', + gender: '性别', + nicknameRequired: '用户昵称不能为空', + phoneRequired: '手机号码不能为空', + phoneInvalid: '请输入正确的手机号码', + emailRequired: '邮箱地址不能为空', + emailInvalid: '请输入正确的邮箱地址' + }, + pwd: { + oldPassword: '旧密码', + newPassword: '新密码', + confirmPassword: '确认密码', + oldPasswordPlaceholder: '请输入旧密码', + newPasswordPlaceholder: '请输入新密码', + confirmPasswordPlaceholder: '请确认新密码', + oldPasswordRequired: '旧密码不能为空', + newPasswordRequired: '新密码不能为空', + passwordLength: '长度在 6 到 20 个字符', + confirmPasswordRequired: '确认密码不能为空', + passwordNotMatch: '两次输入的密码不一致' + }, + avatar: { + chooseAvatar: '选择头像' + } +} diff --git a/src/pages.json b/src/pages.json index 8afc345..eac24ff 100644 --- a/src/pages.json +++ b/src/pages.json @@ -504,6 +504,12 @@ "navigationBarTitleText": "点检项库详情", "navigationStyle": "custom" } + }, + { + "path": "planList/index", + "style": { + "navigationBarTitleText": "生产计划" + } } ] } diff --git a/src/pages/index.vue b/src/pages/index.vue index f3c81cf..81f20f6 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -23,6 +23,7 @@ + {{ t('dashboard.functionNav') }} @@ -35,6 +36,7 @@ + {{ t('dashboard.productionOverview') }} @@ -45,45 +47,104 @@ + {{ t('dashboard.productionPlan') }} - - {{ isShowAllPlans ? t('dashboard.collapseList') : t('dashboard.viewMore') }} + + {{ t('dashboard.viewMore') }} - - - - {{ plan.code }} - - {{ plan.status }} - + + + {{ currentFilterLabel }} + + + + {{ currentRangeLabel }} + + + + + + + + + + + + + + + + + {{ formatNumber(trendData.baogongNum) }} + {{ t('dashboard.baogongNum') }} - - - {{ t('dashboard.productName') }} - {{ plan.productName }} - - - {{ t('dashboard.pipeline') }} - {{ plan.feedingPipelineName }} - - - {{ t('dashboard.planNumber') }} - {{ plan.planNumber }} - - - {{ t('dashboard.planStart') }} - {{ plan.planStartTimeText }} + + {{ formatNumber(trendData.passNum) }} + {{ t('dashboard.passNum') }} + + + {{ formatNumber(trendData.noPassNum) }} + {{ t('dashboard.noPassNum') }} + + + {{ formatPercent(trendData.passRate) }} + {{ t('dashboard.passRate') }} + + + + {{ t('dashboard.baogongNum') }} + + + - - {{ t('dashboard.planEnd') }} - {{ plan.planEndTimeText }} + + + + {{ t('dashboard.passRate') }} + + + + + + + + + + {{ formatNumber(taskTrendData.totalNum) }} + {{ t('dashboard.totalTask') }} + + + {{ formatNumber(taskTrendData.waitingProductionNum) }} + {{ t('dashboard.waitingProduction') }} + + + {{ formatNumber(taskTrendData.producingNum) }} + {{ t('dashboard.producing') }} + + + {{ formatNumber(taskTrendData.completedNum) }} + {{ t('dashboard.completed') }} + + {{ t('dashboard.taskTrend') }} + + + + + + @@ -93,6 +154,12 @@ + + + + @@ -130,6 +197,7 @@ import { onShow } from '@dcloudio/uni-app' import { useI18n } from 'vue-i18n' import request from '@/utils/request' import { onLocaleChange, offLocaleChange, setNavigationTitle } from '@/locales' +import { formatNumber, formatPercent } from '@/utils/format' const { t } = useI18n() @@ -138,7 +206,6 @@ const todoCount = ref(0); const scrollTop = ref(0) const currentScrollTop = ref(0) const showGoTop = ref(false) -const isShowAllPlans = ref(false) const badgeVisible = computed(() => Number(todoCount.value) > 0) const badgeText = computed(() => { const count = Number(todoCount.value) @@ -162,14 +229,349 @@ const statsData = reactive([ { labelKey: 'finished', type: 'finished' } ]); -const planList = reactive([]); -const hasMorePlans = computed(() => planList.length > 3) -const displayPlanList = computed(() => { - if (isShowAllPlans.value) return planList - return planList.slice(0, 3) +const todoList = reactive([]); + +const showFilterPicker = ref(false) +const showRangePicker = ref(false) +const startPickerRef = ref(null) +const endPickerRef = ref(null) +const currentFilter = ref('task') +const currentRange = ref('month') + +const filterColumns = computed(() => [ + [ + { text: t('dashboard.filterTask'), value: 'task' }, + { text: t('dashboard.filterProduct'), value: 'product' } + ] +]) + +const currentFilterLabel = computed(() => { + return currentFilter.value === 'task' ? t('dashboard.filterTask') : t('dashboard.filterProduct') }) -const todoList = reactive([]); +const rangeColumns = computed(() => [ + [ + { text: t('dashboard.rangeYear'), value: 'year' }, + { text: t('dashboard.rangeMonth'), value: 'month' }, + { text: t('dashboard.rangeWeek'), value: 'week' }, + { text: t('dashboard.rangeToday'), value: 'today' }, + { text: t('dashboard.rangeCustom'), value: 'custom' } + ] +]) + +const rangeLabelMap = computed(() => ({ + year: t('dashboard.rangeYear'), + month: t('dashboard.rangeMonth'), + week: t('dashboard.rangeWeek'), + today: t('dashboard.rangeToday'), + custom: t('dashboard.rangeCustom') +})) + +const currentRangeLabel = computed(() => { + return rangeLabelMap.value[currentRange.value] || t('dashboard.rangeMonth') +}) + +const dateRange = reactive({ start: '', end: '' }) + +const trendData = reactive({ + baogongNum: 0, + passNum: 0, + noPassNum: 0, + passRate: 0 +}) + +const taskTrendData = reactive({ + totalNum: 0, + issuedNum: 0, + partialScheduledNum: 0, + waitingProductionNum: 0, + producingNum: 0, + completedNum: 0 +}) + +const baogongChartData = reactive({ + categories: [], + series: [ + { name: t('dashboard.baogongNum'), data: [] } + ] +}) + +const passRateChartData = reactive({ + categories: [], + series: [ + { name: t('dashboard.passRate'), data: [] } + ] +}) + +const taskChartData = reactive({ + categories: [], + series: [ + { name: t('dashboard.taskTrend'), data: [] } + ] +}) + +const chartWidth = computed(() => { + const count = baogongChartData.categories.length + if (count <= 7) return '100%' + return Math.max(count * 50, 300) + 'rpx' +}) + +function getDateRange(type) { + const now = new Date() + const pad2 = (n) => String(n).padStart(2, '0') + const fmt = (d) => `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}` + const end = fmt(now) + + if (type === 'year') { + const start = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate()) + return { start: fmt(start), end } + } + if (type === 'month') { + const start = new Date(now.getFullYear(), now.getMonth(), 1) + return { start: fmt(start), end } + } + if (type === 'week') { + const day = now.getDay() || 7 + const start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - day + 1) + return { start: fmt(start), end } + } + if (type === 'today') { + return { start: end, end } + } + return { start: '', end: '' } +} + +const weekdayKeys = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] + +function transformChartData(dayTrend, rangeType) { + if (!dayTrend || dayTrend.length === 0) { + return { categories: [], baogongData: [], passRateData: [] } + } + + if (rangeType === 'year') { + const monthMap = new Map() + dayTrend.forEach((item) => { + const m = item.day ? item.day.substring(0, 7) : '' + if (!m) return + if (!monthMap.has(m)) { + monthMap.set(m, { baogongNum: 0, passRateSum: 0, count: 0 }) + } + const entry = monthMap.get(m) + entry.baogongNum += item.baogongNum ?? 0 + entry.passRateSum += item.passRate ?? 0 + entry.count += 1 + }) + const categories = [] + const baogongData = [] + const passRateData = [] + monthMap.forEach((val, key) => { + categories.push(key) + baogongData.push(val.baogongNum) + passRateData.push(val.count > 0 ? Math.round((val.passRateSum / val.count) * 100) / 100 : 0) + }) + return { categories, baogongData, passRateData } + } + + if (rangeType === 'week') { + const categories = dayTrend.map((item) => { + const d = new Date(item.day) + const dayIdx = d.getDay() + return t(`dashboard.${weekdayKeys[dayIdx]}`) + }) + return { + categories, + baogongData: dayTrend.map((item) => item.baogongNum ?? 0), + passRateData: dayTrend.map((item) => item.passRate ?? 0) + } + } + + if (rangeType === 'today') { + const categories = dayTrend.map((item) => { + const dayStr = item.day || '' + return dayStr.substring(5) + }) + return { + categories, + baogongData: dayTrend.map((item) => item.baogongNum ?? 0), + passRateData: dayTrend.map((item) => item.passRate ?? 0) + } + } + + const categories = dayTrend.map((item) => { + const dayStr = item.day || '' + return dayStr.substring(5) + }) + return { + categories, + baogongData: dayTrend.map((item) => item.baogongNum ?? 0), + passRateData: dayTrend.map((item) => item.passRate ?? 0) + } +} + +function onFilterConfirm(e) { + const val = e.value[0]?.value || e.value[0] + currentFilter.value = val + showFilterPicker.value = false + if (val === 'product') { + loadTrendData() + } else if (val === 'task') { + loadTaskTrendData() + } +} + +function onRangeConfirm(e) { + const val = e.value[0]?.value || e.value[0] + currentRange.value = val + showRangePicker.value = false + if (val !== 'custom') { + const range = getDateRange(val) + dateRange.start = range.start + dateRange.end = range.end + if (currentFilter.value === 'product') { + loadTrendData() + } else if (currentFilter.value === 'task') { + loadTaskTrendData() + } + } +} + +function formatTimestamp(ts) { + const d = new Date(ts) + const pad = (n) => String(n).padStart(2, '0') + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}` +} + +function datetimeFormatter(type, value) { + const unitMap = { year: '年', month: '月', day: '日', hour: '时', minute: '分' } + return value + (unitMap[type] || '') +} + +function onStartDateConfirm(e) { + dateRange.start = formatTimestamp(e.value) + if (dateRange.start && dateRange.end) { + if (currentFilter.value === 'product') { + loadTrendData() + } else if (currentFilter.value === 'task') { + loadTaskTrendData() + } + } +} + +function onEndDateConfirm(e) { + dateRange.end = formatTimestamp(e.value) + if (dateRange.start && dateRange.end) { + if (currentFilter.value === 'product') { + loadTrendData() + } else if (currentFilter.value === 'task') { + loadTaskTrendData() + } + } +} + +function onPickerClose() { + if (startPickerRef.value) startPickerRef.value.showByClickInput = false + if (endPickerRef.value) endPickerRef.value.showByClickInput = false +} + +async function loadTrendData() { + const trendTypeMap = { year: 1, month: 2, week: 3, today: 4, custom: 5 } + const params = { trendType: trendTypeMap[currentRange.value] || 2 } + if (currentRange.value === 'custom') { + if (dateRange.start) params.beginBaogongTime = dateRange.start + if (dateRange.end) params.endBaogongTime = dateRange.end + } + const res = await request({ + url: '/admin-api/mes/baogong-record/trend', + method: 'get', + params + }) + const data = res?.data || {} + trendData.baogongNum = data.baogongNum ?? 0 + trendData.passNum = data.passNum ?? 0 + trendData.noPassNum = data.noPassNum ?? 0 + trendData.passRate = data.passRate ?? 0 + + if (currentRange.value === 'custom') { + baogongChartData.categories = [] + baogongChartData.series = [{ name: t('dashboard.baogongNum'), data: [] }] + passRateChartData.categories = [] + passRateChartData.series = [{ name: t('dashboard.passRate'), data: [] }] + return + } + + const dayTrend = data.dayTrend || [] + const transformed = transformChartData(dayTrend, currentRange.value) + baogongChartData.categories = transformed.categories + baogongChartData.series = [ + { name: t('dashboard.baogongNum'), data: transformed.baogongData } + ] + passRateChartData.categories = transformed.categories + passRateChartData.series = [ + { name: t('dashboard.passRate'), data: transformed.passRateData } + ] +} + +async function loadTaskTrendData() { + const trendTypeMap = { year: 1, month: 2, week: 3, today: 4, custom: 5 } + const params = { trendType: trendTypeMap[currentRange.value] || 2 } + if (currentRange.value === 'custom') { + if (dateRange.start) params.beginTime = dateRange.start + if (dateRange.end) params.endTime = dateRange.end + } + const res = await request({ + url: '/admin-api/mes/task/trend', + method: 'get', + params + }) + const data = res?.data || {} + taskTrendData.totalNum = data.totalNum ?? 0 + taskTrendData.issuedNum = data.issuedNum ?? 0 + taskTrendData.partialScheduledNum = data.partialScheduledNum ?? 0 + taskTrendData.waitingProductionNum = data.waitingProductionNum ?? 0 + taskTrendData.producingNum = data.producingNum ?? 0 + taskTrendData.completedNum = data.completedNum ?? 0 + + if (currentRange.value === 'custom') { + taskChartData.categories = [] + taskChartData.series = [{ name: t('dashboard.taskTrend'), data: [] }] + return + } + + const dayTrend = data.dayTrend || [] + const categories = [] + const taskData = [] + if (currentRange.value === 'year') { + const monthMap = new Map() + dayTrend.forEach((item) => { + const m = item.day ? item.day.substring(0, 7) : '' + if (!m) return + if (!monthMap.has(m)) { + monthMap.set(m, 0) + } + monthMap.set(m, (monthMap.get(m) ?? 0) + (item.count ?? 0)) + }) + monthMap.forEach((val, key) => { + categories.push(key) + taskData.push(val) + }) + } else if (currentRange.value === 'week') { + const weekdayKeys = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] + dayTrend.forEach((item) => { + const d = new Date(item.day) + const dayIdx = d.getDay() + categories.push(t(`dashboard.${weekdayKeys[dayIdx]}`)) + taskData.push(item.count ?? 0) + }) + } else { + dayTrend.forEach((item) => { + const dayStr = item.day || '' + categories.push(dayStr.substring(5)) + taskData.push(item.count ?? 0) + }) + } + taskChartData.categories = categories + taskChartData.series = [{ name: t('dashboard.taskTrend'), data: taskData }] +} function showTodoList() { todoPopup.value.open(); @@ -199,16 +601,8 @@ function handleNavClick(item) { } } -function handlePlanClick(plan) { - uni.showToast({ - title: t('dashboard.viewPlan', { code: plan.code }), - icon: 'none' - }); -} - function viewMorePlans() { - if (!hasMorePlans.value && !isShowAllPlans.value) return - isShowAllPlans.value = !isShowAllPlans.value + uni.navigateTo({ url: '/pages_function/pages/planList/index' }) } function onScroll(e) { @@ -235,26 +629,6 @@ function formatDate(ms) { return `${y}-${m}-${d}` } -const getPlanStatusLabel = (value) => { - const v = value === '' || value === null || value === undefined ? undefined : String(value) - if (v == '1') return t('dashboard.statusScheduled') - if (v == '6') return t('dashboard.statusTrial') - if (v == '2') return t('dashboard.statusMass') - if (v == '3') return t('dashboard.statusPause') - if (v == '4') return t('dashboard.statusWaitStockIn') - return '-' -} - -function mapPlanStatus(status) { - const v = status === '' || status === null || status === undefined ? undefined : String(status) - if (v == '1') return { status: getPlanStatusLabel(v), statusType: 'pending' } - if (v == '6') return { status: getPlanStatusLabel(v), statusType: 'running' } - if (v == '2') return { status: getPlanStatusLabel(v), statusType: 'running' } - if (v == '3') return { status: getPlanStatusLabel(v), statusType: 'pending' } - if (v == '4') return { status: getPlanStatusLabel(v), statusType: 'finished' } - return { status: getPlanStatusLabel(v), statusType: 'pending' } -} - async function loadProductionStats() { const res = await request({ url: '/admin-api/mes/dashboard/getProduction', method: 'get' }) const taskItems = (res?.data?.taskItems || []).map((i) => ({ @@ -272,29 +646,6 @@ async function loadProductionStats() { }) } -async function loadPlanList() { - const res = await request({ url: '/admin-api/mes/dashboard/getPlan', method: 'get' }) - const raw = Array.isArray(res?.data) ? res.data : (res?.data ? [res.data] : []) - const mapped = raw.map((p) => { - const statusInfo = mapPlanStatus(p?.status) - return { - id: p?.id, - code: p?.code ?? '-', - status: statusInfo.status, - statusType: statusInfo.statusType, - productName: p?.productName ?? '-', - feedingPipelineName: p?.feedingPipelineName ?? '-', - planNumber: p?.planNumber ?? 0, - planStartTimeText: formatDate(p?.planStartTime), - planEndTimeText: formatDate(p?.planEndTime), - } - }) - planList.splice(0, planList.length, ...mapped) - if (mapped.length <= 3) { - isShowAllPlans.value = false - } -} - async function loadTodoList() { const res = await request({ url: '/admin-api/mes/dashboard/getTodoList', method: 'get' }) const data = res?.data || [] @@ -303,7 +654,7 @@ async function loadTodoList() { } async function loadDashboard() { - await Promise.allSettled([loadProductionStats(), loadPlanList(), loadTodoList()]) + await Promise.allSettled([loadProductionStats(), loadTodoList(), loadTrendData()]) } onMounted(() => { @@ -609,89 +960,165 @@ onUnmounted(() => { box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); } -.plan-list { +.filter-bar { display: flex; - flex-direction: column; + align-items: center; + margin-bottom: 24rpx; } -.plan-card { - background: #f8fafc; - border-radius: 16rpx; - padding: 24rpx; - margin-bottom: 20rpx; - - &:last-child { - margin-bottom: 0; - } +.filter-select { + display: flex; + align-items: center; + padding: 12rpx 24rpx; + background: #f0f2f5; + border-radius: 12rpx; + margin-right: 20rpx; &:active { - background: #e8f4ff; + background: #e8ecf0; } } -.plan-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20rpx; -} - -.plan-code { - font-size: 28rpx; - font-weight: 600; +.filter-text { + font-size: 26rpx; color: #1a3a5c; + font-weight: 500; + margin-right: 8rpx; } -.plan-status { - padding: 8rpx 20rpx; - border-radius: 20rpx; - font-size: 22rpx; +.filter-arrow { + font-size: 20rpx; + color: #999999; } -.status-pending { - background: rgba(255, 140, 0, 0.15); - color: #ff8c00; +.filter-date-wrap { + display: flex; + gap: 16rpx; + margin-bottom: 24rpx; + flex-wrap: wrap; } -.status-running { - background: rgba(24, 188, 55, 0.15); - color: #18bc37; -} +.date-picker-item { + flex: 1; + min-width: 200rpx; + display: flex; + align-items: center; + position: relative; + background: #f8fafc; + border-radius: 12rpx; + padding: 6rpx 12rpx; + border: 2rpx solid #e0e6ed; + transition: border-color 0.3s ease; + + &:focus-within { + border-color: #4a90c2; + background: #ffffff; + } + + :deep(.u-datetime-picker) { + flex: 1; + + .u-input { + padding-left: 40rpx; + background: transparent; + border: none; + } + } -.status-finished { - background: rgba(74, 144, 194, 0.15); - color: #4a90c2; + .up-icon { + position: absolute; + left: 12rpx; + z-index: 1; + color: #4a90c2; + } } -.plan-body { - display: flex; - flex-direction: column; +.trend-content { + margin-top: 8rpx; } -.plan-row { +.trend-stats { display: flex; justify-content: space-between; - align-items: center; - margin-bottom: 12rpx; + margin-bottom: 24rpx; +} + +.trend-stat-card { + flex: 1; + background: #f8fafc; + border-radius: 12rpx; + padding: 20rpx 12rpx; + margin: 0 6rpx; + text-align: center; + + &:first-child { + margin-left: 0; + } &:last-child { - margin-bottom: 0; + margin-right: 0; } } -.plan-label { - font-size: 26rpx; +.trend-stat-value { + display: block; + font-size: 36rpx; + font-weight: bold; + color: #1a3a5c; + margin-bottom: 6rpx; + + &.pass { + color: #18bc37; + } + + &.fail { + color: #ff4d4f; + } + + &.rate { + color: #4a90c2; + } +} + +.trend-stat-label { + display: block; + font-size: 22rpx; color: #999999; } -.plan-value { - font-size: 26rpx; - color: #333333; +.trend-chart { + margin-top: 8rpx; } -.plan-num { - font-weight: 600; +.chart-title { + display: block; + font-size: 28rpx; + font-weight: 500; color: #1a3a5c; + margin-bottom: 16rpx; +} + +.chart-scroll { + width: 100%; + white-space: nowrap; +} + +.chart-box { + width: 100%; + height: 450rpx; + min-width: 100%; +} + +.task-placeholder { + display: flex; + align-items: center; + justify-content: center; + height: 300rpx; +} + +.placeholder-text { + font-size: 28rpx; + color: #999999; } .todo-popup { diff --git a/src/pages_function/pages/planList/index.vue b/src/pages_function/pages/planList/index.vue new file mode 100644 index 0000000..7307b8c --- /dev/null +++ b/src/pages_function/pages/planList/index.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/src/utils/format.js b/src/utils/format.js new file mode 100644 index 0000000..1d19442 --- /dev/null +++ b/src/utils/format.js @@ -0,0 +1,39 @@ +import { getCurrentLocale } from '@/locales' + +const ZH_UNITS = [ + { value: 1e8, symbol: '亿' }, + { value: 1e6, symbol: '百万' }, + { value: 1e4, symbol: '万' } +] + +const EN_UNITS = [ + { value: 1e9, symbol: 'B' }, + { value: 1e6, symbol: 'M' }, + { value: 1e3, symbol: 'K' } +] + +function formatWithUnits(num, units, decimals) { + for (const unit of units) { + if (num >= unit.value) { + const formatted = num / unit.value + const rounded = parseFloat(formatted.toFixed(decimals)) + return rounded + unit.symbol + } + } + return num.toLocaleString() +} + +export function formatNumber(num, options = {}) { + if (num === null || num === undefined || isNaN(num)) return '-' + const { decimals = 1, locale } = options + const currentLocale = locale || getCurrentLocale() + const isZh = currentLocale.startsWith('zh') + const units = isZh ? ZH_UNITS : EN_UNITS + return formatWithUnits(Number(num), units, decimals) +} + +export function formatPercent(num, options = {}) { + if (num === null || num === undefined || isNaN(num)) return '-' + const { decimals = 1 } = options + return parseFloat(Number(num).toFixed(decimals)) + '%' +} diff --git a/vite.config.js b/vite.config.js index 246843c..2723f4f 100644 --- a/vite.config.js +++ b/vite.config.js @@ -9,7 +9,7 @@ export default defineConfig(() => { outDir: 'dist', }, server: { - port: '80' + port: 9000 }, plugins: [ uni() @@ -18,4 +18,4 @@ export default defineConfig(() => { /\/README\.md$/, ] } -}) \ No newline at end of file +})