标准版政企呼叫中心业务系统

login.vue 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <!-- 代码已包含 CSS:使用 TailwindCSS , 安装 TailwindCSS 后方可看到布局样式效果 -->
  2. <template>
  3. <div class="min-h-screen flex">
  4. <!-- 左侧品牌区 -->
  5. <div class="w-2/5 relative overflow-hidden">
  6. <img class="absolute w-full h-full object-cover"
  7. :src="loginImage" alt="背景图" />
  8. <div class="relative z-10 flex flex-col h-full p-12 text-white">
  9. <div class="mb-12">
  10. <h1 class="text-3xl font-bold mb-2">12356心理援助热线</h1>
  11. <p class="text-lg opacity-80">全方位的客户服务解决方案</p>
  12. </div>
  13. <div class="mt-auto">
  14. <p class="text-sm opacity-70">打造智能化、数字化的客户服务体验</p>
  15. </div>
  16. </div>
  17. </div>
  18. <!-- 右侧登录区 -->
  19. <div class="w-3/5 bg-white flex items-center justify-center p-12">
  20. <div class="w-96">
  21. <h2 class="text-3xl font-bold mb-8 text-gray-800">欢迎登录</h2>
  22. <div class="space-y-6">
  23. <!-- 用户名输入框 -->
  24. <div class="relative">
  25. <el-input v-model="username" placeholder="请输入用户名" class="h-12 text-base" :prefix-icon="User" />
  26. </div>
  27. <!-- 密码输入框 -->
  28. <div class="relative">
  29. <el-input v-model="password" :type="showPassword ? 'text' : 'password'" placeholder="请输入密码"
  30. class="h-12 text-base" :prefix-icon="Lock">
  31. <template #suffix>
  32. <el-icon class="cursor-pointer" @click="showPassword = !showPassword">
  33. <component :is="showPassword ? View : Hide" />
  34. </el-icon>
  35. </template>
  36. </el-input>
  37. </div>
  38. <!-- 验证码 -->
  39. <div class="flex gap-4">
  40. <el-input v-model="captcha" placeholder="请输入验证码" class="h-12 text-base" :prefix-icon="Key" />
  41. <div class="w-32 h-12 bg-gray-100 flex items-center justify-center cursor-pointer" @click="getCode">
  42. <img class="w-32 h-12" :src="codeUrl" alt="验证码" />
  43. </div>
  44. </div>
  45. <!-- 记住密码 -->
  46. <div class="flex items-center justify-between">
  47. <el-checkbox v-model="rememberMe">记住密码</el-checkbox>
  48. <!-- <a href="#" class="text-blue-600 hover:text-blue-800 text-sm">忘记密码?</a> -->
  49. </div>
  50. <!-- 登录按钮 -->
  51. <el-button type="primary" class="w-full h-12 text-base !rounded-button" @click="handleLogin" :loading="loading">
  52. 登录
  53. </el-button>
  54. </div>
  55. <!-- 底部信息 -->
  56. <div class="mt-12 text-center text-gray-500 text-sm">
  57. <p>12356心理援助热线 v2.0.1</p>
  58. <p class="mt-2">© 2024 All Rights Reserved</p>
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. </template>
  64. <script lang="ts" setup>
  65. import { ref } from 'vue';
  66. import { ElMessage } from 'element-plus';
  67. import { getCodeImg } from '@/api/login'
  68. import { User, Lock, View, Hide, Key } from '@element-plus/icons-vue';
  69. import Cookies from 'js-cookie'
  70. import { encrypt, decrypt } from '@/utils/jsencrypt'
  71. import useUserStore from '@/store/modules/user'
  72. import loginImage from '@/assets/images/login.jpg'; // 默认头像 @/assets/images/login.jng
  73. const userStore = useUserStore()
  74. const router = useRouter()
  75. const { proxy } = getCurrentInstance()
  76. const redirect = ref(undefined)
  77. const username = ref('');
  78. const password = ref('');
  79. const captcha = ref('');
  80. const showPassword = ref(false);
  81. const rememberMe = ref(false);
  82. const captchaText = ref('ABCD1234');
  83. const refreshCaptcha = () => {
  84. const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  85. let result = '';
  86. for (let i = 0; i < 8; i++) {
  87. result += chars.charAt(Math.floor(Math.random() * chars.length));
  88. }
  89. captchaText.value = result;
  90. };
  91. const codeUrl = ref('')
  92. const loading = ref(false)
  93. // 验证码开关
  94. const captchaEnabled = ref(true)
  95. const uuid = ref('');
  96. const getCode = () => {
  97. getCodeImg().then((res) => {
  98. captchaEnabled.value =
  99. res.data.captchaEnabled === undefined ? true : res.data.captchaEnabled
  100. if (captchaEnabled.value) {
  101. codeUrl.value = 'data:image/gif;base64,' + res.data.img
  102. uuid.value = res.data.uuid
  103. }
  104. })
  105. }
  106. const handleLogin = () => {
  107. if (!username.value) {
  108. ElMessage.warning('请输入用户名');
  109. return;
  110. }
  111. if (!password.value) {
  112. ElMessage.warning('请输入密码');
  113. return;
  114. }
  115. if (!captcha.value) {
  116. ElMessage.warning('请输入验证码');
  117. return;
  118. }
  119. loading.value = true
  120. if (rememberMe.value) {
  121. Cookies.set('username', username.value, { expires: 30 })
  122. Cookies.set('password', encrypt(password.value), {
  123. expires: 30
  124. })
  125. Cookies.set('rememberMe', rememberMe.value, { expires: 30 })
  126. } else {
  127. // 否则移除
  128. Cookies.remove('username')
  129. Cookies.remove('password')
  130. Cookies.remove('rememberMe')
  131. }
  132. loading.value = true
  133. // 调用action的登录方法
  134. userStore
  135. .login({
  136. username: username.value,
  137. password: password.value,
  138. rememberMe: rememberMe.value,
  139. code: captcha.value,
  140. uuid: uuid.value
  141. })
  142. .then(() => {
  143. router.push({ path: redirect.value || '/' })
  144. })
  145. .catch(() => {
  146. loading.value = false
  147. // 重新获取验证码
  148. if (captchaEnabled.value) {
  149. getCode()
  150. }
  151. })
  152. };
  153. getCode();
  154. </script>
  155. <style scoped>
  156. .el-input :deep(.el-input__wrapper) {
  157. background-color: #f8fafc;
  158. border: 1px solid #e2e8f0;
  159. box-shadow: none !important;
  160. }
  161. .el-input :deep(.el-input__wrapper.is-focus) {
  162. border-color: #409eff;
  163. }
  164. .el-input :deep(.el-input__inner) {
  165. height: 100%;
  166. }
  167. .el-input :deep(.el-input__prefix) {
  168. font-size: 1.25rem;
  169. color: #64748b;
  170. }
  171. </style>