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