login.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. <template>
  2. <div class="login" id="loginBox">
  3. <div class="login-con">
  4. <div class="img-box">
  5. <img src="../assets/images/login_left.png" alt="">
  6. </div>
  7. <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
  8. <h3 class="title">互联网医院医生端</h3>
  9. <el-form-item>
  10. <el-radio-group v-model="loginForm.type">
  11. <el-radio-button label="1">医生</el-radio-button>
  12. <el-radio-button label="2">药剂师</el-radio-button>
  13. </el-radio-group>
  14. </el-form-item>
  15. <el-form-item prop="account">
  16. <el-input v-model="loginForm.account" type="text" auto-complete="off" placeholder="账号">
  17. <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
  18. </el-input>
  19. </el-form-item>
  20. <el-form-item prop="password">
  21. <el-input
  22. v-model="loginForm.password"
  23. type="password"
  24. auto-complete="off"
  25. placeholder="密码"
  26. @keyup.enter.native="handleLogin"
  27. >
  28. <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
  29. </el-input>
  30. </el-form-item>
  31. <el-form-item prop="code">
  32. <el-input
  33. v-model="loginForm.code"
  34. auto-complete="off"
  35. placeholder="验证码"
  36. style="width: 63%"
  37. @keyup.enter.native="handleLogin"
  38. >
  39. <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
  40. </el-input>
  41. <div class="login-code">
  42. <img :src="codeUrl" @click="getCode" class="login-code-img"/>
  43. </div>
  44. </el-form-item>
  45. <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
  46. <el-form-item style="width:100%;">
  47. <el-button
  48. :loading="loading"
  49. size="medium"
  50. type="primary"
  51. style="width:100%;"
  52. @click.native.prevent="handleLogin"
  53. >
  54. <span v-if="!loading">登 录</span>
  55. <span v-else>登 录 中...</span>
  56. </el-button>
  57. </el-form-item>
  58. </el-form>
  59. </div>
  60. <!-- 底部 -->
  61. <div class="el-login-footer">
  62. <span>{{companyName}}</span>
  63. <a :href="icpUrl" target="_blank">{{icpRecord}}</a>
  64. </div>
  65. </div>
  66. </template>
  67. <script>
  68. import { imConfig } from '@/utils/im'
  69. import { getCodeImg } from "@/api/common";
  70. import Cookies from "js-cookie";
  71. import { encrypt, decrypt } from '@/utils/jsencrypt'
  72. export default {
  73. name: "Login",
  74. data() {
  75. return {
  76. companyName: process.env.VUE_APP_COMPANY_NAME,
  77. icpRecord: process.env.VUE_APP_ICP_RECORD,
  78. icpUrl: process.env.VUE_APP_ICP_URL,
  79. codeUrl: "",
  80. cookiePassword: "",
  81. loginForm: {
  82. account: "",
  83. password: "",
  84. rememberMe: false,
  85. code: "",
  86. uuid: "",
  87. type: '1',
  88. },
  89. loginRules: {
  90. account: [
  91. { required: true, trigger: "blur", message: "用户名不能为空" }
  92. ],
  93. password: [
  94. { required: true, trigger: "blur", message: "密码不能为空" }
  95. ],
  96. code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
  97. },
  98. loading: false,
  99. };
  100. },
  101. watch: {
  102. $route: {
  103. handler: function(route) {
  104. },
  105. immediate: true
  106. }
  107. },
  108. mounted() {
  109. },
  110. created() {
  111. this.getCode();
  112. this.getCookie();
  113. },
  114. methods: {
  115. getCode() {
  116. getCodeImg().then(res => {
  117. this.codeUrl = "data:image/gif;base64," + res.img;
  118. this.loginForm.uuid = res.uuid;
  119. }).catch(err => {
  120. this.$message.error("验证码获取失败,请刷新重试");
  121. console.error("验证码接口异常:", err);
  122. });
  123. },
  124. // 读取Cookie中的账号密码
  125. getCookie() {
  126. const account = Cookies.get("account");
  127. const password = Cookies.get("password");
  128. const rememberMe = Cookies.get('rememberMe');
  129. // 保留原有loginForm属性(如type),仅覆盖Cookie中存在的值
  130. this.loginForm = {
  131. ...this.loginForm,
  132. account: account || this.loginForm.account,
  133. password: password ? decrypt(password) : this.loginForm.password,
  134. rememberMe: rememberMe !== undefined ? Boolean(rememberMe) : this.loginForm.rememberMe
  135. };
  136. },
  137. // 登录核心逻辑
  138. handleLogin() {
  139. this.$refs.loginForm.validate(valid => {
  140. if (!valid) return; // 表单校验失败直接返回
  141. this.loading = true;
  142. // 处理记住密码逻辑
  143. if (this.loginForm.rememberMe) {
  144. Cookies.set("account", this.loginForm.account, { expires: 30 });
  145. Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
  146. Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
  147. } else {
  148. Cookies.remove("account");
  149. Cookies.remove("password");
  150. Cookies.remove('rememberMe');
  151. }
  152. this.$store.dispatch("Login", this.loginForm)
  153. .then((res) => {
  154. const loginType = res.doctor.doctorType;
  155. const userRole = loginType === 1 ? 'doctor' : 'nurse';
  156. localStorage.setItem('loginType', loginType);
  157. localStorage.setItem('userRole', userRole);
  158. // 登录成功跳转首页
  159. this.$router.push({ path: "/index" });
  160. this.$message.success("登录成功!");
  161. })
  162. .catch((err) => {
  163. // 登录失败处理
  164. this.loading = false;
  165. this.getCode(); // 刷新验证码
  166. this.$message.error(err.message || "登录失败,请检查账号密码或验证码");
  167. console.error("登录异常:", err);
  168. });
  169. });
  170. }
  171. }
  172. };
  173. </script>
  174. <style rel="stylesheet/scss" lang="scss">
  175. .login {
  176. display: flex;
  177. justify-content: center;
  178. align-items: center;
  179. height: 100vh;
  180. width: 100%;
  181. background-image: linear-gradient(#0e68c3, #1e99f5);
  182. background-size: cover;
  183. .login-con {
  184. width: 750px;
  185. display: flex;
  186. align-items: center;
  187. justify-content: space-between;
  188. border-radius: 10px;
  189. overflow: hidden;
  190. background: #ffffff;
  191. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  192. .img-box {
  193. width: 460px;
  194. height: 460px;
  195. img {
  196. width: 100%;
  197. height: 100%;
  198. object-fit: cover;
  199. }
  200. }
  201. }
  202. }
  203. .title {
  204. margin: 0px auto 30px auto;
  205. text-align: center;
  206. color: #707070;
  207. font-size: 18px;
  208. font-weight: 500;
  209. }
  210. .login-form {
  211. box-sizing: border-box;
  212. background: #ffffff;
  213. width: 330px;
  214. padding: 25px 25px 5px 25px;
  215. .el-input {
  216. height: 38px;
  217. input {
  218. height: 38px;
  219. }
  220. }
  221. .input-icon {
  222. height: 39px;
  223. width: 14px;
  224. margin-left: 2px;
  225. }
  226. .el-radio-group {
  227. width: 100%;
  228. display: flex;
  229. justify-content: center;
  230. margin-bottom: 10px;
  231. }
  232. .el-radio-button {
  233. margin: 0 15px;
  234. }
  235. }
  236. .login-code {
  237. width: 33%;
  238. height: 38px;
  239. float: right;
  240. img {
  241. cursor: pointer;
  242. vertical-align: middle;
  243. height: 100%;
  244. width: 100%;
  245. object-fit: cover;
  246. }
  247. }
  248. .el-login-footer {
  249. height: 40px;
  250. line-height: 40px;
  251. position: fixed;
  252. bottom: 0;
  253. width: 100%;
  254. text-align: center;
  255. color: #fff;
  256. font-family: Arial;
  257. font-size: 12px;
  258. letter-spacing: 1px;
  259. }
  260. .login-code-img {
  261. height: 38px;
  262. border-radius: 4px;
  263. }
  264. .el-radio-button__inner {
  265. border-radius: 20px !important;
  266. padding: 0 20px;
  267. }
  268. </style>