index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. <template>
  2. <div class="login-container">
  3. <div class="company-name">
  4. {{ title }}
  5. <!-- <img src="./images/logo.png" /> -->
  6. </div>
  7. <div class="fill-container" v-show="isMydesk">
  8. <div class="left">
  9. <img src="./images/background3.png" />
  10. </div>
  11. <div class="right">
  12. <div class="top">
  13. <span>用户登录</span>
  14. <!-- <span>城市排水综合管网管理平台</span> -->
  15. </div>
  16. <el-form
  17. ref="loginForm"
  18. :model="loginForm"
  19. :rules="loginRules"
  20. class="login-form middle"
  21. auto-complete="on"
  22. label-position="left"
  23. style="position: relative; left: calc((100% - 320px) / 2); top: 100px"
  24. >
  25. <el-input
  26. ref="username"
  27. v-model.trim="loginForm.username"
  28. prefix-icon="el-icon-user"
  29. placeholder="请输入账号"
  30. name="username"
  31. type="text"
  32. class="form-input"
  33. tabindex="1"
  34. auto-complete="on"
  35. />
  36. <el-input
  37. :key="passwordType"
  38. ref="password"
  39. v-model.trim="loginForm.password"
  40. :type="passwordType"
  41. placeholder="请输入密码"
  42. name="password"
  43. tabindex="2"
  44. class="form-input"
  45. auto-complete="on"
  46. prefix-icon="el-icon-lock"
  47. @keyup.enter.native="handleLogin"
  48. show-password
  49. />
  50. <el-input
  51. ref="msg"
  52. tabindex="3"
  53. prefix-icon="el-icon-tickets"
  54. placeholder="请输入短信验证码"
  55. v-model.trim="loginForm.msg"
  56. type="text"
  57. class="form-input"
  58. >
  59. <el-button @click="sendMsg()" type="primary" slot="append" :disabled="btnDisabled">{{
  60. btnTitle
  61. }}</el-button>
  62. </el-input>
  63. </el-form>
  64. <el-button type="button" class="login-btn" :loading="loading" @click.native.prevent="handleLogin"
  65. >登录</el-button
  66. >
  67. <el-button type="text" class="forgetpsw-btn" style="left: 38%" @click="resetPsw()">忘记密码?</el-button>
  68. <el-button type="text" class="forgetpsw-btn" style="left: 60%" @click="modifyPsw()"
  69. >修改密码<i class="el-icon-edit"></i
  70. ></el-button>
  71. </div>
  72. </div>
  73. <el-dialog
  74. title="密码修改"
  75. :visible.sync="passwordDialog"
  76. append-to-body
  77. width="520px"
  78. top="25vh"
  79. :close-on-click-modal="false"
  80. :close-on-press-escape="false"
  81. :show-close="false"
  82. >
  83. <el-form ref="changePwdForm" :model="changePwd" :rules="pwdRules" label-width="100px" label-position="right">
  84. <el-form-item label="密码:" prop="pass" style="margin-bottom: 25px">
  85. <el-input
  86. v-model="changePwd.pass"
  87. autocomplete="off"
  88. type="password"
  89. placeholder="请输入密码"
  90. prefix-icon="el-icon-lock"
  91. show-password
  92. />
  93. </el-form-item>
  94. <el-form-item label="确认密码:" prop="checkPass">
  95. <el-input
  96. v-model="changePwd.checkPass"
  97. autocomplete="off"
  98. type="password"
  99. placeholder="请输入密码"
  100. prefix-icon="el-icon-lock"
  101. show-password
  102. />
  103. </el-form-item>
  104. </el-form>
  105. <template slot="footer">
  106. <el-button @click="handleDialogBtnClick('cancel')">取消</el-button>
  107. <el-button type="primary" @click="handleDialogBtnClick('confirm')">确定</el-button>
  108. </template>
  109. </el-dialog>
  110. <ResetPsw
  111. :title="isReset ? '重置密码' : '修改密码'"
  112. :visible="resetPswDialog"
  113. :username="loginForm.username"
  114. :isReset="isReset"
  115. @add="setContent"
  116. @cancel="resetPswDialog = false"
  117. />
  118. </div>
  119. </template>
  120. <script lang="ts">
  121. import { Vue, Component, Watch } from 'vue-property-decorator'
  122. import { userFirstLogin, getMsgCode } from '@/api/user'
  123. import { changePassword } from '@/api/base'
  124. import { regNewPassword } from '@/utils/reg'
  125. import { ElForm } from 'element-ui/types/form'
  126. import { sysTitle } from '@/settings'
  127. import ResetPsw from './resetPsw.vue'
  128. import { encryption } from '@/utils/encryption'
  129. const defaultPwd = '000000'
  130. @Component({ components: { ResetPsw } })
  131. export default class Login extends Vue {
  132. name = 'Login'
  133. url = '@/assets/images/login/logo.png'
  134. title = sysTitle
  135. loginForm = {
  136. username: '',
  137. password: '',
  138. msg: ''
  139. }
  140. btnTitle = '发送验证码'
  141. btnDisabled = false
  142. time = 60
  143. loginRules = {
  144. username: [{ required: true, trigger: 'blur', message: '请输入账号' }],
  145. password: [{ required: true, trigger: 'blur', message: '请输入密码' }],
  146. msg: [{ required: true, trigger: 'blur', message: '请输入短信验证码' }]
  147. }
  148. loading = false
  149. passwordType = 'password'
  150. redirect = undefined
  151. error = 1
  152. // warning: true,
  153. msg = ''
  154. passwordDialog = false // 重置密码用弹窗显隐控制
  155. changePwd = {
  156. pass: '', // 重置密码用新密码
  157. checkPass: '' // 重置密码用确认密码
  158. }
  159. pwdRules = {}
  160. userId = ''
  161. /**是否从mydesk跳转 */
  162. isMydesk = true
  163. mydeskUrl = 'https://uac.ctg.com.cn/sso/login'
  164. get sysTitle() {
  165. return this.$store.state.settings.sysTitle
  166. }
  167. //重置密码
  168. resetPswDialog = false // 重置密码用弹窗显隐控制
  169. isReset = true // 重置or修改
  170. /**mydesk登录验证 */
  171. beforeMount() {
  172. const search = window.location.hash.split('?')[1]
  173. const SYS_ADDR = location.href.replace(/\#\/login.*$/, '')
  174. if (search) {
  175. const typeIndex = search.indexOf('type')
  176. const tokenIndex = search.indexOf('token')
  177. const rtype = this.getSearchString('type', search)
  178. if (typeIndex > -1 && rtype === 'mydesk') {
  179. this.isMydesk = false
  180. }
  181. if (typeIndex > -1 && tokenIndex === -1) {
  182. if (rtype === 'mydesk') {
  183. const url = SYS_ADDR + '#/login?type=mydesk'
  184. window.location.href = this.mydeskUrl + '?url=' + encodeURIComponent(url)
  185. }
  186. } else if (typeIndex > -1 && tokenIndex > -1) {
  187. const token = this.getSearchString('token', search)
  188. this.loginWithTokenCheck(token)
  189. return
  190. }
  191. }
  192. }
  193. mounted() {
  194. this.pwdRules = {
  195. pass: [{ required: true, validator: this.validatePwd1st, trigger: 'blur' }],
  196. checkPass: [{ required: true, validator: this.validatePwd2nd, trigger: 'blur' }]
  197. }
  198. }
  199. getSearchString(key, Url) {
  200. var str = Url
  201. //str = str.substring(1, str.length) // 获取URL中?之后的字符(去掉第一位的问号)
  202. // 以&分隔字符串,获得类似name=xiaoli这样的元素数组
  203. var arr = str.split('&')
  204. var obj = new Object()
  205. // 将每一个数组元素以=分隔并赋给obj对象
  206. for (var i = 0; i < arr.length; i++) {
  207. var tmp_arr = arr[i].split('=')
  208. obj[decodeURIComponent(tmp_arr[0])] = decodeURIComponent(tmp_arr[1])
  209. }
  210. return obj[key]
  211. }
  212. /**
  213. * 根据mydesk token登录
  214. * @param {*} token
  215. */
  216. loginWithTokenCheck(token) {
  217. this.$store.dispatch('user/mydeskLogin', { token: token }).then((result) => {
  218. setTimeout(() => {
  219. //this.$router.push({ path: '/prjSelection' })
  220. this.$router.push({ path: '/' })
  221. }, 0)
  222. })
  223. }
  224. validatePwd1st(rule, value, callback) {
  225. if (value === '') {
  226. callback(new Error('请输入密码!'))
  227. } else {
  228. if (this.changePwd.pass !== '') {
  229. if (!regNewPassword().test(value)) {
  230. callback(new Error('密码位数至少12位,必须包含大小写字母和数字,不可包含非法字符!'))
  231. return
  232. }
  233. }
  234. callback()
  235. }
  236. }
  237. validatePwd2nd(rule, value, callback) {
  238. if (value === '') {
  239. callback(new Error('请再次输入密码'))
  240. } else if (value !== this.changePwd.pass && value !== '') {
  241. callback(new Error('两次输入密码不一致!'))
  242. } else {
  243. callback()
  244. }
  245. }
  246. @Watch('$route', { immediate: true })
  247. changeValue(route, oldvalue) {
  248. this.redirect = route.query && route.query.redirect
  249. }
  250. // 是否显示密码
  251. showPwd() {
  252. if (this.passwordType === 'password') {
  253. this.passwordType = 'text'
  254. } else {
  255. this.passwordType = 'password'
  256. }
  257. this.$nextTick(() => {
  258. ;(this.$refs.password as HTMLElement).focus()
  259. })
  260. }
  261. // 登录
  262. handleLogin() {
  263. ;(this.$refs.loginForm as ElForm).validate((valid) => {
  264. if (valid) {
  265. this.loading = true
  266. /**
  267. * 最短6位,最长16位 {6,16}
  268. * 必须包含1个数字
  269. * 必须包含2个小写字母
  270. * 必须包含2个大写字母
  271. * 必须包含1个特殊字符
  272. */
  273. // const pattern = /^.*(?=.{6,16})(?=.*\d)(?=.*[A-Z]{2,})(?=.*[a-z]{2,})(?=.*[!@#$%^&*?\(\)]).*$/
  274. /**
  275. * 最短6位,最长16位 {8,30}
  276. * 必须包含1个数字
  277. * 必须包含1个小写字母
  278. * 必须包含1个大写字母
  279. * 不必须包含1个特殊字符
  280. */
  281. // const pattern = /^.*(?=.{8,30})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*?\(\)]?).*$/
  282. this.$store
  283. .dispatch('user/login', this.loginForm)
  284. .then((res) => {
  285. const { id } = res.result
  286. // 判断是否首次登录或者重置过密码
  287. userFirstLogin(id)
  288. .then((res) => {
  289. // 先判断用户是否被禁用了 如果是申请的用户 还需要要判断是否同意申请了
  290. const { auditstatus, enableFlag } = res.result
  291. if (enableFlag === '0') {
  292. this.$message({
  293. message: '用户已被禁用,请先启用!',
  294. type: 'error'
  295. })
  296. this.loading = false
  297. sessionStorage.clear()
  298. return
  299. }
  300. if (auditstatus !== '2' && auditstatus !== null) {
  301. this.$message({
  302. message: auditstatus === 1 ? '账户还未审核通过!' : '账户审核未被通过!',
  303. type: 'error'
  304. })
  305. this.loading = false
  306. sessionStorage.clear()
  307. return
  308. }
  309. // 是首次登录 打开弹窗 修改密码
  310. if (res.result.firstlog === '1' && this.loginForm.password === defaultPwd) {
  311. this.userId = id
  312. this.passwordDialog = true
  313. // 清除掉用户id 防止用户没有修改密码刷新进入页面
  314. sessionStorage.removeItem('userId')
  315. this.$store.state.user.userId = undefined
  316. } else {
  317. this.loading = false
  318. setTimeout(() => {
  319. // this.$router.push({ path: '/prjSelection' })
  320. this.$router.push({ path: '/' })
  321. }, 0)
  322. }
  323. })
  324. .catch(() => {
  325. sessionStorage.clear()
  326. this.loading = false
  327. })
  328. // this.$router.push({ path: '/' })
  329. })
  330. .catch((err) => {
  331. this.$message.error(err.message)
  332. this.loading = false
  333. })
  334. } else {
  335. console.log('error submit!!')
  336. return false
  337. }
  338. // this.$router.push('/dashboard')
  339. })
  340. }
  341. //发送验证码
  342. sendMsg() {
  343. if (this.loginForm.username === '' && this.loginForm.password === '') {
  344. this.$message.error('请输入账号')
  345. return
  346. }
  347. let timer = setInterval(() => {
  348. this.time--
  349. this.btnDisabled = true
  350. this.btnTitle = `${this.time}s后重新发送`
  351. if (this.time === 0) {
  352. this.time = 60
  353. this.btnDisabled = false
  354. this.btnTitle = '发送验证码'
  355. clearInterval(timer)
  356. }
  357. }, 1000)
  358. getMsgCode({ username: this.loginForm.username })
  359. .then((result) => {
  360. this.$message.success(result.result)
  361. })
  362. .catch((error) => {
  363. console.log(error)
  364. })
  365. }
  366. // 修改密码弹窗
  367. handleDialogBtnClick(type) {
  368. if (type === 'cancel') {
  369. this.$nextTick(() => {
  370. ;(this.$refs.changePwdForm as ElForm).resetFields()
  371. })
  372. this.passwordDialog = false
  373. this.changePwd.pass = ''
  374. this.changePwd.checkPass = ''
  375. sessionStorage.clear()
  376. this.loading = false
  377. } else {
  378. ;(this.$refs.changePwdForm as ElForm).validate((valid) => {
  379. if (valid) {
  380. const data = {
  381. originalPassword: encryption(defaultPwd),
  382. id: this.userId,
  383. firstlog: 0,
  384. password: encryption(this.changePwd.checkPass)
  385. }
  386. changePassword(data).then((res) => {
  387. if (res.code !== -1) {
  388. this.$message({
  389. message: '密码修改成功,请您重新登录!',
  390. type: 'success'
  391. })
  392. this.passwordDialog = false
  393. this.loading = false
  394. this.changePwd.pass = ''
  395. this.changePwd.checkPass = ''
  396. this.loginForm.password = ''
  397. sessionStorage.clear()
  398. } else {
  399. this.$nextTick(() => {
  400. ;(this.$refs.changePwdForm as ElForm).resetFields()
  401. })
  402. this.passwordDialog = false
  403. this.loading = false
  404. this.changePwd.pass = ''
  405. this.changePwd.checkPass = ''
  406. sessionStorage.clear()
  407. this.$message({
  408. message: res.message,
  409. type: 'error'
  410. })
  411. }
  412. })
  413. } else return false
  414. })
  415. }
  416. }
  417. //重置密码弹窗
  418. resetPsw() {
  419. this.resetPswDialog = true
  420. this.isReset = true
  421. }
  422. setContent(val) {
  423. const { password, code } = val
  424. this.loginForm.password = password
  425. this.loginForm.msg = code
  426. }
  427. //修改密码
  428. modifyPsw() {
  429. this.resetPswDialog = true
  430. this.isReset = false
  431. }
  432. }
  433. </script>
  434. <style lang="scss" scoped>
  435. .login-container {
  436. width: 100%;
  437. height: 100%;
  438. flex-direction: column;
  439. justify-content: center;
  440. align-items: center;
  441. background: url('./images/background.png') no-repeat fixed center/100%;
  442. background-size: cover;
  443. .company-name {
  444. position: absolute;
  445. font-size: 40px;
  446. color: white;
  447. font-weight: 500;
  448. letter-spacing: 4px;
  449. width: 100%;
  450. text-align: center;
  451. top: calc((100% - 534px) / 2);
  452. -webkit-box-reflect: below 1px -webkit-gradient(linear, 0 0, 0 50%, from(transparent), color-stop(0.2, transparent), to(rgba(3, 3, 3, 0.1)));
  453. }
  454. img {
  455. user-select: none;
  456. height: 100%;
  457. }
  458. .fill-container {
  459. position: relative;
  460. width: 926px;
  461. height: 434px;
  462. border-radius: 10px;
  463. background-color: rgb(228, 242, 255);
  464. left: calc((100% - 926px) / 2);
  465. top: calc((100% - 334px) / 2);
  466. .left {
  467. position: relative;
  468. float: left;
  469. width: 538px;
  470. overflow: hidden;
  471. }
  472. .right {
  473. width: 388px;
  474. height: 100%;
  475. position: relative;
  476. float: left;
  477. .top {
  478. font-size: 25px;
  479. font-weight: 700;
  480. color: rgb(45, 116, 231);
  481. text-align: center;
  482. width: 100%;
  483. top: 50px;
  484. position: relative;
  485. float: left;
  486. > span {
  487. line-height: 30px;
  488. &:nth-of-type(2) {
  489. margin-top: 16px;
  490. }
  491. }
  492. }
  493. /deep/ input.el-input__inner {
  494. padding-left: 40px !important;
  495. }
  496. /deep/ i.el-input__icon.el-icon-user,
  497. /deep/ i.el-input__icon.el-icon-lock,
  498. /deep/ i.el-input__icon.el-icon-tickets {
  499. font-size: 20px;
  500. color: #2d74e7;
  501. top: -2.25px;
  502. position: relative;
  503. }
  504. .middle {
  505. width: 320px;
  506. height: 106px;
  507. margin-bottom: 80px;
  508. > .form-input {
  509. height: 36px;
  510. line-height: 36px;
  511. /deep/ input {
  512. height: 36px;
  513. }
  514. &:nth-of-type(2) {
  515. margin-top: 15px;
  516. }
  517. &:nth-of-type(3) {
  518. margin-top: 15px;
  519. }
  520. }
  521. }
  522. .login-btn {
  523. width: 320px;
  524. height: 44px;
  525. border-radius: 22px;
  526. position: relative;
  527. float: left;
  528. left: calc((100% - 320px) / 2);
  529. top: 120px;
  530. overflow: hidden;
  531. font-size: 16px;
  532. background: #2d74e7;
  533. transition: background 0.3s linear;
  534. color: #ffffff;
  535. &:hover {
  536. background: #2467d3;
  537. }
  538. }
  539. .forgetpsw-btn {
  540. position: absolute;
  541. // bottom: 45px;
  542. bottom: 7px;
  543. left: 50%;
  544. margin-left: -28px;
  545. }
  546. .forgetpsw-btn:last-child::before {
  547. content: '';
  548. position: absolute;
  549. height: 12px;
  550. width: 1px;
  551. background: #01a2ff;
  552. margin: 0 auto;
  553. left: -10px;
  554. bottom: 12px;
  555. }
  556. }
  557. }
  558. }
  559. </style>