liweilong
2020-12-02 037956b0794e6b47ef6b6daf308844522c448e96
提交 | 用户 | 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">
6         <h3 class="title">”项目名称“</h3>
7       </div>
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       console.log(loginData)
149       // 获取保存的账号密码
150       if (loginData) this.loginForm = JSON.parse(loginData)
151
152       if (this.loginForm.username === '') {
153         this.$refs.username.focus()
154       } else if (this.loginForm.password === '') {
155         this.$refs.password.focus()
156       } else if (this.loginForm.safecode === '') {
157         this.$refs.safecode.focus()
158       }
159
160       this.getSafeCodeImg()
161     },
162     checkCapslock(e) {
163       const { key } = e
164       this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
165     },
166     showPwd() {
167       if (this.passwordType === 'password') {
168         this.passwordType = ''
169       } else {
170         this.passwordType = 'password'
171       }
172       this.$nextTick(() => {
173         this.$refs.password.focus()
174       })
175     },
176     // 获取验证码图
177     getSafeCodeImg() {
178       var checkedId = this.getCheckedId()
179       this.postFN({
180         url: `admin/create/cheked`,
181         params: { checkedId: checkedId },
182         udData: { noToken: true },
183         mockData: {
184           code: 100,
185           msg: '',
186           data: {
187             imgStr: 'xxxx'
188           }
189         }
190       }, (inf) => {
191         this.safecodeImg = this.perfectSafeCode(inf.imgStr)
192         this.loginForm.checkedId = checkedId
193       })
194     },
195     // 补全验证码
196     perfectSafeCode(img) {
197       if (!img) return
198       return `data:image/jpeg;base64,${img}`
199     },
200     // 登录
201     handleLogin() {
202       this.$refs.loginForm.validate(valid => {
203         if (valid) {
204           const { username, password, safecode, checkedId } = this.loginForm
205           const params = {
206             account: username.trim(),
207             password: password.trim(),
208             checkedId: checkedId,
209             checkedCode: safecode.trim()
210           }
211           this.loading = true
212           this.postFN({
213             url: 'admin/login',
214             params: params,
215             udData: { noToken: true },
216             mockData: {
217               code: 100,
218               msg: '',
219               data: {
220                 adminToken: 'mockdAmintoken', // 登录凭证
221                 name: '潘多拉的臭嘴', // 用户名称
222                 // arr: ['sys_admin_see'], // 权限列表
223                 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',
224                   'coupon_see', 'coupon_add', 'coupon_edit', 'coupon_del', 'activity_see', 'activity_add', 'activity_edit', 'activity_del'
225                 ]
226               }
227             }
228           }, (inf) => {
229             // 保存登录凭证
230             setToken(inf.adminToken)
231
232             // 保存账号密码
233             var loginData = JSON.stringify({
234               username: this.loginForm.username.trim(),
235               password: this.loginForm.password.trim()
236             })
237             localStorage.setItem('loginData', loginData)
238
239             // 保存用户数据
240             setUserData(inf)
241
242             this.loading = false
243
244             // 登录成功跳转页面
245             this.$messageSuc('登录成功')
246             setTimeout(() => {
247               this.$router.push({ path: this.redirect || '/activity/index', query: this.otherQuery })
248             }, 1000)
249           }, (res) => {
250             this.loading = false
251             this.$messageError(res.msg)
252           })
253         } else {
254           console.log('表单验证失败')
255           return false
256         }
257       })
258     },
259     getOtherQuery(query) {
260       return Object.keys(query).reduce((acc, cur) => {
261         if (cur !== 'redirect') {
262           acc[cur] = query[cur]
263         }
264         return acc
265       }, {})
266     }
267   }
268 }
269 </script>
270
271 <style lang="scss">
272 /* 修复input 背景不协调 和光标变色 */
273 /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
274
275 $bg:#283443;
276 $light_gray:#fff;
277 $cursor: #fff;
278
279 @supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
280   .login-container .el-input input {
281     color: $cursor;
282   }
283 }
284
285 /* reset element-ui css */
286 .login-container {
287   .el-input {
288     display: inline-block;
289     height: 47px;
290     width: 85%;
291
292     input {
293       background: transparent;
294       border: 0px;
295       -webkit-appearance: none;
296       border-radius: 0px;
297       padding: 12px 5px 12px 15px;
298       color: $light_gray;
299       height: 47px;
300       caret-color: $cursor;
301
302       &:-webkit-autofill {
303         box-shadow: 0 0 0px 1000px $bg inset !important;
304         -webkit-text-fill-color: $cursor !important;
305       }
306     }
307
308   }
309
310   .el-form-item {
311     border: 1px solid rgba(255, 255, 255, 0.1);
312     background: rgba(0, 0, 0, 0.1);
313     border-radius: 5px;
314     color: #454545;
315   }
316 }
317 </style>
318
319 <style lang="scss" scoped>
320 $bg:#2d3a4b;
321 $dark_gray:#889aa4;
322 $light_gray:#eee;
323
324 .login-container {
325   min-height: 100%;
326   width: 100%;
327   background-color: $bg;
328   overflow: hidden;
329
330   .login-form {
331     position: relative;
332     width: 520px;
333     max-width: 100%;
334     padding: 160px 35px 0;
335     margin: 0 auto;
336     overflow: hidden;
337   }
338
339   .tips {
340     font-size: 14px;
341     color: #fff;
342     margin-bottom: 10px;
343
344     span {
345       &:first-of-type {
346         margin-right: 16px;
347       }
348     }
349   }
350
351   .svg-container {
352     padding: 6px 5px 6px 15px;
353     color: $dark_gray;
354     vertical-align: middle;
355     width: 30px;
356     display: inline-block;
357   }
358
359   .title-container {
360     position: relative;
361
362     .title {
363       font-size: 26px;
364       color: $light_gray;
365       margin: 0px auto 40px auto;
366       text-align: center;
367       font-weight: bold;
368     }
369   }
370
371   .show-pwd {
372     position: absolute;
373     right: 10px;
374     top: 7px;
375     font-size: 16px;
376     color: $dark_gray;
377     cursor: pointer;
378     user-select: none;
379   }
380
381   .safecode-img{
382     width: 100px;
383     height: 80%;
384     position: absolute;
385     right: 10px;
386     top: 50%;
387     transform: translateY(-50%);
388     font-size: 30px;
389     text-align: right;
390     color: #999;
391     cursor: pointer;
392   }
393
394   .thirdparty-button {
395     position: absolute;
396     right: 0;
397     bottom: 6px;
398   }
399
400   @media only screen and (max-width: 470px) {
401     .thirdparty-button {
402       display: none;
403     }
404   }
405 }
406 </style>