| src/main/resources/i18n/en-US/messages.properties | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/i18n/zh-CN/messages.properties | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/webapp/static/js/login/login.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/webapp/views/login.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/resources/i18n/en-US/messages.properties
@@ -16,6 +16,17 @@ common.workPage=Work Page common.businessPage=Business Page login.title=WCS System V3.0 login.subtitle=Please enter your account and password to access the system. login.hero.title=The WCS keeps device scheduling, task execution, and on-site monitoring within the same business workflow. login.hero.subtitle=The Warehouse Control System is built for automated AS/RS execution, coordinating cranes, RGVs, conveyor stations, task commands, location status, and log tracing through unified dispatch and visualization. It helps warehouse operations stay stable, traceable, and collaborative. Zhejiang Zhongyang Warehouse Technology Co., Ltd. focuses on automated AS/RS and intelligent intralogistics systems, covering solution design, software control, equipment integration, and project delivery. login.hero.metric.dispatch.title=Dispatch login.hero.metric.dispatch.desc=Unified orchestration of on-site execution tasks login.hero.metric.trace.title=Traceability login.hero.metric.trace.desc=End-to-end traceability across jobs, devices, and logs login.hero.metric.integration.title=Integration login.hero.metric.integration.desc=Integrates WMS, devices, and business rules login.hero.company.name=Zhejiang Zhongyang Warehouse Technology Co., Ltd. login.hero.company.solution=Automated AS/RS and intelligent logistics system solutions login.username=Account login.password=Password login.submit=Sign In @@ -37,6 +48,35 @@ login.serverInfo.title=System Configuration login.serverInfo.label=System Configuration login.serverInfo.tip=Legacy projects can still use this hardware JSON to apply for a license. login.dialog.close=Close login.mfa.title=MFA Verification login.mfa.tip=Account and password verified. Enter the 6-digit code from your authenticator app to continue signing in. login.mfa.currentAccount=Current account: login.mfa.codeLabel=Verification Code login.mfa.codePlaceholder=Please enter the 6-digit code login.mfa.cancel=Cancel login.mfa.submit=Verify and Sign In login.license.label=License Base64 login.license.tip=Paste the full license field returned by the license service here. login.license.submit=Submit login.license.success=License updated successfully login.validation.usernameRequired=Please enter the account login.validation.passwordRequired=Please enter the password login.validation.mfaRequired=Please enter the 6-digit verification code login.validation.mfaInvalid=Please enter a 6-digit numeric verification code login.error.loginFailed=Login failed login.error.mfaTicketExpired=The login ticket has expired. Please sign in again login.error.mfaFailed=Verification failed login.error.requestCodeFailed=Failed to get request code login.error.serverInfoFailed=Failed to get system configuration login.error.licenseEmpty=License content cannot be empty login.error.licenseUpdateFailed=Failed to update license login.error.licenseImportFailed=Failed to import license login.activate.confirm=Are you sure you want to activate now? login.activate.success=Activation successful login.activate.failed=Activation failed login.projectName.title=Project Name login.error.projectNameFailed=Failed to get project name index.searchMenu=Search menu index.noMatchedMenu=No matching menus index.noAvailableMenu=No available menus for current account src/main/resources/i18n/zh-CN/messages.properties
@@ -16,6 +16,17 @@ common.workPage=工作页面 common.businessPage=业务页面 login.title=WCS系统V3.0 login.subtitle=请输入账号和密码进入系统。 login.hero.title=WCS系统让设备调度、任务执行与现场监控保持在同一套业务链路中。 login.hero.subtitle=Warehouse Control System 面向自动化立体仓库现场执行层,围绕堆垛机、RGV、输送站台、任务指令、库位状态和日志追踪进行统一调度与可视化管理,帮助仓储系统实现稳定、可追溯、可联动的作业控制。浙江中扬立库技术有限公司长期专注于自动化立体仓库与智能物流系统建设,覆盖方案设计、软件控制、设备集成与项目实施交付。 login.hero.metric.dispatch.title=调度 login.hero.metric.dispatch.desc=统一编排现场执行任务 login.hero.metric.trace.title=追溯 login.hero.metric.trace.desc=作业、设备、日志全链路留痕 login.hero.metric.integration.title=集成 login.hero.metric.integration.desc=对接WMS、设备与业务规则 login.hero.company.name=浙江中扬立库技术有限公司 login.hero.company.solution=自动化立体仓库与智能物流系统解决方案 login.username=账号 login.password=密码 login.submit=登录 @@ -37,6 +48,35 @@ login.serverInfo.title=获取系统配置 login.serverInfo.label=系统配置信息 login.serverInfo.tip=老项目仍可继续使用这份硬件信息 JSON 申请许可证。 login.dialog.close=关闭 login.mfa.title=MFA二次验证 login.mfa.tip=账号密码已通过,请输入身份验证器中的 6 位动态验证码后继续登录。 login.mfa.currentAccount=当前账号: login.mfa.codeLabel=验证码 login.mfa.codePlaceholder=请输入6位动态码 login.mfa.cancel=取消 login.mfa.submit=验证并登录 login.license.label=许可证 Base64 login.license.tip=将许可证服务端返回的 license 字段完整粘贴到这里。 login.license.submit=提交 login.license.success=许可证更新成功 login.validation.usernameRequired=请输入账号 login.validation.passwordRequired=请输入密码 login.validation.mfaRequired=请输入6位验证码 login.validation.mfaInvalid=请输入6位数字验证码 login.error.loginFailed=登录失败 login.error.mfaTicketExpired=登录票据已失效,请重新登录 login.error.mfaFailed=验证失败 login.error.requestCodeFailed=获取请求码失败 login.error.serverInfoFailed=获取系统配置信息失败 login.error.licenseEmpty=许可证内容不能为空 login.error.licenseUpdateFailed=许可证更新失败 login.error.licenseImportFailed=许可证录入失败 login.activate.confirm=确定执行一键激活吗? login.activate.success=激活成功 login.activate.failed=激活失败 login.projectName.title=项目名称 login.error.projectNameFailed=获取项目名称失败 index.searchMenu=搜索菜单 index.noMatchedMenu=没有匹配菜单 index.noAvailableMenu=当前账号没有可用菜单 src/main/webapp/static/js/login/login.js
@@ -69,19 +69,50 @@ var localeTick = this.localeTick; void localeTick; if (window.WCS_I18N && typeof window.WCS_I18N.t === "function") { return window.WCS_I18N.t(key); var translated = window.WCS_I18N.t(key); if (translated && translated !== key) { return translated; } } return fallback || key; }, refreshRuleMessages: function () { var vm = this; vm.loginRules = { mobile: [ { required: true, message: vm.text("login.validation.usernameRequired", "请输入账号"), trigger: "blur" } ], password: [ { required: true, message: vm.text("login.validation.passwordRequired", "请输入密码"), trigger: "blur" } ] }; vm.mfaRules = { code: [ { required: true, message: vm.text("login.validation.mfaRequired", "请输入6位验证码"), trigger: "blur" }, { validator: function (rule, value, callback) { if (!/^\d{6}$/.test(String(value || "").trim())) { callback(new Error(vm.text("login.validation.mfaInvalid", "请输入6位数字验证码"))); return; } callback(); }, trigger: "blur" } ] }; }, initLanguageSwitch: function () { var vm = this; if (!window.WCS_I18N || typeof window.WCS_I18N.onReady !== "function") { vm.refreshRuleMessages(); return; } window.WCS_I18N.onReady(function (i18n) { vm.localeOptions = i18n.getLocaleOptions(); vm.currentLocale = i18n.getLocale(); document.title = i18n.t("login.title"); vm.refreshRuleMessages(); vm.localeTick++; }); }, @@ -138,13 +169,13 @@ vm.openMfaDialog(payload); return; } vm.finishLogin(payload); return; } vm.$message.error(res.msg || "登录失败"); vm.finishLogin(payload); return; } vm.$message.error(res.msg || vm.text("login.error.loginFailed", "登录失败")); }, error: function () { vm.$message.error("登录失败"); vm.$message.error(vm.text("login.error.loginFailed", "登录失败")); }, complete: function () { vm.loginLoading = false; @@ -192,7 +223,7 @@ submitMfaLogin: function () { var vm = this; if (!vm.mfaPending.ticket) { vm.$message.error("登录票据已失效,请重新登录"); vm.$message.error(vm.text("login.error.mfaTicketExpired", "登录票据已失效,请重新登录")); vm.closeMfaDialog(); return; } @@ -209,10 +240,10 @@ vm.finishLogin(res.data || {}); return; } vm.$message.error(res.msg || "验证失败"); vm.$message.error(res.msg || vm.text("login.error.mfaFailed", "验证失败")); }, error: function () { vm.$message.error("验证失败"); vm.$message.error(vm.text("login.error.mfaFailed", "验证失败")); }, complete: function () { vm.mfaLoading = false; @@ -250,9 +281,9 @@ textarea.select(); document.execCommand("copy"); document.body.removeChild(textarea); this.$message.success("已复制到剪贴板"); this.$message.success(this.text("login.dialog.copied", "已复制到剪贴板")); } catch (err) { this.$message.error("复制失败"); this.$message.error(this.text("login.dialog.copyFailed", "复制失败")); } }, copyText: function () { @@ -260,7 +291,7 @@ var text = vm.textDialog.text || ""; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(function () { vm.$message.success("已复制到剪贴板"); vm.$message.success(vm.text("login.dialog.copied", "已复制到剪贴板")); }).catch(function () { vm.fallbackCopy(text); }); @@ -275,13 +306,18 @@ method: "GET", success: function (res) { if (Number(res.code) === 200) { vm.openTextDialog("获取请求码", "请求码", res.msg || "", "请求码中已包含项目名称,直接发给许可证服务端即可。"); vm.openTextDialog( vm.text("login.requestCode.title", "获取请求码"), vm.text("login.requestCode.label", "请求码"), res.msg || "", vm.text("login.requestCode.tip", "请求码中已包含项目名称,直接发给许可证服务端即可。") ); return; } vm.$message.error(res.msg || "获取请求码失败"); vm.$message.error(res.msg || vm.text("login.error.requestCodeFailed", "获取请求码失败")); }, error: function () { vm.$message.error("获取请求码失败"); vm.$message.error(vm.text("login.error.requestCodeFailed", "获取请求码失败")); } }); }, @@ -291,17 +327,22 @@ url: baseUrl + "/license/getServerInfos", method: "GET", success: function (res) { vm.openTextDialog("获取系统配置", "系统配置信息", res, "老项目仍可继续使用这份硬件信息 JSON 申请许可证。"); vm.openTextDialog( vm.text("login.serverInfo.title", "获取系统配置"), vm.text("login.serverInfo.label", "系统配置信息"), res, vm.text("login.serverInfo.tip", "老项目仍可继续使用这份硬件信息 JSON 申请许可证。") ); }, error: function () { vm.$message.error("获取系统配置信息失败"); vm.$message.error(vm.text("login.error.serverInfoFailed", "获取系统配置信息失败")); } }); }, submitLicense: function () { var vm = this; if (!vm.licenseBase64) { vm.$message.warning("许可证内容不能为空"); vm.$message.warning(vm.text("login.error.licenseEmpty", "许可证内容不能为空")); return; } ajaxJson({ @@ -313,35 +354,35 @@ if (Number(res.code) === 200) { vm.uploadDialogVisible = false; vm.licenseBase64 = ""; vm.$message.success("许可证更新成功"); vm.$message.success(vm.text("login.license.success", "许可证更新成功")); return; } vm.$message.error(res.msg || "许可证更新失败"); vm.$message.error(res.msg || vm.text("login.error.licenseUpdateFailed", "许可证更新失败")); }, error: function () { vm.$message.error("许可证录入失败"); vm.$message.error(vm.text("login.error.licenseImportFailed", "许可证录入失败")); } }); }, activateLicense: function () { var vm = this; vm.$confirm("确定执行一键激活吗?", "提示", { vm.$confirm(vm.text("login.activate.confirm", "确定执行一键激活吗?"), vm.text("common.prompt", "提示"), { type: "warning", confirmButtonText: "确定", cancelButtonText: "取消" confirmButtonText: vm.text("common.ok", "确定"), cancelButtonText: vm.text("login.mfa.cancel", "取消") }).then(function () { ajaxJson({ url: baseUrl + "/license/activate", method: "POST", success: function (res) { if (Number(res.code) === 200) { vm.$message.success("激活成功"); vm.$message.success(vm.text("login.activate.success", "激活成功")); return; } vm.$message.error(res.msg || "激活失败"); vm.$message.error(res.msg || vm.text("login.activate.failed", "激活失败")); }, error: function () { vm.$message.error("激活失败"); vm.$message.error(vm.text("login.activate.failed", "激活失败")); } }); }).catch(function () { @@ -354,15 +395,15 @@ method: "GET", success: function (res) { if (Number(res.code) === 200) { vm.$alert(res.msg || "", "项目名称", { confirmButtonText: "确定" vm.$alert(res.msg || "", vm.text("login.projectName.title", "项目名称"), { confirmButtonText: vm.text("common.ok", "确定") }); return; } vm.$message.error(res.msg || "获取项目名称失败"); vm.$message.error(res.msg || vm.text("login.error.projectNameFailed", "获取项目名称失败")); }, error: function () { vm.$message.error("获取项目名称失败"); vm.$message.error(vm.text("login.error.projectNameFailed", "获取项目名称失败")); } }); } src/main/webapp/views/login.html
@@ -454,37 +454,34 @@ <div class="login-layout"> <section class="hero-panel animate__animated animate__fadeInLeft"> <div class="brand-chip">Zoneyung WCS</div> <div class="hero-title">WCS系统让设备调度、任务执行与现场监控保持在同一套业务链路中。</div> <div class="hero-title">{{ text('login.hero.title', 'WCS系统让设备调度、任务执行与现场监控保持在同一套业务链路中。') }}</div> <div class="hero-subtitle"> Warehouse Control System 面向自动化立体仓库现场执行层,围绕堆垛机、RGV、输送站台、任务指令、 库位状态和日志追踪进行统一调度与可视化管理,帮助仓储系统实现稳定、可追溯、可联动的作业控制。 浙江中扬立库技术有限公司长期专注于自动化立体仓库与智能物流系统建设,覆盖方案设计、软件控制、 设备集成与项目实施交付。 {{ text('login.hero.subtitle', 'Warehouse Control System 面向自动化立体仓库现场执行层,围绕堆垛机、RGV、输送站台、任务指令、库位状态和日志追踪进行统一调度与可视化管理,帮助仓储系统实现稳定、可追溯、可联动的作业控制。浙江中扬立库技术有限公司长期专注于自动化立体仓库与智能物流系统建设,覆盖方案设计、软件控制、设备集成与项目实施交付。') }} </div> <div class="hero-metrics"> <div class="metric-card"> <div class="metric-value">调度</div> <div class="metric-label">统一编排现场执行任务</div> <div class="metric-value">{{ text('login.hero.metric.dispatch.title', '调度') }}</div> <div class="metric-label">{{ text('login.hero.metric.dispatch.desc', '统一编排现场执行任务') }}</div> </div> <div class="metric-card"> <div class="metric-value">追溯</div> <div class="metric-label">作业、设备、日志全链路留痕</div> <div class="metric-value">{{ text('login.hero.metric.trace.title', '追溯') }}</div> <div class="metric-label">{{ text('login.hero.metric.trace.desc', '作业、设备、日志全链路留痕') }}</div> </div> <div class="metric-card"> <div class="metric-value">集成</div> <div class="metric-label">对接WMS、设备与业务规则</div> <div class="metric-value">{{ text('login.hero.metric.integration.title', '集成') }}</div> <div class="metric-label">{{ text('login.hero.metric.integration.desc', '对接WMS、设备与业务规则') }}</div> </div> </div> <div class="hero-footer"> <span>浙江中扬立库技术有限公司</span> <span>自动化立体仓库与智能物流系统解决方案</span> <span>{{ text('login.hero.company.name', '浙江中扬立库技术有限公司') }}</span> <span>{{ text('login.hero.company.solution', '自动化立体仓库与智能物流系统解决方案') }}</span> </div> </section> <section class="login-card animate__animated animate__fadeInUp"> <div class="login-head"> <h1 class="login-title" @click="handleTitleClick">{{ text('login.title', 'WCS系统V3.0') }}</h1> <div class="login-subtitle">请输入账号和密码进入系统。</div> <div class="login-subtitle">{{ text('login.subtitle', '请输入账号和密码进入系统。') }}</div> </div> <div class="login-body"> <el-form ref="loginForm" class="login-form" :model="loginForm" :rules="loginRules" @submit.native.prevent> @@ -506,7 +503,7 @@ </section> </div> <el-dialog class="tools-dialog" title="系统工具" :visible.sync="toolsDialogVisible" width="560px" :close-on-click-modal="true" append-to-body> <el-dialog class="tools-dialog" :title="text('login.tools.title', '系统工具')" :visible.sync="toolsDialogVisible" width="560px" :close-on-click-modal="true" append-to-body> <div class="tool-group"> <div class="tool-title">{{ text('login.tools.recommended', '推荐操作') }}</div> <div class="tool-actions"> @@ -527,22 +524,22 @@ <el-dialog class="mfa-dialog" title="MFA二次验证" :title="text('login.mfa.title', 'MFA二次验证')" :visible.sync="mfaDialogVisible" width="420px" :close-on-click-modal="false" @close="closeMfaDialog" append-to-body> <div class="mfa-tip">账号密码已通过,请输入身份验证器中的 6 位动态验证码后继续登录。</div> <div class="mfa-account">当前账号:<strong>{{ mfaPending.username || loginForm.mobile || '--' }}</strong></div> <div class="mfa-tip">{{ text('login.mfa.tip', '账号密码已通过,请输入身份验证器中的 6 位动态验证码后继续登录。') }}</div> <div class="mfa-account">{{ text('login.mfa.currentAccount', '当前账号:') }}<strong>{{ mfaPending.username || loginForm.mobile || '--' }}</strong></div> <el-form ref="mfaForm" :model="mfaForm" :rules="mfaRules" label-width="82px" size="small" @submit.native.prevent> <el-form-item label="验证码" prop="code"> <el-input v-model.trim="mfaForm.code" maxlength="6" placeholder="请输入6位动态码" @keyup.enter.native="handleMfaLogin"></el-input> <el-form-item :label="text('login.mfa.codeLabel', '验证码')" prop="code"> <el-input v-model.trim="mfaForm.code" maxlength="6" :placeholder="text('login.mfa.codePlaceholder', '请输入6位动态码')" @keyup.enter.native="handleMfaLogin"></el-input> </el-form-item> </el-form> <div class="mfa-footer"> <el-button @click="closeMfaDialog">取消</el-button> <el-button type="primary" :loading="mfaLoading" @click="handleMfaLogin">验证并登录</el-button> <el-button @click="closeMfaDialog">{{ text('login.mfa.cancel', '取消') }}</el-button> <el-button type="primary" :loading="mfaLoading" @click="handleMfaLogin">{{ text('login.mfa.submit', '验证并登录') }}</el-button> </div> </el-dialog> @@ -551,18 +548,18 @@ <div v-if="textDialog.tip" class="dialog-text-tip">{{ textDialog.tip }}</div> <el-input v-model="textDialog.text" type="textarea" :rows="10" readonly></el-input> <div class="text-footer"> <el-button @click="textDialogVisible = false">关闭</el-button> <el-button @click="textDialogVisible = false">{{ text('login.dialog.close', '关闭') }}</el-button> <el-button type="primary" @click="copyText">{{ text('copy', '复制') }}</el-button> </div> </el-dialog> <el-dialog class="upload-dialog" title="录入许可证" :visible.sync="uploadDialogVisible" width="760px" append-to-body> <div class="dialog-text-label">许可证 Base64</div> <div class="dialog-text-tip">将许可证服务端返回的 license 字段完整粘贴到这里。</div> <el-dialog class="upload-dialog" :title="text('login.tools.uploadLicense', '录入许可证')" :visible.sync="uploadDialogVisible" width="760px" append-to-body> <div class="dialog-text-label">{{ text('login.license.label', '许可证 Base64') }}</div> <div class="dialog-text-tip">{{ text('login.license.tip', '将许可证服务端返回的 license 字段完整粘贴到这里。') }}</div> <el-input v-model.trim="licenseBase64" type="textarea" :rows="10"></el-input> <div class="upload-footer"> <el-button @click="uploadDialogVisible = false">取消</el-button> <el-button type="primary" @click="submitLicense">提交</el-button> <el-button @click="uploadDialogVisible = false">{{ text('login.mfa.cancel', '取消') }}</el-button> <el-button type="primary" @click="submitLicense">{{ text('login.license.submit', '提交') }}</el-button> </div> </el-dialog> </div>