liweilong
2020-12-25 57fedb8aa042c9f8bf5a3214b455144436850f1f
提交 | 用户 | age
2a61f6 1 <template>
L 2   <div class="login-container">
3     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
4
5       <div class="title-container">
9f32bd 6         <h3 class="title">袁曦藏酒</h3>
2a61f6 7       </div>
L 8
9       <el-form-item prop="username">
10         <span class="svg-container">
11           <svg-icon icon-class="user" />
12         </span>
13         <el-input
14           ref="username"
15           v-model="loginForm.username"
16           placeholder="请输入账号"
17           name="username"
18           type="text"
19           tabindex="1"
20           autocomplete="on"
21           @keyup.enter.native="handleLogin"
22         />
23       </el-form-item>
24
25       <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
26         <el-form-item prop="password">
27           <span class="svg-container">
28             <svg-icon icon-class="password" />
29           </span>
30           <el-input
31             :key="passwordType"
32             ref="password"
33             v-model="loginForm.password"
34             :type="passwordType"
35             placeholder="请输入密码"
36             name="password"
37             tabindex="2"
38             autocomplete="on"
39             @keyup.native="checkCapslock"
40             @blur="capsTooltip = false"
41             @keyup.enter.native="handleLogin"
42           />
43           <span class="show-pwd" @click="showPwd">
44             <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
45           </span>
46         </el-form-item>
47       </el-tooltip>
48
49       <el-form-item prop="safecode">
50         <span class="svg-container">
51           <svg-icon icon-class="safecode" />
52         </span>
53         <el-input
54           ref="safecode"
55           v-model="loginForm.safecode"
56           style="width: 60%"
57           placeholder="请输入验证码"
58           name="safecode"
59           type="text"
60           tabindex="3"
61           autocomplete="off"
62           @keyup.enter.native="handleLogin"
63         />
64         <el-image
65           class="safecode-img"
66           :src="safecodeImg"
67           fit="fill"
68           @click="getSafeCodeImg"
69         >
70           <div slot="error" class="image-slot">
71             <i class="el-icon-picture-outline" />
72           </div>
73         </el-image>
74       </el-form-item>
75
76       <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button>
77     </el-form>
78   </div>
79 </template>
80
81 <script>
82 import { setToken, setUserData } from '@/utils/auth' // get token from session
83
84 export default {
85   name: 'Login',
86   components: {},
87   data() {
88     const validateUsername = (rule, value, callback) => {
89       if (!value) {
90         callback(new Error('请输入账号'))
91       } else {
92         callback()
93       }
94     }
95     const validatePassword = (rule, value, callback) => {
96       if (value.length < 5) {
97         callback(new Error('账号不能少于5位'))
98       } else {
99         callback()
100       }
101     }
102     const validateSafecode = (rule, value, callback) => {
103       if (!value) {
104         callback(new Error('请输入验证码'))
105       } else {
106         callback()
107       }
108     }
109     return {
110       loginForm: {
111         username: '',
112         password: '',
113         safecode: '',
114         checkedId: ''
115       },
116       loginRules: {
117         username: [{ required: true, trigger: 'change', validator: validateUsername }],
118         password: [{ required: true, trigger: 'change', validator: validatePassword }],
119         safecode: [{ required: true, trigger: 'change', validator: validateSafecode }]
120       },
121       passwordType: 'password',
122       capsTooltip: false,
123       loading: false,
124       showDialog: false,
125       redirect: undefined,
126       otherQuery: {},
127       safecodeImg: ''
128     }
129   },
130   watch: {
131     $route: {
132       handler: function(route) {
133         const query = route.query
134         if (query) {
135           this.redirect = query.redirect
136           this.otherQuery = this.getOtherQuery(query)
137         }
138       },
139       immediate: true
140     }
141   },
142   mounted() {
143     this.init()
144   },
145   methods: {
146     init() {
147       var loginData = localStorage.getItem('loginData')
148       // 获取保存的账号密码
149       if (loginData) this.loginForm = JSON.parse(loginData)
150
151       if (this.loginForm.username === '') {
152         this.$refs.username.focus()
153       } else if (this.loginForm.password === '') {
154         this.$refs.password.focus()
155       } else if (this.loginForm.safecode === '') {
156         this.$refs.safecode.focus()
157       }
158
159       this.getSafeCodeImg()
160     },
161     checkCapslock(e) {
162       const { key } = e
163       this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
164     },
165     showPwd() {
166       if (this.passwordType === 'password') {
167         this.passwordType = ''
168       } else {
169         this.passwordType = 'password'
170       }
171       this.$nextTick(() => {
172         this.$refs.password.focus()
173       })
174     },
175     // 获取验证码图
176     getSafeCodeImg() {
177       var checkedId = this.getCheckedId()
178       this.postFN({
179         url: `admin/create/cheked`,
180         params: { checkedId: checkedId },
181         udData: { noToken: true },
182         mockData: {
183           code: 100,
184           msg: '',
185           data: {
186             imgStr: 'xxxx'
187           }
188         }
189       }, (inf) => {
190         this.safecodeImg = this.perfectSafeCode(inf.imgStr)
191         this.loginForm.checkedId = checkedId
192       })
193     },
194     // 补全验证码
195     perfectSafeCode(img) {
196       if (!img) return
197       return `data:image/jpeg;base64,${img}`
198     },
199     // 登录
200     handleLogin() {
201       this.$refs.loginForm.validate(valid => {
202         if (valid) {
203           const { username, password, safecode, checkedId } = this.loginForm
204           const params = {
205             account: username.trim(),
206             password: password.trim(),
207             checkedId: checkedId,
208             checkedCode: safecode.trim()
209           }
210           this.loading = true
211           this.postFN({
212             url: 'admin/login',
213             params: params,
214             udData: { noToken: true },
215             mockData: {
216               code: 100,
217               msg: '',
218               data: {
219                 adminToken: 'mockdAmintoken', // 登录凭证
220                 name: '潘多拉的臭嘴', // 用户名称
221                 // arr: ['sys_admin_see'], // 权限列表
222                 arr: ['sys_admin_see', 'sys_admin_add', 'sys_admin_edit', 'sys_admin_del', 'sys_admin_role_see', 'sys_admin_role_add', 'sys_admin_role_edit', 'sys_admin_role_del', 'corp_user_schedule_see', 'corp_user_schedule_add', 'corp_user_schedule_edit', 'corp_user_schedule_del', 'user_mp_banner_see', 'user_mp_banner_add', 'user_mp_banner_edit', 'user_mp_banner_del', 'shop_see', 'shop_add', 'shop_edit', 'shop_del', 'shop_device', 'corp_user_see', 'corp_user_add', 'corp_user_edit', 'corp_user_del', 'change_assistant_see', 'ser_pro_material_see', 'service_project_see', 'service_project_add', 'service_project_edit', 'service_project_del', 'service_topic_see', 'service_topic_add', 'service_topic_edit', 'service_topic_del', 'service_project_order_see', 'service_project_order_edit', 'goods_type_see', 'goods_type_add', 'goods_type_edit', 'goods_type_del', 'goods_see', 'goods_add', 'goods_edit', 'goods_del', 'goods_inventory', 'goods_order_see', 'goods_order_edit', 'goods_index_banner_see', 'goods_index_banner_add', 'goods_index_banner_edit', 'goods_index_banner_del', 'user_see', 'user_edit', 'user_cash_see', 'user_cash_edit', 'distribute_relate', 'distribute_order', 'document_edit', 'operation_see',
9f32bd 223                   'coupon_see', 'coupon_add', 'coupon_edit', 'coupon_del', 'activity_see', 'activity_add', 'activity_edit', 'activity_del', 'banner_see', 'banner_add', 'banner_edit', 'banner_del'
2a61f6 224                 ]
L 225               }
226             }
227           }, (inf) => {
228             // 保存登录凭证
229             setToken(inf.adminToken)
230
231             // 保存账号密码
232             var loginData = JSON.stringify({
233               username: this.loginForm.username.trim(),
234               password: this.loginForm.password.trim()
235             })
236             localStorage.setItem('loginData', loginData)
237
238             // 保存用户数据
239             setUserData(inf)
240
241             this.loading = false
242
243             // 登录成功跳转页面
244             this.$messageSuc('登录成功')
245             setTimeout(() => {
246               this.$router.push({ path: this.redirect || '/activity/index', query: this.otherQuery })
247             }, 1000)
248           }, (res) => {
249             this.loading = false
250             this.$messageError(res.msg)
251           })
252         } else {
253           console.log('表单验证失败')
254           return false
255         }
256       })
257     },
258     getOtherQuery(query) {
259       return Object.keys(query).reduce((acc, cur) => {
260         if (cur !== 'redirect') {
261           acc[cur] = query[cur]
262         }
263         return acc
264       }, {})
265     }
266   }
267 }
268 </script>
269
270 <style lang="scss">
271 /* 修复input 背景不协调 和光标变色 */
272 /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
273
274 $bg:#283443;
275 $light_gray:#fff;
276 $cursor: #fff;
277
278 @supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
279   .login-container .el-input input {
280     color: $cursor;
281   }
282 }
283
284 /* reset element-ui css */
285 .login-container {
286   .el-input {
287     display: inline-block;
288     height: 47px;
289     width: 85%;
290
291     input {
292       background: transparent;
293       border: 0px;
294       -webkit-appearance: none;
295       border-radius: 0px;
296       padding: 12px 5px 12px 15px;
297       color: $light_gray;
298       height: 47px;
299       caret-color: $cursor;
300
301       &:-webkit-autofill {
302         box-shadow: 0 0 0px 1000px $bg inset !important;
303         -webkit-text-fill-color: $cursor !important;
304       }
305     }
306
307   }
308
309   .el-form-item {
310     border: 1px solid rgba(255, 255, 255, 0.1);
311     background: rgba(0, 0, 0, 0.1);
312     border-radius: 5px;
313     color: #454545;
314   }
315 }
316 </style>
317
318 <style lang="scss" scoped>
319 $bg:#2d3a4b;
320 $dark_gray:#889aa4;
321 $light_gray:#eee;
322
323 .login-container {
324   min-height: 100%;
325   width: 100%;
326   background-color: $bg;
327   overflow: hidden;
328
329   .login-form {
330     position: relative;
331     width: 520px;
332     max-width: 100%;
333     padding: 160px 35px 0;
334     margin: 0 auto;
335     overflow: hidden;
336   }
337
338   .tips {
339     font-size: 14px;
340     color: #fff;
341     margin-bottom: 10px;
342
343     span {
344       &:first-of-type {
345         margin-right: 16px;
346       }
347     }
348   }
349
350   .svg-container {
351     padding: 6px 5px 6px 15px;
352     color: $dark_gray;
353     vertical-align: middle;
354     width: 30px;
355     display: inline-block;
356   }
357
358   .title-container {
359     position: relative;
360
361     .title {
362       font-size: 26px;
363       color: $light_gray;
364       margin: 0px auto 40px auto;
365       text-align: center;
366       font-weight: bold;
367     }
368   }
369
370   .show-pwd {
371     position: absolute;
372     right: 10px;
373     top: 7px;
374     font-size: 16px;
375     color: $dark_gray;
376     cursor: pointer;
377     user-select: none;
378   }
379
380   .safecode-img{
381     width: 100px;
382     height: 80%;
383     position: absolute;
384     right: 10px;
385     top: 50%;
386     transform: translateY(-50%);
387     font-size: 30px;
388     text-align: right;
389     color: #999;
390     cursor: pointer;
391   }
392
393   .thirdparty-button {
394     position: absolute;
395     right: 0;
396     bottom: 6px;
397   }
398
399   @media only screen and (max-width: 470px) {
400     .thirdparty-button {
401       display: none;
402     }
403   }
404 }
405 </style>