Browse Source

初始化

黎海 1 month ago
parent
commit
31aafd2795

+ 1 - 0
package.json

@@ -22,6 +22,7 @@
22
     "nprogress": "0.2.0",
22
     "nprogress": "0.2.0",
23
     "path-to-regexp": "2.4.0",
23
     "path-to-regexp": "2.4.0",
24
     "vue": "2.6.10",
24
     "vue": "2.6.10",
25
+    "vue-i18n": "^8.28.2",
25
     "vue-router": "3.0.6",
26
     "vue-router": "3.0.6",
26
     "vuex": "3.1.0"
27
     "vuex": "3.1.0"
27
   },
28
   },

+ 9 - 1
src/api/user.js

@@ -2,7 +2,15 @@ import request from '@/utils/request'
2
 
2
 
3
 export function login(data) {
3
 export function login(data) {
4
   return request({
4
   return request({
5
-    url: '/vue-admin-template/user/login',
5
+    url: '/login',
6
+    method: 'post',
7
+    data
8
+  })
9
+}
10
+
11
+export function register(data) {
12
+  return request({
13
+    url: '/register',
6
     method: 'post',
14
     method: 'post',
7
     data
15
     data
8
   })
16
   })

+ 21 - 0
src/i18n/index.js

@@ -0,0 +1,21 @@
1
+// src/i18n/index.js
2
+import Vue from 'vue'
3
+import VueI18n from 'vue-i18n'
4
+
5
+// 导入语言包
6
+import en from './locales/en.json'
7
+import zh from './locales/zh.json'
8
+
9
+Vue.use(VueI18n)
10
+
11
+const messages = {
12
+  en,
13
+  zh
14
+}
15
+
16
+const i18n = new VueI18n({
17
+  locale: 'zh', // 设置默认语言
18
+  messages
19
+})
20
+
21
+export default i18n

+ 4 - 0
src/i18n/locales/en.json

@@ -0,0 +1,4 @@
1
+{
2
+  "mine": "home",
3
+  "logout": "Logout"
4
+}

+ 8 - 0
src/i18n/locales/zh.json

@@ -0,0 +1,8 @@
1
+{
2
+  "mine": "首页",
3
+  "logout": "退出",
4
+  "login": "登录",
5
+  "switchToRegister": "切换到注册",
6
+  "switchToLogin": "切换到登录",
7
+  "register": "注册"
8
+}

+ 12 - 9
src/layout/components/Navbar.vue

@@ -13,17 +13,14 @@
13
         <el-dropdown-menu slot="dropdown" class="user-dropdown">
13
         <el-dropdown-menu slot="dropdown" class="user-dropdown">
14
           <router-link to="/">
14
           <router-link to="/">
15
             <el-dropdown-item>
15
             <el-dropdown-item>
16
-              Home
16
+              {{ $t('mine') }}
17
             </el-dropdown-item>
17
             </el-dropdown-item>
18
           </router-link>
18
           </router-link>
19
-          <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/">
20
-            <el-dropdown-item>Github</el-dropdown-item>
21
-          </a>
22
-          <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
23
-            <el-dropdown-item>Docs</el-dropdown-item>
24
-          </a>
19
+          <el-dropdown-item @click.native="toggleLanguage">
20
+            <span style="display:block;">{{ currentLanguage === 'zh' ? 'Switch to English' : '切换到中文' }}</span>
21
+          </el-dropdown-item>
25
           <el-dropdown-item divided @click.native="logout">
22
           <el-dropdown-item divided @click.native="logout">
26
-            <span style="display:block;">Log Out</span>
23
+            <span style="display:block;">{{ $t('logout') }}</span>
27
           </el-dropdown-item>
24
           </el-dropdown-item>
28
         </el-dropdown-menu>
25
         </el-dropdown-menu>
29
       </el-dropdown>
26
       </el-dropdown>
@@ -45,7 +42,10 @@ export default {
45
     ...mapGetters([
42
     ...mapGetters([
46
       'sidebar',
43
       'sidebar',
47
       'avatar'
44
       'avatar'
48
-    ])
45
+    ]),
46
+    currentLanguage() {
47
+      return this.$i18n.locale
48
+    }
49
   },
49
   },
50
   methods: {
50
   methods: {
51
     toggleSideBar() {
51
     toggleSideBar() {
@@ -54,6 +54,9 @@ export default {
54
     async logout() {
54
     async logout() {
55
       await this.$store.dispatch('user/logout')
55
       await this.$store.dispatch('user/logout')
56
       this.$router.push(`/login?redirect=${this.$route.fullPath}`)
56
       this.$router.push(`/login?redirect=${this.$route.fullPath}`)
57
+    },
58
+    toggleLanguage() {
59
+      this.$i18n.locale = this.currentLanguage === 'zh' ? 'en' : 'zh'
57
     }
60
     }
58
   }
61
   }
59
 }
62
 }

+ 2 - 1
src/main.js

@@ -11,7 +11,7 @@ import '@/styles/index.scss' // global css
11
 import App from './App'
11
 import App from './App'
12
 import store from './store'
12
 import store from './store'
13
 import router from './router'
13
 import router from './router'
14
-
14
+import i18n from '@/i18n'
15
 import '@/icons' // icon
15
 import '@/icons' // icon
16
 import '@/permission' // permission control
16
 import '@/permission' // permission control
17
 
17
 
@@ -39,5 +39,6 @@ new Vue({
39
   el: '#app',
39
   el: '#app',
40
   router,
40
   router,
41
   store,
41
   store,
42
+  i18n,
42
   render: h => h(App)
43
   render: h => h(App)
43
 })
44
 })

+ 0 - 24
src/router/index.js

@@ -6,30 +6,6 @@ Vue.use(Router)
6
 /* Layout */
6
 /* Layout */
7
 import Layout from '@/layout'
7
 import Layout from '@/layout'
8
 
8
 
9
-/**
10
- * Note: sub-menu only appear when route children.length >= 1
11
- * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
12
- *
13
- * hidden: true                   if set true, item will not show in the sidebar(default is false)
14
- * alwaysShow: true               if set true, will always show the root menu
15
- *                                if not set alwaysShow, when item has more than one children route,
16
- *                                it will becomes nested mode, otherwise not show the root menu
17
- * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb
18
- * name:'router-name'             the name is used by <keep-alive> (must set!!!)
19
- * meta : {
20
-    roles: ['admin','editor']    control the page roles (you can set multiple roles)
21
-    title: 'title'               the name show in sidebar and breadcrumb (recommend set)
22
-    icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
23
-    breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
24
-    activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
25
-  }
26
- */
27
-
28
-/**
29
- * constantRoutes
30
- * a base page that does not have permission requirements
31
- * all roles can be accessed
32
- */
33
 export const constantRoutes = [
9
 export const constantRoutes = [
34
   {
10
   {
35
     path: '/login',
11
     path: '/login',

+ 2 - 1
src/utils/request.js

@@ -5,7 +5,8 @@ import { getToken } from '@/utils/auth'
5
 
5
 
6
 // create an axios instance
6
 // create an axios instance
7
 const service = axios.create({
7
 const service = axios.create({
8
-  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
8
+  baseURL: 'http://192.168.1.9:8000/docs', // url = base url + request url
9
+  // baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
9
   // withCredentials: true, // send cookies when cross-domain requests
10
   // withCredentials: true, // send cookies when cross-domain requests
10
   timeout: 5000 // request timeout
11
   timeout: 5000 // request timeout
11
 })
12
 })

+ 53 - 18
src/views/login/index.vue

@@ -3,9 +3,23 @@
3
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
3
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
4
 
4
 
5
       <div class="title-container">
5
       <div class="title-container">
6
-        <h3 class="title">Login Form</h3>
6
+        <h3 class="title">{{ isLogin ? $t('login') : $t('register') }}</h3>
7
       </div>
7
       </div>
8
 
8
 
9
+      <el-form-item v-if="!isLogin" prop="email">
10
+        <span class="svg-container">
11
+          <svg-icon icon-class="email" />
12
+        </span>
13
+        <el-input
14
+          v-model="loginForm.email"
15
+          placeholder="Email"
16
+          name="email"
17
+          type="email"
18
+          tabindex="1"
19
+          auto-complete="on"
20
+        />
21
+      </el-form-item>
22
+
9
       <el-form-item prop="username">
23
       <el-form-item prop="username">
10
         <span class="svg-container">
24
         <span class="svg-container">
11
           <svg-icon icon-class="user" />
25
           <svg-icon icon-class="user" />
@@ -16,7 +30,7 @@
16
           placeholder="Username"
30
           placeholder="Username"
17
           name="username"
31
           name="username"
18
           type="text"
32
           type="text"
19
-          tabindex="1"
33
+          tabindex="2"
20
           auto-complete="on"
34
           auto-complete="on"
21
         />
35
         />
22
       </el-form-item>
36
       </el-form-item>
@@ -32,20 +46,21 @@
32
           :type="passwordType"
46
           :type="passwordType"
33
           placeholder="Password"
47
           placeholder="Password"
34
           name="password"
48
           name="password"
35
-          tabindex="2"
49
+          tabindex="3"
36
           auto-complete="on"
50
           auto-complete="on"
37
-          @keyup.enter.native="handleLogin"
51
+          @keyup.enter.native="handleSubmit"
38
         />
52
         />
39
         <span class="show-pwd" @click="showPwd">
53
         <span class="show-pwd" @click="showPwd">
40
           <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
54
           <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
41
         </span>
55
         </span>
42
       </el-form-item>
56
       </el-form-item>
43
 
57
 
44
-      <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
58
+      <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleSubmit">
59
+        {{ isLogin ? $t('login') : $t('register') }}
60
+      </el-button>
45
 
61
 
46
-      <div class="tips">
47
-        <span style="margin-right:20px;">username: admin</span>
48
-        <span> password: any</span>
62
+      <div class="switch-mode" @click="toggleMode">
63
+        {{ isLogin ? $t('switchToRegister') : $t('switchToLogin') }}
49
       </div>
64
       </div>
50
 
65
 
51
     </el-form>
66
     </el-form>
@@ -72,12 +87,23 @@ export default {
72
         callback()
87
         callback()
73
       }
88
       }
74
     }
89
     }
90
+    const validateEmail = (rule, value, callback) => {
91
+      const emailPattern = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/
92
+      if (!emailPattern.test(value)) {
93
+        callback(new Error('Please enter a valid email address'))
94
+      } else {
95
+        callback()
96
+      }
97
+    }
75
     return {
98
     return {
99
+      isLogin: true,
76
       loginForm: {
100
       loginForm: {
101
+        email: '',
77
         username: 'admin',
102
         username: 'admin',
78
         password: '111111'
103
         password: '111111'
79
       },
104
       },
80
       loginRules: {
105
       loginRules: {
106
+        email: [{ required: true, trigger: 'blur', validator: validateEmail }],
81
         username: [{ required: true, trigger: 'blur', validator: validateUsername }],
107
         username: [{ required: true, trigger: 'blur', validator: validateUsername }],
82
         password: [{ required: true, trigger: 'blur', validator: validatePassword }]
108
         password: [{ required: true, trigger: 'blur', validator: validatePassword }]
83
       },
109
       },
@@ -86,15 +112,10 @@ export default {
86
       redirect: undefined
112
       redirect: undefined
87
     }
113
     }
88
   },
114
   },
89
-  watch: {
90
-    $route: {
91
-      handler: function(route) {
92
-        this.redirect = route.query && route.query.redirect
93
-      },
94
-      immediate: true
95
-    }
96
-  },
97
   methods: {
115
   methods: {
116
+    toggleMode() {
117
+      this.isLogin = !this.isLogin
118
+    },
98
     showPwd() {
119
     showPwd() {
99
       if (this.passwordType === 'password') {
120
       if (this.passwordType === 'password') {
100
         this.passwordType = ''
121
         this.passwordType = ''
@@ -105,11 +126,15 @@ export default {
105
         this.$refs.password.focus()
126
         this.$refs.password.focus()
106
       })
127
       })
107
     },
128
     },
108
-    handleLogin() {
129
+    handleSubmit() {
109
       this.$refs.loginForm.validate(valid => {
130
       this.$refs.loginForm.validate(valid => {
110
         if (valid) {
131
         if (valid) {
111
           this.loading = true
132
           this.loading = true
112
-          this.$store.dispatch('user/login', this.loginForm).then(() => {
133
+          const action = this.isLogin ? 'user/login' : 'user/register'
134
+          this.$store.dispatch(action, this.loginForm).then(() => {
135
+            if (!this.isLogin) {
136
+              this.toggleMode()
137
+            }
113
             this.$router.push({ path: this.redirect || '/' })
138
             this.$router.push({ path: this.redirect || '/' })
114
             this.loading = false
139
             this.loading = false
115
           }).catch(() => {
140
           }).catch(() => {
@@ -176,6 +201,7 @@ $cursor: #fff;
176
 $bg:#2d3a4b;
201
 $bg:#2d3a4b;
177
 $dark_gray:#889aa4;
202
 $dark_gray:#889aa4;
178
 $light_gray:#eee;
203
 $light_gray:#eee;
204
+$green: #00ff00;
179
 
205
 
180
 .login-container {
206
 .login-container {
181
   min-height: 100%;
207
   min-height: 100%;
@@ -233,5 +259,14 @@ $light_gray:#eee;
233
     cursor: pointer;
259
     cursor: pointer;
234
     user-select: none;
260
     user-select: none;
235
   }
261
   }
262
+
263
+  .switch-mode {
264
+    text-decoration: underline;
265
+    color: $green;
266
+    cursor: pointer;
267
+    user-select: none;
268
+    text-align: center;
269
+    margin-top: 20px;
270
+  }
236
 }
271
 }
237
 </style>
272
 </style>