index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. <script setup lang="ts">
  2. import {
  3. ref,
  4. toRaw,
  5. reactive,
  6. watch,
  7. computed,
  8. onMounted,
  9. onBeforeUnmount
  10. } from "vue";
  11. import { useI18n } from "vue-i18n";
  12. import Motion from "./utils/motion";
  13. // import { useRouter } from "vue-router";
  14. // import { router } from "@/router";
  15. import { message } from "@/utils/message";
  16. import { loginRules } from "./utils/rule";
  17. import phone from "./components/phone.vue";
  18. import TypeIt from "@/components/ReTypeit";
  19. import qrCode from "./components/qrCode.vue";
  20. import regist from "./components/regist.vue";
  21. import update from "./components/update.vue";
  22. import { initRouter } from "@/router/utils";
  23. import { Router } from "vue-router";
  24. import { useNav } from "@/layout/hooks/useNav";
  25. import type { FormInstance } from "element-plus";
  26. import { $t, transformI18n } from "@/plugins/i18n";
  27. import { operates, thirdParty } from "./utils/enums";
  28. import { useLayout } from "@/layout/hooks/useLayout";
  29. import { useUserStoreHook } from "@/store/modules/user";
  30. import { loginicon, avatar, illustration } from "./utils/static";
  31. import { ReImageVerify } from "@/components/ReImageVerify";
  32. import { useRenderIcon } from "@/components/ReIcon/src/hooks";
  33. import { useTranslationLang } from "@/layout/hooks/useTranslationLang";
  34. import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
  35. import Cookies from "js-cookie";
  36. import { ShakeDownEncrypt, ShakeDownDecrypt } from "@/utils/CryptoJS";
  37. import dayIcon from "@/assets/svg/day.svg?component";
  38. import darkIcon from "@/assets/svg/dark.svg?component";
  39. import globalization from "@/assets/svg/globalization.svg?component";
  40. import Lock from "@iconify-icons/ri/lock-fill";
  41. import Check from "@iconify-icons/ep/check";
  42. import User from "@iconify-icons/ri/user-3-fill";
  43. defineOptions({
  44. name: "Login"
  45. });
  46. const imgCode = ref("");
  47. // const router = useRouter();
  48. const loading = ref(false);
  49. const checked = ref(false);
  50. const ruleFormRef = ref<FormInstance>();
  51. const currentPage = computed(() => {
  52. return useUserStoreHook().currentPage;
  53. });
  54. const { t } = useI18n();
  55. const { initStorage } = useLayout();
  56. initStorage();
  57. const { dataTheme, dataThemeChange } = useDataThemeChange();
  58. dataThemeChange();
  59. const { title, getDropdownItemStyle, getDropdownItemClass } = useNav();
  60. const { locale, translationCh, translationEn } = useTranslationLang();
  61. const ruleForm = reactive({
  62. username: "",
  63. password: "",
  64. verifyCode: ""
  65. });
  66. const onLogin = async (formEl: FormInstance | undefined) => {
  67. loading.value = true;
  68. const value = {
  69. username: ruleForm.username,
  70. password: ruleForm.password
  71. };
  72. checked.value
  73. ? Cookies.set("isRememberPassword", "true") &&
  74. Cookies.set("RememberAccount", ShakeDownEncrypt(ruleForm))
  75. : Cookies.set("isRememberPassword", "") &&
  76. Cookies.set(
  77. "RememberAccount",
  78. ShakeDownEncrypt({ username: ruleForm.username })
  79. );
  80. if (!formEl) return;
  81. await formEl.validate((valid, fields) => {
  82. if (valid) {
  83. useUserStoreHook()
  84. .loginByUsername(value)
  85. .then((res: any) => {
  86. if (res.status === 1) {
  87. // 获取后端路
  88. initRouter().then((router: Router) => {
  89. router.push("/");
  90. message("登录成功", { type: "success" });
  91. });
  92. } else {
  93. loading.value = false;
  94. message(res.msg, { type: "error" });
  95. }
  96. });
  97. } else {
  98. loading.value = false;
  99. return fields;
  100. }
  101. });
  102. };
  103. /** 使用公共函数,避免`removeEventListener`失效 */
  104. function onkeypress({ code }: KeyboardEvent) {
  105. if (code === "Enter" || code === "NumpadEnter") {
  106. onLogin(ruleFormRef.value);
  107. }
  108. }
  109. onMounted(() => {
  110. Cookies.get("isRememberPassword") &&
  111. (checked.value = true) &&
  112. (ruleForm.password = ShakeDownDecrypt(
  113. Cookies.get("RememberAccount")
  114. ).password);
  115. Cookies.get("RememberAccount") &&
  116. (ruleForm.username = ShakeDownDecrypt(
  117. Cookies.get("RememberAccount")
  118. ).username);
  119. window.document.addEventListener("keypress", onkeypress);
  120. });
  121. onBeforeUnmount(() => {
  122. window.document.removeEventListener("keypress", onkeypress);
  123. });
  124. watch(imgCode, value => {
  125. useUserStoreHook().SET_VERIFYCODE(value);
  126. });
  127. </script>
  128. <template>
  129. <div class="select-none">
  130. <!-- <img :src="bg" class="wave" /> -->
  131. <div class="flex-c absolute right-5 top-3">
  132. <!-- 主题 -->
  133. <!-- <el-switch
  134. v-model="dataTheme"
  135. inline-prompt
  136. :active-icon="dayIcon"
  137. :inactive-icon="darkIcon"
  138. @change="dataThemeChange"
  139. /> -->
  140. <!-- 国际化 -->
  141. <!-- <el-dropdown trigger="click">
  142. <globalization
  143. class="hover:text-primary hover:!bg-[transparent] w-[20px] h-[20px] ml-1.5 cursor-pointer outline-none duration-300"
  144. />
  145. <template #dropdown>
  146. <el-dropdown-menu class="translation">
  147. <el-dropdown-item
  148. :style="getDropdownItemStyle(locale, 'zh')"
  149. :class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
  150. @click="translationCh"
  151. >
  152. <IconifyIconOffline
  153. class="check-zh"
  154. v-show="locale === 'zh'"
  155. :icon="Check"
  156. />
  157. 简体中文
  158. </el-dropdown-item>
  159. <el-dropdown-item
  160. :style="getDropdownItemStyle(locale, 'en')"
  161. :class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
  162. @click="translationEn"
  163. >
  164. <span class="check-en" v-show="locale === 'en'">
  165. <IconifyIconOffline :icon="Check" />
  166. </span>
  167. English
  168. </el-dropdown-item>
  169. </el-dropdown-menu>
  170. </template>
  171. </el-dropdown> -->
  172. </div>
  173. <div class="login-container">
  174. <div class="img">
  175. <!-- <component :is="toRaw(illustration)" /> -->
  176. <img :src="loginicon" class="loginicon" />
  177. </div>
  178. <div class="login-box">
  179. <div class="login-form">
  180. <!-- <avatar class="avatar" /> -->
  181. <img :src="avatar" class="avatar" />
  182. <Motion>
  183. <h2 class="outline-none">
  184. <TypeIt :values="[title]" :cursor="false" :speed="150" />
  185. </h2>
  186. </Motion>
  187. <el-form v-if="currentPage === 0" ref="ruleFormRef" :model="ruleForm" :rules="loginRules" size="large">
  188. <Motion :delay="100">
  189. <el-form-item :rules="[
  190. {
  191. required: true,
  192. message: transformI18n($t('login.usernameReg')),
  193. trigger: 'blur'
  194. }
  195. ]" prop="username">
  196. <el-input clearable v-model="ruleForm.username" :placeholder="t('login.username')"
  197. :prefix-icon="useRenderIcon(User)" />
  198. </el-form-item>
  199. </Motion>
  200. <Motion :delay="150">
  201. <el-form-item prop="password">
  202. <el-input clearable show-password v-model="ruleForm.password" :placeholder="t('login.password')"
  203. :prefix-icon="useRenderIcon(Lock)" />
  204. </el-form-item>
  205. </Motion>
  206. <Motion :delay="200">
  207. <el-form-item prop="verifyCode">
  208. <el-input clearable v-model="ruleForm.verifyCode" :placeholder="t('login.verifyCode')"
  209. :prefix-icon="useRenderIcon('ri:shield-keyhole-line')">
  210. <template v-slot:append>
  211. <ReImageVerify v-model:code="imgCode" />
  212. </template>
  213. </el-input>
  214. </el-form-item>
  215. </Motion>
  216. <Motion :delay="250">
  217. <el-form-item>
  218. <div class="w-full h-[20px] flex justify-between items-center">
  219. <el-checkbox v-model="checked">
  220. {{ t("login.remember") }}
  221. </el-checkbox>
  222. <!-- <el-button
  223. link
  224. type="primary"
  225. @click="useUserStoreHook().SET_CURRENTPAGE(4)"
  226. >
  227. {{ t("login.forget") }}
  228. </el-button> -->
  229. </div>
  230. <el-button class="w-full mt-4" size="default" type="primary" :loading="loading"
  231. @click="onLogin(ruleFormRef)">
  232. {{ t("login.login") }}
  233. </el-button>
  234. </el-form-item>
  235. </Motion>
  236. <!-- <Motion :delay="300">
  237. <el-form-item>
  238. <div class="w-full h-[20px] flex justify-between items-center">
  239. <el-button
  240. v-for="(item, index) in operates"
  241. :key="index"
  242. class="w-full mt-4"
  243. size="default"
  244. @click="useUserStoreHook().SET_CURRENTPAGE(index + 1)"
  245. >
  246. {{ t(item.title) }}
  247. </el-button>
  248. </div>
  249. </el-form-item>
  250. </Motion> -->
  251. </el-form>
  252. <!-- <Motion v-if="currentPage === 0" :delay="350">
  253. <el-form-item>
  254. <el-divider>
  255. <p class="text-gray-500 text-xs">{{ t("login.thirdLogin") }}</p>
  256. </el-divider>
  257. <div class="w-full flex justify-evenly">
  258. <span
  259. v-for="(item, index) in thirdParty"
  260. :key="index"
  261. :title="t(item.title)"
  262. >
  263. <IconifyIconOnline
  264. :icon="`ri:${item.icon}-fill`"
  265. width="20"
  266. class="cursor-pointer text-gray-500 hover:text-blue-400"
  267. />
  268. </span>
  269. </div>
  270. </el-form-item>
  271. </Motion> -->
  272. <!-- 手机号登录 -->
  273. <phone v-if="currentPage === 1" />
  274. <!-- 二维码登录 -->
  275. <qrCode v-if="currentPage === 2" />
  276. <!-- 注册 -->
  277. <regist v-if="currentPage === 3" />
  278. <!-- 忘记密码 -->
  279. <update v-if="currentPage === 4" />
  280. </div>
  281. </div>
  282. </div>
  283. </div>
  284. </template>
  285. <style scoped>
  286. @import url("@/style/login.css");
  287. </style>
  288. <style lang="scss" scoped>
  289. :deep(.el-input-group__append, .el-input-group__prepend) {
  290. padding: 0;
  291. }
  292. .translation {
  293. ::v-deep(.el-dropdown-menu__item) {
  294. padding: 5px 40px;
  295. }
  296. .check-zh {
  297. position: absolute;
  298. left: 20px;
  299. }
  300. .check-en {
  301. position: absolute;
  302. left: 20px;
  303. }
  304. }
  305. .avatar {
  306. margin: 0 auto;
  307. }
  308. </style>