index.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. <template>
  2. <div class="system-layer" :style="{ backgroundImage: `url(${appConstant.banner})` }">
  3. <div class="content">
  4. <div class="login-layer">
  5. <div class="content">
  6. <div class="info">
  7. <img src="@/app/xmfire/images/banner@2x.png" />
  8. <span>{{ dateFormat(currentDate, "yyyy-MM-dd hh:mm:ss") }}</span>
  9. </div>
  10. <el-form class="panel login" :model="form" @submit.stop>
  11. <img :src="appConstant.ico" />
  12. <h2>{{ appConstant.title }}</h2>
  13. <el-form-item class="panel-form-item">
  14. <p class="err-info">{{ verification.phone }}</p>
  15. <el-input
  16. :maxlength="11"
  17. v-model.trim="form.phone"
  18. placeholder="手机号"
  19. @keydown.enter="submitClick"
  20. ></el-input>
  21. </el-form-item>
  22. <el-form-item class="panel-form-item">
  23. <p class="err-info">{{ verification.psw }}</p>
  24. <el-input
  25. v-model="form.psw"
  26. :maxlength="16"
  27. placeholder="密码"
  28. :type="flag ? 'password' : 'text'"
  29. @keydown.enter="submitClick"
  30. >
  31. <template v-slot:suffix>
  32. <img
  33. v-if="flag"
  34. @click="flag = !flag"
  35. style="width: 20px; margin: 15px"
  36. src="@/assets/image/pasword.png"
  37. alt=""
  38. />
  39. <el-icon :size="20" @click="flag = !flag" class="icon-style" v-else>
  40. <View />
  41. </el-icon>
  42. </template>
  43. </el-input>
  44. </el-form-item>
  45. <el-form-item class="panel-form-item code-form-item">
  46. <p class="err-info">{{ verification.code }}</p>
  47. <el-input
  48. v-model="form.code"
  49. placeholder="验证码"
  50. @keydown.enter="submitClick"
  51. class="code-input"
  52. >
  53. <template v-slot:append>
  54. <img :src="codeImg" class="code-img" @click="refer" />
  55. </template>
  56. </el-input>
  57. </el-form-item>
  58. <el-form-item class="panel-form-item">
  59. <el-button type="primary" class="fill" @click="submitClick">登录</el-button>
  60. </el-form-item>
  61. <div class="more">
  62. <a @click="$router.push({ name: 'forget' })">忘记密码</a>
  63. </div>
  64. </el-form>
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. </template>
  70. <script lang="ts" setup>
  71. import { reactive, watch, ref, computed, onUnmounted } from "vue";
  72. import { openErrorMsg, baseURL, getCode } from "@/request";
  73. import { PHONE } from "@/constant/REG";
  74. import { guid, strToParams, dateFormat } from "@/util";
  75. import { RouteName, router } from "@/router";
  76. import { login } from "@/store/system";
  77. import { appConstant } from "@/app";
  78. import { user } from "@/store/user";
  79. const currentDate = ref(new Date());
  80. const interval = setInterval(() => {
  81. currentDate.value = new Date();
  82. });
  83. onUnmounted(() => clearInterval(interval));
  84. // 是否显示明文密码
  85. const flag = ref(true);
  86. // 表单
  87. const form = reactive({
  88. phone: localStorage.getItem("userName") || "",
  89. psw: localStorage.getItem("password") || "",
  90. code: "",
  91. remember: import.meta.env.DEV || localStorage.getItem("remember") === "1",
  92. });
  93. const verification = reactive({ phone: "", psw: "", code: "" });
  94. // 验证
  95. watch(
  96. form,
  97. () => {
  98. console.log("form", form);
  99. if (!form.phone) {
  100. verification.phone = "请输入手机号";
  101. } else if (form.phone == "88888888888") {
  102. verification.phone = "";
  103. } else {
  104. verification.phone = PHONE.REG.test(form.phone) ? "" : PHONE.tip;
  105. }
  106. if (!form.psw) {
  107. verification.psw = "请输入密码";
  108. } else {
  109. verification.psw = "";
  110. }
  111. if (!form.code.trim()) {
  112. verification.code = "请输入验证码";
  113. } else {
  114. verification.code = "";
  115. }
  116. },
  117. { immediate: true }
  118. );
  119. // 图片验证码
  120. const imgKey = ref(guid());
  121. const refer = () => (imgKey.value = guid());
  122. const codeImg = computed(() => baseURL + getCode + "?key=" + imgKey.value);
  123. // 表单提交
  124. const submitClick = async () => {
  125. if (verification.phone && verification.phone !== "88888888888") {
  126. return openErrorMsg(verification.phone);
  127. }
  128. if (verification.psw) return openErrorMsg(verification.psw);
  129. if (verification.code) return openErrorMsg(verification.code);
  130. try {
  131. await login({ phoneNum: form.phone, code: form.code, password: form.psw });
  132. if (form.remember) {
  133. localStorage.setItem("userName", form.phone);
  134. localStorage.setItem("password", form.psw);
  135. localStorage.setItem("remember", "1");
  136. } else {
  137. localStorage.setItem("userName", "");
  138. localStorage.setItem("password", "");
  139. localStorage.setItem("remember", "0");
  140. }
  141. const params = strToParams(window.location.search);
  142. if ("redirect" in params) {
  143. const url = new URL(unescape(params.redirect));
  144. url.searchParams.delete("token");
  145. url.searchParams.append("token", user.value.token);
  146. window.location.replace(url);
  147. } else {
  148. router.replace({ name: RouteName.scene, params: { caseId: 360 } });
  149. }
  150. } catch (e) {
  151. console.error(e);
  152. return refer();
  153. }
  154. };
  155. </script>
  156. <style lang="scss" scoped>
  157. .system-layer {
  158. width: 100%;
  159. min-height: 100%;
  160. display: flex;
  161. flex-direction: row;
  162. align-items: center;
  163. justify-content: center;
  164. background: no-repeat left bottom;
  165. background-size: cover;
  166. }
  167. .content {
  168. display: flex;
  169. justify-content: center;
  170. align-items: flex-start;
  171. }
  172. .login-layer {
  173. text-align: right;
  174. }
  175. .content {
  176. display: flex;
  177. justify-content: center;
  178. align-items: flex-start;
  179. }
  180. .info {
  181. color: #fff;
  182. flex: none;
  183. text-align: left;
  184. position: relative;
  185. height: 100%;
  186. pointer-events: none;
  187. span {
  188. position: absolute;
  189. bottom: 20px;
  190. left: 50%;
  191. transform: translateX(-50%);
  192. font-size: 18px;
  193. color: #fff;
  194. }
  195. img {
  196. height: 562px;
  197. }
  198. h1 {
  199. font-size: 2.8rem;
  200. line-height: 3.7rem;
  201. margin-bottom: 0.7rem;
  202. }
  203. p {
  204. font-size: 2rem;
  205. line-height: 2.2rem;
  206. }
  207. }
  208. .top-text {
  209. margin-bottom: 50px;
  210. pointer-events: none;
  211. height: 153px;
  212. min-width: 1200px;
  213. img {
  214. position: absolute;
  215. right: 0;
  216. }
  217. }
  218. .login {
  219. width: 380px;
  220. padding: 40px 40px 30px;
  221. position: relative;
  222. display: inline-block;
  223. h2 {
  224. padding-left: 0;
  225. padding-bottom: 0;
  226. border-bottom: none;
  227. margin-bottom: 2.14rem;
  228. span {
  229. color: #646566;
  230. font-size: 1.33rem;
  231. margin-top: 0.71rem;
  232. display: block;
  233. }
  234. }
  235. .panel-form-item {
  236. padding-left: 0;
  237. padding-right: 0;
  238. .icon-style {
  239. margin-right: 14px;
  240. font-size: 20px;
  241. line-height: 50px;
  242. }
  243. }
  244. .more a:first-child::after {
  245. content: "";
  246. position: absolute;
  247. right: -5px;
  248. width: 1px;
  249. height: 8px;
  250. background: #dcdee0;
  251. top: 50%;
  252. transform: translateY(-50%);
  253. }
  254. }
  255. .code-img {
  256. width: 100%;
  257. height: 100%;
  258. // object-fit: cover;
  259. }
  260. </style>
  261. <style lang="scss">
  262. .system-layer .panel {
  263. background: rgba(255, 255, 255, 0.7);
  264. box-shadow: 0px 2px 20px 0px rgba(5, 38, 38, 0.15);
  265. width: 380px;
  266. padding: 40px 40px 30px;
  267. text-align: initial;
  268. text-align: center;
  269. border-radius: 0;
  270. img {
  271. width: 100px;
  272. }
  273. h2 {
  274. color: #323233;
  275. font-size: 1.4rem;
  276. margin-bottom: 2.14rem;
  277. font-weight: normal;
  278. padding-left: 0;
  279. border-bottom: 0;
  280. text-align: center;
  281. }
  282. .panel-form-item {
  283. position: relative;
  284. padding-bottom: 2.14rem;
  285. margin: 0;
  286. padding-left: 0;
  287. padding-right: 0;
  288. &.remember {
  289. padding: 0;
  290. }
  291. .err-info {
  292. position: absolute;
  293. top: 100%;
  294. left: 0;
  295. font-size: 1rem;
  296. line-height: 2.14rem;
  297. color: #fa5555;
  298. }
  299. }
  300. .more {
  301. text-align: center;
  302. a {
  303. color: #323233;
  304. line-height: 21px;
  305. font-size: 16px;
  306. margin: 0 5px;
  307. position: relative;
  308. text-decoration: none;
  309. cursor: pointer;
  310. }
  311. }
  312. }
  313. .panel-form-item .el-select {
  314. width: 100%;
  315. }
  316. .panel-form-item .el-button,
  317. .panel-form-item .el-input__inner {
  318. height: 50px;
  319. font-size: 1.14rem;
  320. }
  321. .panel-form-item .el-button {
  322. line-height: 26px;
  323. font-weight: bold;
  324. font-size: 16px;
  325. }
  326. .panel-form-item .el-form-item__label {
  327. line-height: 50px;
  328. }
  329. .login .code-form-item .el-input {
  330. display: flex;
  331. }
  332. .login .code-form-item .el-input-group__append {
  333. flex: none;
  334. margin-left: 10px;
  335. width: 95px;
  336. display: flex;
  337. align-items: center;
  338. justify-content: center;
  339. padding: 0;
  340. }
  341. .login .code-form-item .el-input__inner {
  342. flex: 1;
  343. }
  344. .login .code-form-item .el-input-group__append,
  345. .login .code-form-item .el-input__inner {
  346. border-radius: 4px;
  347. }
  348. input[type="password"]::-ms-reveal {
  349. display: none;
  350. }
  351. </style>