Login.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. <style>
  2. .impowerBox .title {
  3. display: none;
  4. }
  5. </style>
  6. <template>
  7. <div class="main">
  8. <a-form :form="form" class="user-layout-login" ref="formLogin" id="formLogin">
  9. <a-tabs :activeKey="customActiveKey" :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
  10. @change="handleTabClick">
  11. <a-tab-pane key="tab1" tab="企业微信扫码登录">
  12. <a-form-item>
  13. <div id="wx_reg" style="display:flex;justify-content: center;margin-top:15px"></div>
  14. <div style="display:flex;justify-content: center;color:red;font-size:16px;">
  15. 需先用企业微信开通过账号,方可使用企业微信登录
  16. </div>
  17. </a-form-item>
  18. </a-tab-pane>
  19. <a-tab-pane key="tab2" tab="账号密码登陆">
  20. <a-form-item>
  21. <a-input size="large"
  22. v-decorator="['username', validatorRules.username, { validator: this.handleUsernameOrEmail }]" type="text"
  23. placeholder="请输入帐户名">
  24. <a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }" />
  25. </a-input>
  26. </a-form-item>
  27. <a-form-item>
  28. <a-input v-decorator="['password', validatorRules.password]" size="large" type="password"
  29. autocomplete="false" placeholder="密码">
  30. <a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }" />
  31. </a-input>
  32. </a-form-item>
  33. <a-row :gutter="0">
  34. <a-col :span="14">
  35. <a-form-item>
  36. <a-input v-decorator="['inputCode', validatorRules.inputCode]" size="large" type="text"
  37. @change="inputCodeChange" placeholder="请输入验证码">
  38. <a-icon slot="prefix" v-if="inputCodeContent == verifiedCode" type="smile"
  39. :style="{ color: 'rgba(0,0,0,.25)' }" />
  40. <a-icon slot="prefix" v-else type="frown" :style="{ color: 'rgba(0,0,0,.25)' }" />
  41. </a-input>
  42. </a-form-item>
  43. </a-col>
  44. <a-col :span="10">
  45. <j-graphic-code @success="generateCode" style="float: right"></j-graphic-code>
  46. </a-col>
  47. </a-row>
  48. </a-tab-pane>
  49. </a-tabs>
  50. <a-form-item v-if="customActiveKey != 'tab1'">
  51. <a-checkbox v-model="formLogin.rememberMe">自动登陆</a-checkbox>
  52. <router-link :to="{ name: 'alteration' }" class="forge-password" style="float: right;">
  53. 忘记密码
  54. </router-link>
  55. <!--
  56. <router-link :to="{ name: 'register'}" class="forge-password" style="float: right;margin-right: 10px" >
  57. 注册账户
  58. </router-link>
  59. -->
  60. </a-form-item>
  61. <a-form-item style="margin-top:24px" v-if="customActiveKey != 'tab1'">
  62. <a-button size="large" type="primary" htmlType="submit" class="login-button" :loading="loginBtn"
  63. @click.stop.prevent="handleSubmit" :disabled="loginBtn">确定
  64. </a-button>
  65. </a-form-item>
  66. <!-- <div class="otherLogin" v-if="customActiveKey != 'tab1'"><span class="titleTip">其他登录方式</span></div> -->
  67. <!-- <div class="feishu" @click="FSlogin" v-if="customActiveKey != 'tab1'">
  68. <span class="FSicon">
  69. <img src="@/assets/feishu.png" alt="">
  70. </span>
  71. <span class="FSinfo">使用飞书快捷登录</span>
  72. </div> -->
  73. <!-- <div class="user-login-other">
  74. <span>其他登陆方式</span>
  75. <a><a-icon class="item-icon" type="alipay-circle"></a-icon></a>
  76. <a><a-icon class="item-icon" type="taobao-circle"></a-icon></a>
  77. <a><a-icon class="item-icon" type="weibo-circle"></a-icon></a>
  78. <router-link class="register" :to="{ name: 'register' }">
  79. 注册账户
  80. </router-link>
  81. </div> -->
  82. </a-form>
  83. <two-step-captcha v-if="requiredTwoStepCaptcha" :visible="stepCaptchaVisible" @success="stepCaptchaSuccess"
  84. @cancel="stepCaptchaCancel"></two-step-captcha>
  85. <a-modal title="登录部门选择" :width="450" :visible="departVisible" :closable="false" :maskClosable="false">
  86. <template slot="footer">
  87. <a-button type="primary" @click="departOk">确认</a-button>
  88. </template>
  89. <a-form>
  90. <a-form-item :labelCol="{ span: 4 }" :wrapperCol="{ span: 20 }" style="margin-bottom:10px"
  91. :validate-status="validate_status">
  92. <a-tooltip placement="topLeft">
  93. <template slot="title">
  94. <span>您隶属于多部门,请选择登录部门</span>
  95. </template>
  96. <a-avatar style="backgroundColor:#87d068" icon="gold" />
  97. </a-tooltip>
  98. <a-select @change="departChange" :class="{ 'valid-error': validate_status == 'error' }" placeholder="请选择登录部门"
  99. style="margin-left:10px;width: 80%">
  100. <a-icon slot="suffixIcon" type="gold" />
  101. <a-select-option v-for="d in departList" :key="d.id" :value="d.orgCode">
  102. {{ d.departName }}
  103. </a-select-option>
  104. </a-select>
  105. </a-form-item>
  106. </a-form>
  107. </a-modal>
  108. </div>
  109. </template>
  110. <script>
  111. //import md5 from "md5"
  112. import api from '@/api'
  113. import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
  114. import {
  115. mapActions
  116. } from 'vuex'
  117. import {
  118. timeFix
  119. } from '@/utils/util'
  120. import Vue from 'vue'
  121. import {
  122. ACCESS_TOKEN
  123. } from '@/store/mutation-types'
  124. import JGraphicCode from '@/components/jeecg/JGraphicCode'
  125. import {
  126. putAction
  127. } from '@/api/manage'
  128. import {
  129. postAction
  130. } from '@/api/manage'
  131. import {
  132. getAction
  133. } from '@/api/manage'
  134. import {
  135. encryption
  136. } from '@/utils/encryption/aesEncrypt'
  137. export default {
  138. components: {
  139. TwoStepCaptcha,
  140. JGraphicCode
  141. },
  142. data() {
  143. return {
  144. customActiveKey: 'tab2',
  145. loginBtn: false,
  146. // login type: 0 email, 1 username, 2 telephone
  147. loginType: 0,
  148. requiredTwoStepCaptcha: false,
  149. stepCaptchaVisible: false,
  150. form: this.$form.createForm(this),
  151. state: {
  152. time: 60,
  153. smsSendBtn: false
  154. },
  155. formLogin: {
  156. username: '',
  157. password: '',
  158. captcha: '',
  159. mobile: '',
  160. rememberMe: true
  161. },
  162. validatorRules: {
  163. username: {
  164. rules: [{
  165. required: true,
  166. message: '请输入用户名!',
  167. validator: 'click'
  168. }]
  169. },
  170. password: {
  171. rules: [{
  172. required: true,
  173. message: '请输入密码!',
  174. validator: 'click'
  175. }]
  176. },
  177. mobile: {
  178. rules: [{
  179. validator: this.validateMobile
  180. }]
  181. },
  182. captcha: {
  183. rule: [{
  184. required: true,
  185. message: '请输入验证码!'
  186. }]
  187. },
  188. inputCode: {
  189. rules: [{
  190. required: true,
  191. message: '请输入验证码!'
  192. }, {
  193. validator: this.validateInputCode
  194. }]
  195. }
  196. },
  197. verifiedCode: '',
  198. inputCodeContent: '',
  199. inputCodeNull: true,
  200. departList: [],
  201. departVisible: false,
  202. departSelected: '',
  203. currentUsername: '',
  204. validate_status: ''
  205. }
  206. },
  207. created() {
  208. Vue.ls.remove(ACCESS_TOKEN)
  209. this.getRouterData()
  210. // update-begin- --- author:scott ------ date:20190225 ---- for:暂时注释,未实现登录验证码功能
  211. // this.$http.get('/auth/2step-code')
  212. // .then(res => {
  213. // this.requiredTwoStepCaptcha = res.result.stepCode
  214. // }).catch(err => {
  215. // console.log('2step-code:', err)
  216. // })
  217. // update-end- --- author:scott ------ date:20190225 ---- for:暂时注释,未实现登录验证码功能
  218. // this.requiredTwoStepCaptcha = true
  219. },
  220. mounted() {
  221. this.$nextTick(() => {
  222. var url = ''
  223. if (process.env.NODE_ENV === 'development') {
  224. url = 'http://localhost:3000'
  225. } else if (process.env.NODE_ENV === 'production') {
  226. url = 'http://adsp.c-top.com.cn'
  227. }
  228. console.log(url)
  229. window.WwLogin({
  230. id: 'wx_reg',
  231. appid: 'ww24b8a47826f5875f',
  232. agentid: '1000002',
  233. redirect_uri: 'http://callback.c-top.com.cn:8080/jeecg-boot/qywexin',
  234. state: url + '/user/transfer-local',
  235. href: ''
  236. })
  237. })
  238. },
  239. methods: {
  240. ...mapActions(['Login', 'Logout', 'PhoneLogin']),
  241. // handler
  242. handleUsernameOrEmail(rule, value, callback) {
  243. const regex = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/
  244. if (regex.test(value)) {
  245. this.loginType = 0
  246. } else {
  247. this.loginType = 1
  248. }
  249. callback()
  250. },
  251. handleTabClick(key) {
  252. this.customActiveKey = key
  253. // this.form.resetFields()
  254. },
  255. handleSubmit() {
  256. let that = this
  257. let loginParams = {
  258. remember_me: that.formLogin.rememberMe
  259. }
  260. // 使用账户密码登陆
  261. if (that.customActiveKey === 'tab2') {
  262. that.form.validateFields(['username', 'password', 'inputCode'], {
  263. force: true
  264. }, (err, values) => {
  265. if (!err) {
  266. getAction('/sys/getEncryptedString', {})
  267. .then(res => {
  268. loginParams.username = values.username
  269. //loginParams.password = md5(values.password)
  270. loginParams.password = encryption(values.password, res.result.key, res.result.iv)
  271. that
  272. .Login(loginParams)
  273. .then(res => {
  274. this.departConfirm(res)
  275. })
  276. .catch(err => {
  277. that.requestFailed(err)
  278. })
  279. })
  280. .catch(err => {
  281. that.requestFailed(err)
  282. })
  283. }
  284. })
  285. // 使用手机号登陆
  286. } else if (that.customActiveKey === 'tab3') {
  287. that.form.validateFields(['mobile', 'captcha'], {
  288. force: true
  289. }, (err, values) => {
  290. if (!err) {
  291. loginParams.mobile = values.mobile
  292. loginParams.captcha = values.captcha
  293. that
  294. .PhoneLogin(loginParams)
  295. .then(res => {
  296. console.log(res.result)
  297. this.departConfirm(res)
  298. })
  299. .catch(err => {
  300. that.requestFailed(err)
  301. })
  302. }
  303. })
  304. }
  305. },
  306. getCaptcha(e) {
  307. e.preventDefault()
  308. let that = this
  309. this.form.validateFields(['mobile'], {
  310. force: true
  311. }, (err, values) => {
  312. if (!values.mobile) {
  313. that.cmsFailed('请输入手机号')
  314. } else if (!err) {
  315. this.state.smsSendBtn = true
  316. let interval = window.setInterval(() => {
  317. if (that.state.time-- <= 0) {
  318. that.state.time = 60
  319. that.state.smsSendBtn = false
  320. window.clearInterval(interval)
  321. }
  322. }, 1000)
  323. const hide = this.$message.loading('验证码发送中..', 0)
  324. let smsParams = {}
  325. smsParams.mobile = values.mobile
  326. smsParams.smsmode = '0'
  327. postAction('/sys/sms', smsParams)
  328. .then(res => {
  329. if (!res.success) {
  330. setTimeout(hide, 0)
  331. this.cmsFailed(res.message)
  332. }
  333. console.log(res)
  334. setTimeout(hide, 500)
  335. })
  336. .catch(err => {
  337. setTimeout(hide, 1)
  338. clearInterval(interval)
  339. that.state.time = 60
  340. that.state.smsSendBtn = false
  341. this.requestFailed(err)
  342. })
  343. }
  344. })
  345. },
  346. stepCaptchaSuccess() {
  347. this.loginSuccess()
  348. },
  349. stepCaptchaCancel() {
  350. this.Logout().then(() => {
  351. this.loginBtn = false
  352. this.stepCaptchaVisible = false
  353. })
  354. },
  355. loginSuccess() {
  356. this.loginBtn = false
  357. this.$router.push({
  358. name: 'dashboard'
  359. })
  360. this.$notification.success({
  361. message: '欢迎',
  362. description: `${timeFix()},欢迎回来`
  363. })
  364. },
  365. cmsFailed(err) {
  366. setTimeout(() => {
  367. this.$notification['error']({
  368. key:"1",
  369. message: '登录失败',
  370. description: err,
  371. duration: 4
  372. })
  373. }, 2000);
  374. },
  375. requestFailed(err) {
  376. setTimeout(() => {
  377. this.$notification['error']({
  378. key:"1",
  379. message: '登录失败',
  380. description: ((err.response || {}).data || {}).message || err.message || '请求出现错误,请稍后再试',
  381. duration: 4
  382. })
  383. }, 2000);
  384. this.loginBtn = false
  385. },
  386. validateMobile(rule, value, callback) {
  387. if (!value || new RegExp(/^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$/).test(value)) {
  388. callback()
  389. } else {
  390. callback('您的手机号码格式不正确!')
  391. }
  392. },
  393. validateInputCode(rule, value, callback) {
  394. if (!value || this.verifiedCode == this.inputCodeContent) {
  395. callback()
  396. } else {
  397. callback('您输入的验证码不正确!')
  398. }
  399. },
  400. generateCode(value) {
  401. this.verifiedCode = value.toLowerCase()
  402. },
  403. inputCodeChange(e) {
  404. this.inputCodeContent = e.target.value
  405. if (!e.target.value || 0 == e.target.value) {
  406. this.inputCodeNull = true
  407. } else {
  408. this.inputCodeContent = this.inputCodeContent.toLowerCase()
  409. this.inputCodeNull = false
  410. }
  411. },
  412. departConfirm(res) {
  413. if (res.success) {
  414. let multi_depart = res.result.multi_depart
  415. //0:无部门 1:一个部门 2:多个部门
  416. if (multi_depart == 0) {
  417. this.loginSuccess()
  418. this.$notification.warn({
  419. message: '提示',
  420. description: `您尚未归属部门,请确认账号信息`,
  421. duration: 3
  422. })
  423. } else if (multi_depart == 2) {
  424. this.departVisible = true
  425. this.currentUsername = this.form.getFieldValue('username')
  426. this.departList = res.result.departs
  427. } else {
  428. this.loginSuccess()
  429. }
  430. } else {
  431. this.requestFailed(res)
  432. this.Logout()
  433. }
  434. },
  435. departOk() {
  436. if (!this.departSelected) {
  437. this.validate_status = 'error'
  438. return false
  439. }
  440. let obj = {
  441. orgCode: this.departSelected,
  442. username: this.form.getFieldValue('username')
  443. }
  444. putAction('/sys/selectDepart', obj).then(res => {
  445. if (res.success) {
  446. this.departClear()
  447. this.loginSuccess()
  448. } else {
  449. this.requestFailed(res)
  450. this.Logout().then(() => {
  451. this.departClear()
  452. })
  453. }
  454. })
  455. },
  456. departClear() {
  457. this.departList = []
  458. this.departSelected = ''
  459. this.currentUsername = ''
  460. this.departVisible = false
  461. this.validate_status = ''
  462. },
  463. departChange(value) {
  464. this.validate_status = 'success'
  465. this.departSelected = value
  466. },
  467. getRouterData() {
  468. this.$nextTick(() => {
  469. this.form.setFieldsValue({
  470. username: this.$route.params.username
  471. })
  472. })
  473. },
  474. FSlogin() {
  475. console.log('FSlogin');
  476. // this.$router.push('http://192.168.0.111:8088/jeecg-boot/sys/feishu/url')
  477. // window.history.go('');
  478. window.location.href =
  479. "https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri=http%3A%2F%2Fadsp.tjyourong.com.cn%2Fuser%2FFStransfer&app_id=cli_9e68af69ca34d00e&state=";
  480. // getAction('/sys/feishu/url', {}).then((res) => {
  481. // console.log(res);
  482. // if (res.success) {
  483. // }
  484. // })
  485. }
  486. }
  487. }
  488. </script>
  489. <style lang="scss" scoped>
  490. .user-layout-login {
  491. label {
  492. font-size: 14px;
  493. }
  494. .getCaptcha {
  495. display: block;
  496. width: 100%;
  497. height: 40px;
  498. }
  499. .forge-password {
  500. font-size: 14px;
  501. }
  502. button.login-button {
  503. padding: 0 15px;
  504. font-size: 16px;
  505. height: 40px;
  506. width: 100%;
  507. }
  508. .user-login-other {
  509. text-align: left;
  510. margin-top: 24px;
  511. line-height: 22px;
  512. .item-icon {
  513. font-size: 24px;
  514. color: rgba(0, 0, 0, 0.2);
  515. margin-left: 16px;
  516. vertical-align: middle;
  517. cursor: pointer;
  518. transition: color 0.3s;
  519. &:hover {
  520. color: #1890ff;
  521. }
  522. }
  523. .register {
  524. float: right;
  525. }
  526. }
  527. .otherLogin {
  528. margin-top: 60px;
  529. font-size: 14px;
  530. color: #999;
  531. height: 20px;
  532. line-height: 20px;
  533. text-align: center;
  534. position: relative;
  535. .titleTip::before {
  536. content: '';
  537. display: block;
  538. width: 120px;
  539. height: 1px;
  540. background-color: #ccc;
  541. position: absolute;
  542. top: 10px;
  543. left: 5px;
  544. }
  545. .titleTip::after {
  546. content: '';
  547. display: block;
  548. width: 120px;
  549. height: 1px;
  550. background-color: #ccc;
  551. position: absolute;
  552. top: 10px;
  553. right: 5px;
  554. }
  555. }
  556. .feishu {
  557. text-align: center;
  558. cursor: pointer;
  559. margin-top: 15px;
  560. padding: 5px 0;
  561. // border: 1px solid #ccc;
  562. border-radius: 10px;
  563. .FSicon {
  564. display: inline-block;
  565. width: 40px;
  566. height: 40px;
  567. background-color: #fff;
  568. border-radius: 50%;
  569. padding: 6px;
  570. img {
  571. height: 100%;
  572. }
  573. }
  574. .FSinfo {
  575. display: inline-block;
  576. height: 40px;
  577. line-height: 40px;
  578. margin-left: 15px;
  579. font-size: 16px;
  580. font-weight: 500;
  581. // color: rgb(0,127,255);
  582. }
  583. }
  584. .feishu:hover {
  585. color: rgb(0, 127, 255)
  586. }
  587. }
  588. </style>
  589. <style>
  590. .valid-error .ant-select-selection__placeholder {
  591. color: #f5222d;
  592. }
  593. </style>