邃芒慧语、照片说话(PC) https://photo.metavatar.cc/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1169 lines
32 KiB

  1. <template>
  2. <div class="login-container">
  3. <div class="Version">Version 1.0.8 test</div>
  4. <div class="videoBox">
  5. <video
  6. src="https://video.metavatar.cc/sv/4aaaaa5e-18832dbb5e6/4aaaaa5e-18832dbb5e6.mp4"
  7. muted
  8. autoplay
  9. loop
  10. ></video>
  11. </div>
  12. <!-- 正常登录 -->
  13. <el-form
  14. v-if="isLogin == 1"
  15. ref="loginFormRef"
  16. :model="loginData"
  17. :rules="loginRules"
  18. class="login-form"
  19. >
  20. <div class="flex text-white items-center py-4">
  21. <span class="text-2xl flex-1 text-center">{{
  22. $t("login.title") + " " + $t("login.login")
  23. }}</span>
  24. <lang-select style="color: #fff" />
  25. </div>
  26. <el-form-item prop="email">
  27. <div class="p-2 text-white">
  28. <svg-icon icon-class="user" />
  29. </div>
  30. <el-input
  31. class="flex-1"
  32. ref="email"
  33. size="large"
  34. v-model="loginData.email"
  35. :placeholder="$t('login.email')"
  36. name="email"
  37. />
  38. </el-form-item>
  39. <el-form-item prop="password">
  40. <span class="p-2 text-white">
  41. <svg-icon icon-class="password" />
  42. </span>
  43. <el-input
  44. class="flex-1"
  45. v-model="loginData.password"
  46. :placeholder="$t('login.password')"
  47. :type="passwordVisible === false ? 'password' : 'input'"
  48. size="large"
  49. name="password"
  50. @keyup.enter="handleLogin"
  51. />
  52. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  53. <svg-icon
  54. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  55. class="text-white cursor-pointer"
  56. />
  57. </span>
  58. </el-form-item>
  59. <!-- 验证码 -->
  60. <el-form-item prop="verifyCode">
  61. <span class="p-2 text-white">
  62. <svg-icon icon-class="verify_code" />
  63. </span>
  64. <el-input
  65. v-model="loginData.verifyCode"
  66. auto-complete="off"
  67. :placeholder="$t('login.verifyCode')"
  68. class="flex-1"
  69. @keyup.enter="handleLogin"
  70. />
  71. <span class="captcha">
  72. <img v-if="showCodeImg" :src="verifyCodeUrl" @click="getCode" />
  73. </span>
  74. </el-form-item>
  75. <el-button
  76. size="default"
  77. :loading="loading"
  78. type="primary"
  79. class="loginBtn"
  80. @click.prevent="handleLogin"
  81. >
  82. <el-icon
  83. v-if="isLogining"
  84. style="margin-right: 10px"
  85. class="is-loading"
  86. >
  87. <svg
  88. viewBox="0 0 1024 1024"
  89. xmlns="http://www.w3.org/2000/svg"
  90. data-v-ea893728=""
  91. >
  92. <path
  93. fill="currentColor"
  94. d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
  95. ></path>
  96. </svg>
  97. </el-icon>
  98. {{ $t("login.loginBtn") }}
  99. </el-button>
  100. <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'">
  101. <div style="margin-bottom: 5px" @click="loginFlag(2)">
  102. <span class="join">{{ $t("login.signUp") }}</span>
  103. </div>
  104. <div>
  105. <span class="join" @click="loginFlag(3)">{{
  106. $t("login.forgetPwd")
  107. }}</span>
  108. </div>
  109. </div>
  110. </el-form>
  111. <!-- 注册账户 -->
  112. <el-form
  113. v-if="isLogin == 2"
  114. ref="loginFormRef"
  115. :model="loginData2"
  116. :rules="loginRules"
  117. class="login-form"
  118. >
  119. <div class="flex text-white items-center py-4">
  120. <span class="text-2xl flex-1 text-center">{{
  121. $t("login.title") + " " + $t("login.register")
  122. }}</span>
  123. <lang-select style="color: #fff" />
  124. </div>
  125. <el-form-item prop="email">
  126. <div class="p-2 text-white">
  127. <svg-icon icon-class="user" />
  128. </div>
  129. <el-input
  130. class="flex-1"
  131. ref="email"
  132. size="large"
  133. v-model="loginData2.email"
  134. :placeholder="$t('login.email')"
  135. name="email"
  136. />
  137. </el-form-item>
  138. <el-form-item prop="password">
  139. <span class="p-2 text-white">
  140. <svg-icon icon-class="password" />
  141. </span>
  142. <el-input
  143. class="flex-1"
  144. v-model="loginData2.password"
  145. :placeholder="$t('login.password')"
  146. :type="passwordVisible === false ? 'password' : 'input'"
  147. size="large"
  148. name="password"
  149. />
  150. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  151. <svg-icon
  152. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  153. class="text-white cursor-pointer"
  154. />
  155. </span>
  156. </el-form-item>
  157. <el-form-item prop="confirmPassword">
  158. <span class="p-2 text-white">
  159. <svg-icon icon-class="password" />
  160. </span>
  161. <el-input
  162. class="flex-1"
  163. v-model="loginData2.confirmPassword"
  164. :placeholder="$t('login.confirmPassword')"
  165. :type="passwordVisible === false ? 'password' : 'input'"
  166. size="large"
  167. name="confirmPassword"
  168. @keyup.enter="handleRegister"
  169. />
  170. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  171. <svg-icon
  172. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  173. class="text-white cursor-pointer"
  174. />
  175. </span>
  176. </el-form-item>
  177. <el-button
  178. size="default"
  179. :loading="loading"
  180. type="primary"
  181. class="loginBtn"
  182. @click.prevent="handleRegister"
  183. >
  184. <el-icon
  185. v-if="isRegistering"
  186. style="margin-right: 10px"
  187. class="is-loading"
  188. >
  189. <svg
  190. viewBox="0 0 1024 1024"
  191. xmlns="http://www.w3.org/2000/svg"
  192. data-v-ea893728=""
  193. >
  194. <path
  195. fill="currentColor"
  196. d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
  197. ></path>
  198. </svg>
  199. </el-icon>
  200. {{ $t("login.registerBtn") }}
  201. </el-button>
  202. <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'">
  203. <div style="margin-bottom: 5px" @click="loginFlag(1)">
  204. <span class="join">{{ $t("login.signIn") }}</span>
  205. </div>
  206. <div>
  207. <span class="join" @click="loginFlag(3)">{{
  208. $t("login.forgetPwd")
  209. }}</span>
  210. </div>
  211. </div>
  212. </el-form>
  213. <!-- 忘记密码 -->
  214. <el-form
  215. v-if="isLogin == 3"
  216. ref="loginFormRef"
  217. :model="loginData3"
  218. :rules="loginRules"
  219. class="login-form"
  220. >
  221. <div class="flex text-white items-center py-4">
  222. <span class="text-2xl flex-1 text-center">{{
  223. $t("login.title") + " " + $t("login.forgetPwdTitle")
  224. }}</span>
  225. <lang-select style="color: #fff" />
  226. </div>
  227. <el-form-item prop="email">
  228. <div class="p-2 text-white">
  229. <svg-icon icon-class="user" />
  230. </div>
  231. <el-input
  232. class="flex-1"
  233. ref="email"
  234. size="large"
  235. v-model="loginData3.email"
  236. :placeholder="$t('login.email')"
  237. name="email"
  238. />
  239. </el-form-item>
  240. <el-button
  241. size="default"
  242. :loading="loading"
  243. type="primary"
  244. class="loginBtn"
  245. @click.prevent="sendEmailforgetPwd"
  246. >
  247. <el-icon
  248. v-if="isRegistering"
  249. style="margin-right: 10px"
  250. class="is-loading"
  251. >
  252. <svg
  253. viewBox="0 0 1024 1024"
  254. xmlns="http://www.w3.org/2000/svg"
  255. data-v-ea893728=""
  256. >
  257. <path
  258. fill="currentColor"
  259. d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
  260. ></path>
  261. </svg>
  262. </el-icon>
  263. {{ $t("login.SendEmail") }}
  264. </el-button>
  265. <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'">
  266. <div style="margin-bottom: 5px" @click="loginFlag(1)">
  267. <span class="join">{{ $t("login.signIn") }}</span>
  268. </div>
  269. </div>
  270. </el-form>
  271. <!-- 重置密码 -->
  272. <el-form
  273. v-if="isLogin == 4"
  274. ref="loginFormRef"
  275. :model="loginData4"
  276. :rules="loginRules"
  277. class="login-form"
  278. >
  279. <div class="flex text-white items-center py-4">
  280. <span class="text-2xl flex-1 text-center">{{
  281. $t("login.title") + " " + $t("login.resetPassword")
  282. }}</span>
  283. <lang-select style="color: #fff" />
  284. </div>
  285. <el-form-item prop="oldPassword">
  286. <span class="p-2 text-white">
  287. <svg-icon icon-class="password" />
  288. </span>
  289. <el-input
  290. class="flex-1"
  291. v-model="loginData4.oldPassword"
  292. :placeholder="$t('login.oldPwd')"
  293. :type="passwordVisible === false ? 'password' : 'input'"
  294. size="large"
  295. name="password"
  296. />
  297. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  298. <svg-icon
  299. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  300. class="text-white cursor-pointer"
  301. />
  302. </span>
  303. </el-form-item>
  304. <el-form-item prop="password">
  305. <span class="p-2 text-white">
  306. <svg-icon icon-class="password" />
  307. </span>
  308. <el-input
  309. class="flex-1"
  310. v-model="loginData4.password"
  311. :placeholder="$t('login.newPwd')"
  312. :type="passwordVisible === false ? 'password' : 'input'"
  313. size="large"
  314. name="password"
  315. />
  316. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  317. <svg-icon
  318. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  319. class="text-white cursor-pointer"
  320. />
  321. </span>
  322. </el-form-item>
  323. <el-form-item prop="confirmPassword4">
  324. <span class="p-2 text-white">
  325. <svg-icon icon-class="password" />
  326. </span>
  327. <el-input
  328. class="flex-1"
  329. v-model="loginData4.confirmPassword4"
  330. :placeholder="$t('login.confirmNewPwd')"
  331. :type="passwordVisible === false ? 'password' : 'input'"
  332. size="large"
  333. name="confirmPassword4"
  334. />
  335. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  336. <svg-icon
  337. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  338. class="text-white cursor-pointer"
  339. />
  340. </span>
  341. </el-form-item>
  342. <el-button
  343. size="default"
  344. :loading="loading"
  345. type="primary"
  346. class="loginBtn"
  347. @click.prevent="resetPwdForm"
  348. >
  349. <el-icon
  350. v-if="isRegistering"
  351. style="margin-right: 10px"
  352. class="is-loading"
  353. >
  354. <svg
  355. viewBox="0 0 1024 1024"
  356. xmlns="http://www.w3.org/2000/svg"
  357. data-v-ea893728=""
  358. >
  359. <path
  360. fill="currentColor"
  361. d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
  362. ></path>
  363. </svg>
  364. </el-icon>
  365. {{ $t("login.confirm") }}
  366. </el-button>
  367. <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'">
  368. <div style="margin-bottom: 5px" @click="loginFlag(1)">
  369. <span class="join">{{ $t("login.signIn") }}</span>
  370. </div>
  371. <div>
  372. <span
  373. class="join"
  374. @click="router.push({ path: 'createVideo', params: {} })"
  375. >{{ $t("login.gohome") }}</span
  376. >
  377. </div>
  378. </div>
  379. </el-form>
  380. <!-- 忘记密码邮件返回 -->
  381. <el-form
  382. v-if="isLogin == 5"
  383. ref="loginFormRef"
  384. :model="loginData5"
  385. :rules="loginRules"
  386. class="login-form"
  387. >
  388. <div class="flex text-white items-center py-4">
  389. <span class="text-2xl flex-1 text-center">{{
  390. $t("login.title") + " " + $t("login.setNewPwd")
  391. }}</span>
  392. <lang-select style="color: #fff" />
  393. </div>
  394. <el-form-item prop="newPwd">
  395. <div class="p-2 text-white">
  396. <svg-icon icon-class="password" />
  397. </div>
  398. <el-input
  399. class="flex-1"
  400. ref="email"
  401. size="large"
  402. v-model="loginData5.newPwd"
  403. :placeholder="$t('login.newPwd')"
  404. :type="passwordVisible === false ? 'password' : 'input'"
  405. name="password"
  406. />
  407. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  408. <svg-icon
  409. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  410. class="text-white cursor-pointer"
  411. />
  412. </span>
  413. </el-form-item>
  414. <el-form-item prop="confirmNewPwd">
  415. <div class="p-2 text-white">
  416. <svg-icon icon-class="password" />
  417. </div>
  418. <el-input
  419. class="flex-1"
  420. ref="email"
  421. size="large"
  422. v-model="loginData5.confirmNewPwd"
  423. :placeholder="$t('login.confirmNewPwd')"
  424. name="password"
  425. :type="passwordVisible === false ? 'password' : 'input'"
  426. />
  427. <span class="mr-2" @click="passwordVisible = !passwordVisible">
  428. <svg-icon
  429. :icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
  430. class="text-white cursor-pointer"
  431. />
  432. </span>
  433. </el-form-item>
  434. <el-button
  435. size="default"
  436. :loading="loading"
  437. type="primary"
  438. class="loginBtn"
  439. @click.prevent="resetPwdEmail"
  440. >
  441. <el-icon
  442. v-if="isRegistering"
  443. style="margin-right: 10px"
  444. class="is-loading"
  445. >
  446. <svg
  447. viewBox="0 0 1024 1024"
  448. xmlns="http://www.w3.org/2000/svg"
  449. data-v-ea893728=""
  450. >
  451. <path
  452. fill="currentColor"
  453. d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
  454. ></path>
  455. </svg>
  456. </el-icon>
  457. {{ $t("login.confirm") }}
  458. </el-button>
  459. <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'">
  460. <div style="margin-bottom: 5px" @click="loginFlag(1)">
  461. <span class="join">{{ $t("login.signIn") }}</span>
  462. </div>
  463. </div>
  464. </el-form>
  465. </div>
  466. </template>
  467. <script setup lang="ts">
  468. import LangSelect from "@/components/LangSelect/index.vue";
  469. import SvgIcon from "@/components/SvgIcon/index.vue";
  470. import {
  471. register,
  472. login,
  473. sendRegisterEmail,
  474. getCodeImgUrl,
  475. sendUpdPwdEmailApi,
  476. resetPwdEmailApi,
  477. resetPwdFormApi,
  478. } from "@/apis/login";
  479. import axios from "axios";
  480. // 状态管理依赖
  481. import { useUserStore } from "@/store/modules/user";
  482. // API依赖
  483. import {
  484. LocationQuery,
  485. LocationQueryValue,
  486. useRoute,
  487. useRouter,
  488. } from "vue-router";
  489. import { useI18n } from "vue-i18n";
  490. const { locale } = useI18n();
  491. const currentLan = ref(locale);
  492. const userStore = useUserStore();
  493. const route = useRoute();
  494. const router = useRouter();
  495. /**
  496. * 按钮loading
  497. */
  498. const loading = ref(false);
  499. /**
  500. * 密码是否可见
  501. */
  502. const passwordVisible = ref(false);
  503. /**
  504. * 验证码图片Base64字符串
  505. */
  506. const verifyCodeUrl = ref();
  507. /**
  508. * 登录/注册 显示哪个表单
  509. */
  510. const isLogin = ref(1);
  511. const showCodeImg = ref(true);
  512. /**
  513. * 登录表单引用
  514. */
  515. const loginFormRef = ref(ElForm);
  516. const isLogining = ref(false);
  517. const isRegistering = ref(false);
  518. const loginData = ref({
  519. email: "",
  520. password: "",
  521. verifyCode: "",
  522. });
  523. const loginData2 = ref({
  524. email: "",
  525. password: "",
  526. confirmPassword: "",
  527. });
  528. const loginData3 = ref({
  529. email: "",
  530. });
  531. const loginData4 = ref({
  532. oldPassword: "",
  533. password: "",
  534. confirmPassword4: "",
  535. });
  536. const loginData5 = ref({
  537. newPwd: "",
  538. confirmNewPwd: "",
  539. });
  540. const loginRules = ref({
  541. email: [
  542. {
  543. required: true,
  544. trigger: "blur",
  545. validator: emailValidator,
  546. },
  547. ],
  548. password: [{ required: true, trigger: "blur", validator: passwordValidator }],
  549. confirmPassword: [
  550. { required: true, trigger: "blur", validator: confirmPasswordValidator },
  551. ],
  552. verifyCode: [
  553. {
  554. required: true,
  555. trigger: "blur",
  556. message:
  557. currentLan.value == "zh-cn"
  558. ? "请输入验证码"
  559. : "Please input verifyCode",
  560. },
  561. ],
  562. oldPassword: [
  563. { required: true, trigger: "blur", validator: passwordValidator },
  564. ],
  565. confirmPassword4: [
  566. { required: true, trigger: "blur", validator: confirmPasswordValidator4 },
  567. ],
  568. newPwd: [{ required: true, trigger: "blur", validator: passwordValidator }],
  569. confirmNewPwd: [
  570. { required: true, trigger: "blur", validator: confirmPasswordValidator5 },
  571. ],
  572. });
  573. watch(currentLan, (newValue, oldValue) => {
  574. const loginRule = loginRules.value;
  575. loginRule.verifyCode[0].message =
  576. newValue == "zh-cn" ? "请输入验证码" : "Please input verifyCode";
  577. setTimeout(() => {
  578. loginFormRef.value.resetFields();
  579. getInfo();
  580. }, 100);
  581. // 切换语言刷新验证码
  582. getCode();
  583. });
  584. /**
  585. * @description: 切换登录/注册状态
  586. */
  587. function loginFlag(type: number) {
  588. isLogin.value = type;
  589. // 切换登录/注册状态刷新验证码
  590. getCode();
  591. setTimeout(() => {
  592. loginFormRef.value.resetFields();
  593. }, 100);
  594. }
  595. /**
  596. * @description: 将账户/密码存储在本地
  597. * @param:email,password
  598. */
  599. function saveInfo(data: any) {
  600. const userInfo = JSON.stringify({
  601. email: data.email,
  602. password: data.password,
  603. });
  604. // 将用户信息加密
  605. const enCodeUserInfo = encodeURI(userInfo);
  606. localStorage.setItem("userInfo", enCodeUserInfo);
  607. }
  608. /**
  609. * @description: 将存储在本地的账户/密码恢复至登录表单
  610. */
  611. function getInfo() {
  612. const data = localStorage.getItem("userInfo");
  613. // 将用户信息解密
  614. const deCodeUserInfo = decodeURI(data as any);
  615. const userInfo = JSON.parse(deCodeUserInfo);
  616. if (userInfo) {
  617. loginData.value.email = userInfo.email ? userInfo.email : "";
  618. loginData.value.password = userInfo.password ? userInfo.password : "";
  619. }
  620. }
  621. //#region 密码校验部分
  622. /**
  623. * 邮箱校验器
  624. */
  625. function emailValidator(rule: any, value: any, callback: any) {
  626. const msg =
  627. currentLan.value == "zh-cn"
  628. ? "邮箱不能为空!"
  629. : "The E-amil can not be empty";
  630. const msg2 =
  631. currentLan.value == "zh-cn" ? "邮箱格式不正确!" : "Incorrect email format";
  632. const emailReg =
  633. /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  634. if (!value) {
  635. callback(new Error(msg));
  636. } else if (!emailReg.test(value)) {
  637. callback(new Error(msg2));
  638. } else {
  639. callback();
  640. }
  641. }
  642. /**
  643. * 密码校验器
  644. */
  645. function passwordValidator(rule: any, value: any, callback: any) {
  646. const msg =
  647. currentLan.value == "zh-cn"
  648. ? "密码不能为空!"
  649. : "The password can not be empty";
  650. const msg2 =
  651. currentLan.value == "zh-cn"
  652. ? "密码至少为6位!"
  653. : "The password can not be less than 6 digits";
  654. if (!value) {
  655. callback(new Error(msg));
  656. } else if (value.length < 6) {
  657. callback(new Error(msg2));
  658. } else {
  659. callback();
  660. }
  661. }
  662. /**
  663. * 确认密码校验器
  664. */
  665. function confirmPasswordValidator(rule: any, value: any, callback: any) {
  666. const msg =
  667. currentLan.value == "zh-cn"
  668. ? "确认密码不能为空!"
  669. : "The Confirm password can not be empty";
  670. const msg2 =
  671. currentLan.value == "zh-cn"
  672. ? "两次输入密码不一致!"
  673. : "Confirm Passward entered should match";
  674. if (!value) {
  675. callback(new Error(msg));
  676. } else if (value !== loginData2.value.password) {
  677. callback(new Error(msg2));
  678. } else {
  679. callback();
  680. }
  681. }
  682. /**
  683. * 确认密码校验器
  684. */
  685. function confirmPasswordValidator4(rule: any, value: any, callback: any) {
  686. const msg =
  687. currentLan.value == "zh-cn"
  688. ? "确认密码不能为空!"
  689. : "The Confirm password can not be empty";
  690. const msg2 =
  691. currentLan.value == "zh-cn"
  692. ? "两次输入密码不一致!"
  693. : "Confirm Passward entered should match";
  694. if (!value) {
  695. callback(new Error(msg));
  696. } else if (value !== loginData4.value.password) {
  697. callback(new Error(msg2));
  698. } else {
  699. callback();
  700. }
  701. }
  702. function confirmPasswordValidator5(rule: any, value: any, callback: any) {
  703. const msg =
  704. currentLan.value == "zh-cn"
  705. ? "确认密码不能为空!"
  706. : "The Confirm password can not be empty";
  707. const msg2 =
  708. currentLan.value == "zh-cn"
  709. ? "两次输入密码不一致!"
  710. : "Confirm Passward entered should match";
  711. if (!value) {
  712. callback(new Error(msg));
  713. } else if (value !== loginData5.value.newPwd) {
  714. callback(new Error(msg2));
  715. } else {
  716. callback();
  717. }
  718. }
  719. //#endregion ----------------------------
  720. // 登录行为
  721. function handleLogin() {
  722. loginFormRef.value.validate((val: any) => {
  723. if (val) {
  724. const data = {
  725. email: loginData.value.email,
  726. password: loginData.value.password,
  727. code: loginData.value.verifyCode,
  728. };
  729. isLogining.value = true;
  730. doLogin(data);
  731. } else {
  732. const msg =
  733. currentLan.value == "zh-cn"
  734. ? "请检查信息格式!"
  735. : "Please check the format !";
  736. ElMessage.error(msg);
  737. return;
  738. }
  739. });
  740. }
  741. // 注册行为
  742. function handleRegister() {
  743. loginFormRef.value.validate((val: any) => {
  744. if (val) {
  745. const data = {
  746. email: loginData2.value.email,
  747. password: loginData2.value.password,
  748. };
  749. isRegistering.value = true;
  750. doRegister(data);
  751. } else {
  752. const msg =
  753. currentLan.value == "zh-cn"
  754. ? "请检查信息格式!"
  755. : "Please check the format !";
  756. ElMessage.error(msg);
  757. return;
  758. }
  759. });
  760. }
  761. //#region 忘记密码 表单3
  762. function sendEmailforgetPwd() {
  763. const msg =
  764. currentLan.value == "zh-cn"
  765. ? "确认信息已发送至您的邮箱,请注意查收"
  766. : "An email has been send to you, Please pay attention to confirm";
  767. loginFormRef.value.validate(async (val: any) => {
  768. if (val) {
  769. const data = {
  770. email: loginData3.value.email,
  771. };
  772. await sendUpdPwdEmailApi(data.email)
  773. .then((res) => {
  774. console.log(res, "res");
  775. ElMessage.success(msg);
  776. })
  777. .catch((err) => {
  778. console.log(err, "err");
  779. ElMessage.error(err.message);
  780. });
  781. } else {
  782. const msg =
  783. currentLan.value == "zh-cn"
  784. ? "请检查信息格式!"
  785. : "Please check the format !";
  786. ElMessage.error(msg);
  787. return;
  788. }
  789. });
  790. }
  791. //#endregion --------------------------
  792. //#region 忘记密码 表单5
  793. function resetPwdEmail() {
  794. loginFormRef.value.validate(async (val: any) => {
  795. if (val) {
  796. try {
  797. const res = await resetPwdEmailApi({
  798. pwd: loginData5.value.newPwd,
  799. ticket: route.query.ticket,
  800. });
  801. localStorage.removeItem("AccessToken");
  802. loginData.value.email = route.query.email + "";
  803. loginData.value.password = "";
  804. isLogin.value = 1;
  805. router.push({ path: "login", query: {} });
  806. } catch (error) {
  807. ElMessage.error(error);
  808. console.log(error);
  809. }
  810. } else {
  811. const msg =
  812. currentLan.value == "zh-cn"
  813. ? "请检查信息格式!"
  814. : "Please check the format !";
  815. ElMessage.error(msg);
  816. return;
  817. }
  818. });
  819. }
  820. //#endregion --------------------------
  821. //#region 重置密码 表单4
  822. function resetPwdForm() {
  823. loginFormRef.value.validate(async (val: any) => {
  824. if (val) {
  825. try {
  826. const res = await resetPwdFormApi({
  827. oldpwd: loginData4.value.oldPassword,
  828. newpwd: loginData4.value.password,
  829. });
  830. localStorage.removeItem("AccessToken");
  831. loginData.value.password = "";
  832. isLogin.value = 1;
  833. router.push({ path: "login", query: {} });
  834. } catch (error) {
  835. ElMessage.error(error.message);
  836. console.log(error);
  837. }
  838. } else {
  839. const msg =
  840. currentLan.value == "zh-cn"
  841. ? "请检查信息格式!"
  842. : "Please check the format !";
  843. ElMessage.error(msg);
  844. return;
  845. }
  846. });
  847. }
  848. //#endregion --------------------------
  849. function getCode() {
  850. showCodeImg.value = false;
  851. axios({
  852. url: getCodeImgUrl,
  853. method: "get",
  854. }).then(() => {
  855. verifyCodeUrl.value = getCodeImgUrl;
  856. showCodeImg.value = true;
  857. });
  858. }
  859. /**
  860. * @description:注册
  861. * @param {Object} data
  862. * @return: data
  863. */
  864. async function doRegister(data: object) {
  865. const msg =
  866. currentLan.value == "zh-cn"
  867. ? "确认信息已发送至您的邮箱,请注意查收"
  868. : "An email has been send to you, Please pay attention to confirm";
  869. await register(data)
  870. .then((res) => {
  871. console.log(res, "res");
  872. isRegistering.value = false;
  873. ElMessage.success(msg);
  874. // 注册成功将账号密码保存到本地
  875. saveInfo(data);
  876. })
  877. .catch((err) => {
  878. // 注册失败刷新验证码
  879. getCode();
  880. isRegistering.value = false;
  881. console.log(err, "err");
  882. ElMessage.error(err.message);
  883. });
  884. }
  885. /**
  886. * @description:登录
  887. * @param {Object} data
  888. * @return: data
  889. */
  890. async function doLogin(data: any) {
  891. const msg =
  892. currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!";
  893. await login(data)
  894. .then((res) => {
  895. console.log(res, "res");
  896. localStorage.setItem("AccessToken", res.data.token);
  897. ElMessage.success(msg);
  898. router.push("/createVideo");
  899. // 注册成功将账号密码保存到本地
  900. saveInfo(data);
  901. isLogining.value = false;
  902. })
  903. .catch((err) => {
  904. console.log(err, "err");
  905. // 登录失败刷新验证码
  906. getCode();
  907. ElMessage.error(err.message);
  908. isLogining.value = false;
  909. if (err.code == 2112) {
  910. reSendEmail(data.email);
  911. }
  912. });
  913. }
  914. /**
  915. * @description:重新发送邮件
  916. * @param {string} email
  917. * @return: data
  918. */
  919. async function reSendEmail(email: string) {
  920. const msg =
  921. currentLan.value == "zh-cn"
  922. ? "确认信息已发送至您的邮箱,请注意查收!"
  923. : "An email has been send to you, Please pay attention to confirm !";
  924. await sendRegisterEmail(email)
  925. .then((res) => {
  926. console.log(res, "res");
  927. ElMessage.success(msg);
  928. })
  929. .catch((err) => {
  930. console.log(err, "err");
  931. ElMessage.error(err.message);
  932. });
  933. }
  934. onMounted(() => {
  935. getCode();
  936. getInfo();
  937. // 重置密码
  938. if (router.currentRoute.value.params.type) {
  939. isLogin.value = Number(router.currentRoute.value.params.type);
  940. }
  941. //有resetPwd则说明是重置密码邮件来的
  942. if (route.query.resetPwd) {
  943. isLogin.value = 5;
  944. // route.query.ticket
  945. }
  946. });
  947. </script>
  948. <style lang="scss" scoped>
  949. .login-container {
  950. position: relative;
  951. width: 100%;
  952. min-height: 100%;
  953. overflow: hidden;
  954. // background-color: #2d3a4b;
  955. .Version {
  956. position: absolute;
  957. bottom: 20px;
  958. right: 20px;
  959. color: #ffffff;
  960. }
  961. .login-form {
  962. position: absolute;
  963. top: 46%;
  964. left: 10%;
  965. width: 520px;
  966. max-width: 100%;
  967. padding: 20px;
  968. overflow: hidden;
  969. backdrop-filter: blur(3px);
  970. background: linear-gradient(
  971. 123.64deg,
  972. rgba(188, 193, 196, 0.1) -22.71%,
  973. rgba(255, 255, 255, 0.039) 70.04%
  974. );
  975. border-radius: 20px;
  976. transform: translateY(-50%);
  977. border: 1px solid #cacaca;
  978. transition: all 0.15s;
  979. .captcha {
  980. position: absolute;
  981. top: 0;
  982. right: 0;
  983. img {
  984. width: 120px;
  985. height: 48px;
  986. cursor: pointer;
  987. }
  988. }
  989. &:hover {
  990. backdrop-filter: blur(7px);
  991. }
  992. }
  993. }
  994. .loginBtn {
  995. width: 100%;
  996. height: 40px;
  997. background: linear-gradient(270deg, #4b61dc, #15d1b8);
  998. transition: all 0.3s;
  999. &:hover {
  1000. transform: scale(1.02);
  1001. }
  1002. }
  1003. .bottomBtnCN {
  1004. display: flex;
  1005. justify-content: space-between;
  1006. align-items: center;
  1007. padding: 0 10px;
  1008. color: #fff;
  1009. text-align: center;
  1010. margin-top: 20px;
  1011. .join {
  1012. cursor: pointer;
  1013. border-bottom: 2px solid #ffffff00;
  1014. padding: 0 3px;
  1015. padding-bottom: 2px;
  1016. transition: all 0.3s;
  1017. &:hover {
  1018. border-bottom: 2px solid #ffffff;
  1019. }
  1020. }
  1021. }
  1022. .bottomBtnEN {
  1023. padding: 0 10px;
  1024. color: #fff;
  1025. text-align: center;
  1026. margin-top: 20px;
  1027. .join {
  1028. cursor: pointer;
  1029. border-bottom: 2px solid #ffffff00;
  1030. padding: 0 3px;
  1031. padding-bottom: 2px;
  1032. transition: all 0.3s;
  1033. &:hover {
  1034. border-bottom: 2px solid #ffffff;
  1035. }
  1036. }
  1037. }
  1038. .videoBox {
  1039. position: absolute;
  1040. top: 0;
  1041. left: 0;
  1042. width: 100%;
  1043. height: 100%;
  1044. z-index: -1;
  1045. video {
  1046. width: 100%;
  1047. height: 100%;
  1048. object-fit: fill;
  1049. }
  1050. }
  1051. .el-form-item {
  1052. background: rgb(0 0 0 / 10%);
  1053. border: 1px solid #ffffff2d;
  1054. border-radius: 5px;
  1055. }
  1056. .el-input {
  1057. background: transparent;
  1058. // 子组件 scoped 无效,使用 :deep
  1059. :deep(.el-input__wrapper) {
  1060. padding: 0;
  1061. background: transparent;
  1062. box-shadow: none;
  1063. .el-input__inner {
  1064. color: #fff;
  1065. background: transparent;
  1066. border: 0;
  1067. border-radius: 0;
  1068. caret-color: #fff;
  1069. &:-webkit-autofill {
  1070. box-shadow: 0 0 0 1000px transparent inset !important;
  1071. -webkit-text-fill-color: #fff !important;
  1072. }
  1073. // 设置输入框自动填充的延迟属性
  1074. &:-webkit-autofill,
  1075. &:-webkit-autofill:hover,
  1076. &:-webkit-autofill:focus,
  1077. &:-webkit-autofill:active {
  1078. transition: color 99999s ease-out, background-color 99999s ease-out;
  1079. transition-delay: 99999s;
  1080. }
  1081. }
  1082. }
  1083. }
  1084. @keyframes rotate {
  1085. from {
  1086. transform: rotate(0deg);
  1087. }
  1088. to {
  1089. transform: rotate(360deg);
  1090. }
  1091. }
  1092. </style>