多语言

main
768863620@qq.com 2024-09-20 15:54:44 +08:00
parent efe3644f6a
commit 5c74590560
7 changed files with 178 additions and 89 deletions

View File

@ -47,6 +47,7 @@
"vue-count-to": "^1.0.13", "vue-count-to": "^1.0.13",
"vue-cropper": "0.4.9", "vue-cropper": "0.4.9",
"vue-echarts": "^5.0.0-beta.0", "vue-echarts": "^5.0.0-beta.0",
"vue-i18n": "^8.28.2",
"vue-image-crop-upload": "^2.5.0", "vue-image-crop-upload": "^2.5.0",
"vue-router": "3.0.2", "vue-router": "3.0.2",
"vue-splitpane": "1.0.4", "vue-splitpane": "1.0.4",

View File

@ -3,14 +3,14 @@
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="$t(item.meta.title)" />
</el-menu-item> </el-menu-item>
</app-link> </app-link>
</template> </template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title"> <template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="$t(item.meta.title)" />
</template> </template>
<sidebar-item <sidebar-item
v-for="child in item.children" v-for="child in item.children"

View File

@ -12,7 +12,7 @@
@click.middle.native="closeSelectedTag(tag)" @click.middle.native="closeSelectedTag(tag)"
@contextmenu.prevent.native="openMenu(tag,$event)" @contextmenu.prevent.native="openMenu(tag,$event)"
> >
{{ tag.title }} {{$t(tag.title )}}
<span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> <span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</router-link> </router-link>
</scroll-pane> </scroll-pane>

View File

@ -4,7 +4,14 @@ import Cookies from 'js-cookie'
import 'normalize.css/normalize.css' import 'normalize.css/normalize.css'
import VueClipboard from 'vue-clipboard2' import VueClipboard from 'vue-clipboard2'
import ElementUI from 'element-ui'
import Element, { Table, TableColumn } from 'element-ui' import Element, { Table, TableColumn } from 'element-ui'
import VueI18n from 'vue-i18n'
import locale from 'element-ui/lib/locale'
import enLocale from './i18n/en'
import zhCNLocale from './i18n/zh-CN'
const TableProps = Element.Table.props const TableProps = Element.Table.props
const TableColumnProps = Element.TableColumn.props const TableColumnProps = Element.TableColumn.props
TableProps.border = { type: Boolean, default: true } // 边框 TableProps.border = { type: Boolean, default: true } // 边框
@ -14,10 +21,11 @@ TableColumnProps.showOverflowTooltip = { type: Boolean, default: true } // 文
TableColumnProps.sortable = { type: Boolean, default: true } // 置默认的排序列和排序顺序 TableColumnProps.sortable = { type: Boolean, default: true } // 置默认的排序列和排序顺序
Vue.use(Table) Vue.use(Table)
Vue.use(TableColumn) Vue.use(TableColumn)
Vue.use(ElementUI, { locale })
// 数据字典 // 数据字典
import dict from './components/Dict' import dict from './components/Dict'
import FileSaver from "file-saver"; import FileSaver from 'file-saver'
import XLSX from "xlsx"; import XLSX from 'xlsx'
// 权限指令 // 权限指令
import checkPer from '@/utils/permission' import checkPer from '@/utils/permission'
import permission from './components/Permission' import permission from './components/Permission'
@ -36,16 +44,32 @@ Vue.use(VueClipboard)
Vue.use(checkPer) Vue.use(checkPer)
Vue.use(permission) Vue.use(permission)
Vue.use(dict) Vue.use(dict)
Vue.use(VueI18n)
const messages = {
en: enLocale,
'zh': zhCNLocale
}
const i18n = new VueI18n({
locale: 'en', // 设置默认语言
messages
})
Vue.use(Element, { Vue.use(Element, {
size: Cookies.get('size') || 'small' // set element-ui default size size: Cookies.get('size') || 'small' // set element-ui default size
}) })
locale.i18n((key, value) => i18n.t(key, value))
Vue.use(ElementUI, { i18n: (key, value) => i18n.t(key, value) })
Vue.prototype.$fileSaver = FileSaver Vue.prototype.$fileSaver = FileSaver
Vue.prototype.$xlsx = XLSX Vue.prototype.$xlsx = XLSX
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({
i18n,
el: '#app', el: '#app',
router, router,
store, store,

View File

@ -9,7 +9,7 @@ import { filterAsyncRouter } from '@/store/modules/permission'
NProgress.configure({ showSpinner: false })// NProgress Configuration NProgress.configure({ showSpinner: false })// NProgress Configuration
const whiteList = ['/login', '/401', '404', '/system2/report']// no redirect whitelist const whiteList = ['/login', '/login_en', '/401', '404', '/system2/report']// no redirect whitelist
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (to.meta.title) { if (to.meta.title) {

View File

@ -9,6 +9,10 @@ export const constantRouterMap = [
meta: { title: '登录', noCache: false ,keepAlive:true}, meta: { title: '登录', noCache: false ,keepAlive:true},
component: (resolve) => require(['@/views/login'], resolve), component: (resolve) => require(['@/views/login'], resolve),
hidden: true hidden: true
},{ path: '/login_en',
meta: { title: 'Login', noCache: false ,keepAlive:true},
component: (resolve) => require(['@/views/login_en'], resolve),
hidden: true
},{ path: '/home', },{ path: '/home',
meta: { title: '登录', noCache: false ,keepAlive:true}, meta: { title: '登录', noCache: false ,keepAlive:true},
component: (resolve) => require(['@/views/home'], resolve), component: (resolve) => require(['@/views/home'], resolve),

View File

@ -1,10 +1,22 @@
<template> <template>
<div class="login" :style="'background-image:url('+ Background +');'"> <div class="main_div" :style="'background-image:url('+ Background +');'">
<BindLicense ref="BindLicense"/> <BindLicense ref="BindLicense"/>
<el-row type="flex" style="width: 100%;height: 100%">
<!-- 底部 -->
<!-- <el-col :span="12" ><div class="main_left" ></div></el-col> -->
<el-col :span="24"><div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form">
<h3 class="title" @click="bingLicense"> <div style="margin-top: 20px;margin-right: auto;margin-left: auto;width: 100px;height: 100px">
WMS 管理系统 <el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" style="height: 100px;width: 100px" fit="fill"></el-avatar>
</h3> </div>
<h2 class="title" @click="bingLicense">
欢迎来到 YouChain Plus! 👋
</h2>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
@ -26,13 +38,29 @@
<el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;"> <el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;">
记住我 记住我
</el-checkbox> </el-checkbox>
<el-dropdown style="margin-left: 200px;color: #00a0e9" :trigger="hover" @command="handleCommand">
<span class="el-dropdown-link">
语言切换<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="zh">中文</el-dropdown-item>
<el-dropdown-item command="en">英文</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-form-item style="width:100%;"> <el-form-item style="width:100%;">
<el-button :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin"> <el-button :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin">
<span v-if="!loading"> </span> <span v-if="!loading"> </span>
<span v-else> ...</span> <span v-else> ...</span>
</el-button> </el-button>
</el-form-item> </el-form-item>
<h5 class="zhuce" @click="bingLicense">
如您还没有账号<span style="color: #00a0e9;margin-left: 5px" href="">请联系管理员</span>
</h5>
</el-form> </el-form>
</div></el-col>
</el-row>
<!-- 底部 --> <!-- 底部 -->
<div v-if="$store.state.settings.showFooter" id="el-login-footer"> <div v-if="$store.state.settings.showFooter" id="el-login-footer">
<span v-html="$store.state.settings.footerTxt" /> <span v-html="$store.state.settings.footerTxt" />
@ -48,22 +76,20 @@ import Config from '@/settings'
import { getCodeImg, getDeviceInfo } from '@/api/login' import { getCodeImg, getDeviceInfo } from '@/api/login'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import qs from 'qs' import qs from 'qs'
import Background from '@/assets/images/background.webp' import Background from '@/assets/images/background3.png'
import BindLicense from '@/views/licenseBind.vue' import BindLicense from '@/views/licenseBind.vue'
import BindOrderNumber from '@/views/base-data/box/bindOrderNumber.vue'
export default { export default {
name: 'Login', name: 'Login',
components: { BindOrderNumber, BindLicense }, components: { BindLicense },
data() { data() {
return { return {
click_count: 0, click_count: 0,
dialogFormVisible: true,
Background: Background, Background: Background,
codeUrl: '', codeUrl: '',
cookiePass: '', cookiePass: '',
loginForm: { loginForm: {
username: '', username: 'admin',
password: '', password: '123456',
rememberMe: false, rememberMe: false,
code: '', code: '',
uuid: '' uuid: ''
@ -99,9 +125,16 @@ export default {
this.getCookie() this.getCookie()
// token // token
this.point() this.point()
this.getDevice() this.getDevice()
}, },
methods: { methods: {
handleCommand(command) {
if (command === 'en') {
this.$message('click on item ' + command)
this.$router.push('/login_en')
}
},
getCode() { getCode() {
getCodeImg().then(res => { getCodeImg().then(res => {
this.codeUrl = res.img this.codeUrl = res.img
@ -128,6 +161,7 @@ export default {
} }
}, },
handleLogin() { handleLogin() {
this.$i18n.locale = 'zh'
this.$refs.loginForm.validate(valid => { this.$refs.loginForm.validate(valid => {
const user = { const user = {
username: this.loginForm.username, username: this.loginForm.username,
@ -136,12 +170,14 @@ export default {
code: this.loginForm.code, code: this.loginForm.code,
uuid: this.loginForm.uuid uuid: this.loginForm.uuid
} }
if (user.password !== this.cookiePass) {
user.password = encrypt(user.password) user.password = encrypt(user.password)
}
if (valid) { if (valid) {
this.loading = true this.loading = true
if (user.rememberMe) { if (user.rememberMe) {
Cookies.set('username', user.username, { expires: Config.passCookieExpires }) Cookies.set('username', user.username, { expires: Config.passCookieExpires })
Cookies.set('password', this.loginForm.password, { expires: Config.passCookieExpires }) Cookies.set('password', user.password, { expires: Config.passCookieExpires })
Cookies.set('rememberMe', user.rememberMe, { expires: Config.passCookieExpires }) Cookies.set('rememberMe', user.rememberMe, { expires: Config.passCookieExpires })
} else { } else {
Cookies.remove('username') Cookies.remove('username')
@ -151,8 +187,7 @@ export default {
this.$store.dispatch('Login', user).then(() => { this.$store.dispatch('Login', user).then(() => {
this.loading = false this.loading = false
this.$router.push({ path: this.redirect || '/' }) this.$router.push({ path: this.redirect || '/' })
// eslint-disable-next-line handle-callback-err }).catch(() => {
}).catch(err => {
this.loading = false this.loading = false
this.getCode() this.getCode()
}) })
@ -176,38 +211,63 @@ export default {
}, },
bingLicense() { bingLicense() {
this.click_count = this.click_count + 1 this.click_count = this.click_count + 1
if (this.click_count % 10 === 0) { if (this.click_count % 3 === 0) {
this.$refs.BindLicense.dialogVisible = true this.$refs.BindLicense.dialogVisible = true
} }
} }
} }
} }
</script> </script>
<style rel="stylesheet/scss" lang="scss"> <style rel="stylesheet/scss" lang="scss">
.login { .main_div {
background: #f7f7f7;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
width: 100%;
background-size: cover;
}
.main_left {
background: #fffffff5;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
background-size: cover;
}
.login {
background: #00000045;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
background-size: cover; background-size: cover;
} }
.title { .title {
margin: 0 auto 30px auto; margin: 30px auto 30px 0px;
text-align: left;
color: #707070;
}
.zhuce {
margin: 30px auto 30px 0px;
text-align: center; text-align: center;
color: #707070; color: #707070;
} }
.login-form { .login-form {
border-radius: 6px; border-radius: 6px;
background: #ffffff; background: #fffffff0;
width: 385px; width: 520px;
padding: 25px 25px 5px 25px; height: 620px;
padding: 40px 80px 40px 80px;
.el-input { .el-input {
height: 38px; height: 40px;
input { input {
height: 38px; height: 40px;
} }
} }
.input-icon{ .input-icon{