Login.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <template>
  2. <div class="main">
  3. <a-form class="user-layout-login" ref="formLogin" :autoFormCreate="(form)=>{this.form = form}" id="formLogin">
  4. <a-tabs
  5. :activeKey="customActiveKey"
  6. :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
  7. @change="handleTabClick">
  8. <a-tab-pane key="tab1" tab="账号密码登陆">
  9. <a-form-item
  10. fieldDecoratorId="username"
  11. :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入帐户名或邮箱地址' }, { validator: this.handleUsernameOrEmail }], validateTrigger: 'change'}"
  12. >
  13. <a-input size="large" type="text" placeholder="帐户名或邮箱地址 / admin">
  14. <a-icon slot="prefix" type='user' :style="{ color: 'rgba(0,0,0,.25)' }"/>
  15. </a-input>
  16. </a-form-item>
  17. <a-form-item
  18. fieldDecoratorId="password"
  19. :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur'}">
  20. <a-input size="large" type="password" placeholder="密码 / admin">
  21. <a-icon slot="prefix" type='lock' :style="{ color: 'rgba(0,0,0,.25)' }"/>
  22. </a-input>
  23. </a-form-item>
  24. </a-tab-pane>
  25. <a-tab-pane key="tab2" tab="手机号登陆">
  26. <a-form-item
  27. fieldDecoratorId="mobile"
  28. :fieldDecoratorOptions="{rules: [{ required: true, pattern: /^1[34578]\d{9}$/, message: '请输入正确的手机号' }], validateTrigger: 'change'}">
  29. <a-input size="large" type="text" placeholder="手机号">
  30. <a-icon slot="prefix" type='mobile' :style="{ color: 'rgba(0,0,0,.25)' }"/>
  31. </a-input>
  32. </a-form-item>
  33. <a-row :gutter="16">
  34. <a-col class="gutter-row" :span="16">
  35. <a-form-item
  36. fieldDecoratorId="captcha"
  37. :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入验证码' }], validateTrigger: 'blur'}">
  38. <a-input size="large" type="text" placeholder="验证码">
  39. <a-icon slot="prefix" type='mail' :style="{ color: 'rgba(0,0,0,.25)' }"/>
  40. </a-input>
  41. </a-form-item>
  42. </a-col>
  43. <a-col class="gutter-row" :span="8">
  44. <a-button
  45. class="getCaptcha"
  46. :disabled="state.smsSendBtn"
  47. @click.stop.prevent="getCaptcha"
  48. v-text="!state.smsSendBtn && '获取验证码' || (state.time+' s')"></a-button>
  49. </a-col>
  50. </a-row>
  51. </a-tab-pane>
  52. </a-tabs>
  53. <a-form-item>
  54. <a-checkbox v-model="formLogin.rememberMe">自动登陆</a-checkbox>
  55. <router-link :to="{ name: 'recover', params: { user: 'aaa'} }" class="forge-password" style="float: right;">
  56. 忘记密码
  57. </router-link>
  58. </a-form-item>
  59. <a-form-item style="margin-top:24px">
  60. <a-button
  61. size="large"
  62. type="primary"
  63. htmlType="submit"
  64. class="login-button"
  65. :loading="loginBtn"
  66. @click.stop.prevent="handleSubmit"
  67. :disabled="loginBtn">确定
  68. </a-button>
  69. </a-form-item>
  70. <div class="user-login-other">
  71. <span>其他登陆方式</span>
  72. <a><a-icon class="item-icon" type="alipay-circle"></a-icon></a>
  73. <a><a-icon class="item-icon" type="taobao-circle"></a-icon></a>
  74. <a><a-icon class="item-icon" type="weibo-circle"></a-icon></a>
  75. <router-link class="register" :to="{ name: 'register' }">
  76. 注册账户
  77. </router-link>
  78. </div>
  79. </a-form>
  80. <two-step-captcha v-if="requiredTwoStepCaptcha" :visible="stepCaptchaVisible" @success="stepCaptchaSuccess"></two-step-captcha>
  81. </div>
  82. </template>
  83. <script>
  84. import md5 from "md5"
  85. import api from '@/api'
  86. import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
  87. import { mapActions } from "vuex"
  88. import { timeFix } from "@/utils/util"
  89. export default {
  90. components: {
  91. TwoStepCaptcha
  92. },
  93. data () {
  94. return {
  95. customActiveKey: "tab1",
  96. loginBtn: false,
  97. // login type: 0 email, 1 username, 2 telephone
  98. loginType: 0,
  99. requiredTwoStepCaptcha: true,
  100. stepCaptchaVisible: false,
  101. form: null,
  102. state: {
  103. time: 60,
  104. smsSendBtn: false,
  105. },
  106. formLogin: {
  107. username: "",
  108. password: "",
  109. captcha: "",
  110. mobile: "",
  111. rememberMe: true
  112. },
  113. }
  114. },
  115. created () {
  116. this.$http.get('/auth/2step-code')
  117. .then(res => {
  118. this.requiredTwoStepCaptcha = res.result.stepCode
  119. }).catch(err => {
  120. console.log('2step-code:', err)
  121. })
  122. // this.requiredTwoStepCaptcha = true
  123. },
  124. methods: {
  125. ...mapActions([ "Login" ]),
  126. // handler
  127. handleUsernameOrEmail (rule, value, callback) {
  128. const regex = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/;
  129. if (regex.test(value)) {
  130. this.loginType = 0
  131. } else {
  132. this.loginType = 1
  133. }
  134. callback()
  135. },
  136. handleTabClick (key) {
  137. this.customActiveKey = key
  138. // this.form.resetFields()
  139. },
  140. handleSubmit () {
  141. let that = this
  142. let flag = false
  143. let loginParams = {
  144. remember_me: that.formLogin.rememberMe
  145. };
  146. // 使用账户密码登陆
  147. if (that.customActiveKey === 'tab1') {
  148. that.form.validateFields([ 'username', 'password' ], { force: true }, (err, values) => {
  149. if (!err) {
  150. flag = true
  151. loginParams[!that.loginType ? 'email' : 'username'] = values.username
  152. loginParams.password = md5(values.password)
  153. }
  154. })
  155. // 使用手机号登陆
  156. } else {
  157. that.form.validateFields([ 'mobile', 'captcha' ], { force: true }, (err, values) => {
  158. if (!err) {
  159. flag = true
  160. loginParams = Object.assign(loginParams, values)
  161. }
  162. })
  163. }
  164. if (!flag) return
  165. that.loginBtn = true
  166. that.Login(loginParams).then(() => {
  167. if (that.requiredTwoStepCaptcha) {
  168. that.stepCaptchaVisible = true
  169. } else {
  170. that.loginSuccess()
  171. }
  172. }).catch((err) => {
  173. that.requestFailed(err);
  174. })
  175. },
  176. getCaptcha (e) {
  177. e.preventDefault()
  178. let that = this
  179. this.form.validateFields([ 'mobile' ], { force: true },
  180. (err) => {
  181. if (!err) {
  182. this.state.smsSendBtn = true;
  183. let interval = window.setInterval(() => {
  184. if (that.state.time-- <= 0) {
  185. that.state.time = 60;
  186. that.state.smsSendBtn = false;
  187. window.clearInterval(interval);
  188. }
  189. }, 1000);
  190. const hide = this.$message.loading('验证码发送中..', 0);
  191. this.$http.post(api.SendSms, { mobile: that.formLogin.mobile })
  192. .then(res => {
  193. setTimeout(hide, 2500);
  194. this.$notification[ 'success' ]({
  195. message: '提示',
  196. description: '验证码获取成功,您的验证码为:' + res.result.captcha,
  197. duration: 8
  198. })
  199. })
  200. .catch(err => {
  201. setTimeout(hide, 1);
  202. clearInterval(interval);
  203. that.state.time = 60;
  204. that.state.smsSendBtn = false;
  205. this.requestFailed(err);
  206. });
  207. }
  208. }
  209. );
  210. },
  211. stepCaptchaSuccess () {
  212. this.loginSuccess()
  213. },
  214. loginSuccess () {
  215. this.loginBtn = false
  216. this.$router.push({ name: "dashboard" })
  217. this.$message.success(timeFix() + ',欢迎回来', 3)
  218. },
  219. requestFailed (err) {
  220. this.$notification[ 'error' ]({
  221. message: '错误',
  222. description: ((err.response || {}).data || {}).message || "请求出现错误,请稍后再试",
  223. duration: 4,
  224. });
  225. this.loginBtn = false;
  226. },
  227. }
  228. }
  229. </script>
  230. <style lang="scss" scoped>
  231. .user-layout-login {
  232. label {
  233. font-size: 14px;
  234. }
  235. .getCaptcha {
  236. display: block;
  237. width: 100%;
  238. height: 40px;
  239. }
  240. .forge-password {
  241. font-size: 14px;
  242. }
  243. button.login-button {
  244. padding: 0 15px;
  245. font-size: 16px;
  246. height: 40px;
  247. width: 100%;
  248. }
  249. .user-login-other {
  250. text-align: left;
  251. margin-top: 24px;
  252. line-height: 22px;
  253. .item-icon {
  254. font-size: 24px;
  255. color: rgba(0,0,0,.2);
  256. margin-left: 16px;
  257. vertical-align: middle;
  258. cursor: pointer;
  259. transition: color .3s;
  260. &:hover {
  261. color: #1890ff;
  262. }
  263. }
  264. .register {
  265. float: right;
  266. }
  267. }
  268. }
  269. </style>