Login.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <template>
  2. <Teleport to="body">
  3. <div class="login-layer">
  4. <div class="login-box">
  5. <span class="close" @click="emits('close')"><i class="iconfont icon-close"></i></span>
  6. <div class="area">
  7. <h4>用户登录</h4>
  8. <div class="input">
  9. <span class="icon">
  10. <i class="iconfont icon-user"></i>
  11. </span>
  12. <input type="text" v-model.trim="username" />
  13. <div class="tips" v-show="errors.username">{{ errors.username }}</div>
  14. </div>
  15. <div class="input">
  16. <span class="icon">
  17. <i class="iconfont icon-password"></i>
  18. </span>
  19. <input :type="showpass ? 'text' : 'password'" v-model.trim="password" />
  20. <div class="tips" v-show="errors.password">{{ errors.password }}</div>
  21. <span class="showpass" @click="showpass = !showpass">
  22. <i class="iconfont" :class="[showpass ? 'icon-log_eye_selected' : 'icon-log_eye_normal']"></i>
  23. </span>
  24. </div>
  25. <div class="remember">
  26. <div @click="remember = !remember">
  27. <div class="checkbox" :class="{ checked: remember }"></div>
  28. <div class="checkbox-label">记住密码</div>
  29. </div>
  30. </div>
  31. <div class="button">
  32. <button type="submit" @click="onLogin">登录</button>
  33. <div class="tips" v-show="errors.message">{{ errors.message }}</div>
  34. </div>
  35. <div class="links">
  36. <a href="http://test.4dkankan.com/#/login/forget?from=%2F">忘记密码</a>
  37. <a href="http://test.4dkankan.com/#/login/register?from=%2F">官网注册</a>
  38. </div>
  39. </div>
  40. </div>
  41. </div>
  42. </Teleport>
  43. </template>
  44. <script setup>
  45. import { ref, onMounted } from 'vue'
  46. import { http } from '@/utils/request'
  47. import common from '@/utils/common'
  48. const emits = defineEmits(['close', 'user'])
  49. const showpass = ref(false)
  50. const remember = ref(false)
  51. const username = ref('')
  52. const password = ref('')
  53. const errors = ref({})
  54. const onLogin = () => {
  55. errors.value = {}
  56. if (!username.value) {
  57. errors.value.username = '手机号码不能为空'
  58. return
  59. }
  60. if (!/^1[3-9]\d{9}$/.test(username.value)) {
  61. errors.value.username = '请输入正确手机号'
  62. return
  63. }
  64. if (!password.value) {
  65. errors.value.password = '密码不能为空'
  66. return
  67. }
  68. http.post(`smart-site/fdLogin`, {
  69. password: common.encodeStr(Base64.encode(password.value)),
  70. phoneNum: username.value,
  71. rememberMe: remember.value,
  72. randomcode: '1234',
  73. })
  74. .then(response => {
  75. if (response.success) {
  76. if (remember.value) {
  77. localStorage.setItem('remember', true)
  78. localStorage.setItem('username', username.value)
  79. localStorage.setItem('password', password.value)
  80. } else {
  81. localStorage.removeItem('remember')
  82. localStorage.removeItem('username')
  83. localStorage.removeItem('password')
  84. }
  85. localStorage.setItem('token', response.data.token)
  86. emits('user', {
  87. head: response.data.user.head,
  88. nickName: response.data.user.nickName,
  89. })
  90. emits('close')
  91. } else {
  92. errors.value.message = response.message
  93. }
  94. })
  95. .catch(() => {
  96. alert('服务器连接失败')
  97. })
  98. }
  99. onMounted(() => {
  100. if (localStorage.getItem('remember')) {
  101. remember.value = true
  102. username.value = localStorage.getItem('username') || ''
  103. password.value = localStorage.getItem('password') || ''
  104. }
  105. })
  106. </script>
  107. <style lang="scss" scoped>
  108. .login-layer {
  109. position: absolute;
  110. left: 0;
  111. top: 0;
  112. width: 100%;
  113. height: 100%;
  114. z-index: 9999;
  115. display: flex;
  116. align-items: center;
  117. justify-content: center;
  118. }
  119. .login-box {
  120. padding: 0 40px;
  121. position: absolute;
  122. width: 440px;
  123. height: 482px;
  124. background: rgba(27, 27, 28, 0.8);
  125. box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
  126. border-radius: 4px 4px 4px 4px;
  127. opacity: 1;
  128. border: 1px solid #000000;
  129. backdrop-filter: blur(4px);
  130. color: #fff;
  131. h4 {
  132. font-size: 24px;
  133. color: #999999;
  134. font-weight: 400;
  135. padding-bottom: 20px;
  136. border-bottom: solid 1px rgba(255, 255, 255, 0.16);
  137. margin-top: 60px;
  138. margin-bottom: 0px;
  139. }
  140. .close {
  141. cursor: pointer;
  142. position: absolute;
  143. top: 20px;
  144. right: 20px;
  145. color: rgba(255, 255, 255, 0.8);
  146. i {
  147. font-size: 14px;
  148. }
  149. }
  150. .tips {
  151. position: absolute;
  152. left: 0;
  153. top: 38px;
  154. font-size: 12px;
  155. color: rgba(250, 85, 85, 1);
  156. }
  157. .input {
  158. position: relative;
  159. height: 34px;
  160. margin-top: 30px;
  161. background: rgba(255, 255, 255, 0.1);
  162. border-radius: 4px 4px 4px 4px;
  163. border: 1px solid rgba(255, 255, 255, 0.2);
  164. display: flex;
  165. .icon {
  166. position: relative;
  167. width: 36px;
  168. height: 100%;
  169. display: flex;
  170. align-items: center;
  171. justify-content: center;
  172. &::after {
  173. content: '';
  174. position: absolute;
  175. right: 0;
  176. top: 50%;
  177. width: 1px;
  178. height: 20px;
  179. margin-top: -10px;
  180. background-color: rgba(255, 255, 255, 0.2);
  181. }
  182. }
  183. .showpass {
  184. cursor: pointer;
  185. position: absolute;
  186. top: 50%;
  187. right: 10px;
  188. transform: translateY(-50%);
  189. }
  190. input {
  191. flex: 1;
  192. width: 100%;
  193. height: 100%;
  194. border: none;
  195. background: transparent;
  196. outline: none;
  197. padding: 0 10px;
  198. color: #fff;
  199. }
  200. }
  201. .remember {
  202. margin-top: 30px;
  203. > div {
  204. cursor: pointer;
  205. display: inline-block;
  206. position: relative;
  207. white-space: nowrap;
  208. }
  209. }
  210. .checkbox {
  211. display: inline-block;
  212. position: relative;
  213. width: 16px;
  214. height: 16px;
  215. margin-right: 5px;
  216. &::before {
  217. content: '';
  218. border: 1px solid #0076f6;
  219. border-radius: 2px;
  220. width: 16px;
  221. height: 16px;
  222. position: absolute;
  223. left: 0px;
  224. top: 0;
  225. display: inline-block;
  226. }
  227. &.checked {
  228. &::after {
  229. left: 4px;
  230. top: 7px;
  231. position: absolute;
  232. display: table;
  233. border: 2px solid #0076f6;
  234. border-top: 0;
  235. border-left: 0;
  236. transform: rotate(45deg) translate(-50%, -50%);
  237. opacity: 1;
  238. transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s;
  239. width: 6px;
  240. height: 8px;
  241. content: ' ';
  242. }
  243. }
  244. }
  245. .checkbox-label {
  246. display: inline-block;
  247. vertical-align: 3px;
  248. }
  249. .button {
  250. position: relative;
  251. margin-top: 40px;
  252. button {
  253. cursor: pointer;
  254. color: #fff;
  255. width: 100%;
  256. height: 34px;
  257. background: #0076f6;
  258. border-radius: 2px;
  259. border: none;
  260. outline: none;
  261. }
  262. .tips {
  263. text-align: center;
  264. top: 40px;
  265. width: 100%;
  266. }
  267. }
  268. .links {
  269. margin-top: 40px;
  270. display: flex;
  271. justify-content: space-between;
  272. a {
  273. color: #0076f6;
  274. text-decoration: none;
  275. &:hover {
  276. text-decoration: underline;
  277. }
  278. }
  279. }
  280. }
  281. </style>