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.

1219 lines
26 KiB

4 weeks ago
4 weeks ago
1 month ago
  1. <template>
  2. <view class="login-registration-container">
  3. <!-- 自定义导航栏 -->
  4. <view
  5. class="custom-navbar"
  6. :style="{ paddingTop: safeAreaInsets?.top + 'px' }"
  7. >
  8. <!-- <view class="nav-left">
  9. <text class="back-btn" @click="goToIndex"></text>
  10. </view> -->
  11. <view class="nav-right">
  12. <image
  13. @click="goToService"
  14. class="icons"
  15. src="../../../static/icons/Headset.png"
  16. alt="联系客服"
  17. />
  18. <image
  19. class="icons"
  20. @click="goToIndex"
  21. src="../../../static/icons/Frame.png"
  22. alt="返回首页"
  23. />
  24. </view>
  25. </view>
  26. <!-- Logo -->
  27. <!-- <image class="logo" src="/static/logo.png" mode="aspectFit"></image> -->
  28. <!-- 欢迎语 -->
  29. <text class="welcome-text">登录DeepChart</text>
  30. <!-- 邮箱/手机号切换 -->
  31. <view class="switch-container">
  32. <text
  33. class="switch-item"
  34. :class="{ active: switchType === 'User' }"
  35. @click="switchUser"
  36. >用户名</text
  37. >
  38. <text
  39. class="switch-item"
  40. :class="{ active: switchType === 'Phone' }"
  41. @click="switchPhone"
  42. >手机号</text
  43. ><text
  44. class="switch-item"
  45. :class="{ active: switchType === 'Email' }"
  46. @click="switchEmail"
  47. >邮箱</text
  48. >
  49. </view>
  50. <!-- 输入框 -->
  51. <view class="input-container">
  52. <view v-if="switchType === 'User'">
  53. <!-- 修改邮箱输入框容器将图标包含在内 -->
  54. <view class="input-with-icon">
  55. <image
  56. class="input-icon"
  57. src="../../../static/icons/People-safe.png"
  58. alt=""
  59. />
  60. <input
  61. class="input-field"
  62. type="text"
  63. placeholder="请输入DeepChart ID"
  64. v-model="deepChartID"
  65. />
  66. </view>
  67. <view class="input-with-icon">
  68. <image
  69. class="input-icon"
  70. src="../../../static/icons/Unlock.png"
  71. alt=""
  72. />
  73. <input
  74. class="input-field"
  75. type="text"
  76. placeholder="请输入密码"
  77. v-model="password"
  78. />
  79. </view>
  80. </view>
  81. <view v-if="switchType === 'Email'">
  82. <!-- 修改邮箱输入框容器将图标包含在内 -->
  83. <view class="input-with-icon">
  84. <image
  85. class="input-icon"
  86. src="../../../static/icons/Mail.png"
  87. alt=""
  88. />
  89. <input
  90. class="input-field"
  91. type="text"
  92. placeholder="请输入邮箱"
  93. v-model="email"
  94. />
  95. <view>
  96. <button
  97. class="send-code-btn-email"
  98. :disabled="isCodeBtnDisabled"
  99. :class="{ 'send-code-btn-disabled': isCodeBtnDisabled }"
  100. @click="sendCode"
  101. >
  102. <text
  103. class="send-code-text"
  104. :class="{ 'send-code-btn-disabled-text': isCodeBtnDisabled }"
  105. >{{ codeBtnText }}</text
  106. >
  107. </button>
  108. </view>
  109. </view>
  110. <view class="input-with-icon">
  111. <image
  112. class="input-icon"
  113. src="../../../static/icons/Text-recognition.png"
  114. alt=""
  115. />
  116. <input
  117. class="input-field"
  118. type="text"
  119. placeholder="请输入验证码"
  120. v-model="verifyCode"
  121. />
  122. </view>
  123. </view>
  124. <view v-if="switchType === 'Phone'" class="phone-input-container">
  125. <view class="country-code-selector" @click="showCountryPicker">
  126. <image
  127. class="country-flag-img"
  128. src="../../../static/icons/Iphone.png"
  129. mode="aspectFit"
  130. ></image>
  131. <text class="country-code">{{ selectedCountry.code }}</text>
  132. <!-- <text class="arrow-down"></text> -->
  133. </view>
  134. <input
  135. class="input-field phone-input"
  136. type="number"
  137. placeholder="输入手机号"
  138. v-model="phone"
  139. @input="onPhoneInput"
  140. />
  141. <view>
  142. <button
  143. class="send-code-btn"
  144. :disabled="isCodeBtnDisabled"
  145. :class="{ 'send-code-btn-disabled': isCodeBtnDisabled }"
  146. @click="sendCode"
  147. >
  148. <text
  149. class="send-code-text"
  150. :class="{ 'send-code-btn-disabled-text': isCodeBtnDisabled }"
  151. >{{ codeBtnText }}</text
  152. >
  153. </button>
  154. </view>
  155. </view>
  156. <view v-if="switchType === 'Phone'" class="input-with-icon">
  157. <image
  158. class="input-icon"
  159. src="../../../static/icons/Text-recognition.png"
  160. alt=""
  161. />
  162. <input
  163. class="input-field"
  164. type="text"
  165. placeholder="请输入验证码"
  166. v-model="verifyCode"
  167. />
  168. </view>
  169. </view>
  170. <!-- 用户协议 -->
  171. <view @click="changeCheckbox" class="agreement-container-one">
  172. <image class="checkbox" :src="checkboxUrl"></image>
  173. <text class="agreement-text-one"
  174. >接受 <text class="link" @click="openAgreement">用户协议</text>
  175. <text class="link" @click="openPrivacy">隐私政策</text></text
  176. >
  177. </view>
  178. <view v-if="switchType === 'User'" class="agreement-container">
  179. <text class="agreement-text"
  180. ><text @click="recoverPassword">忘记ID/密码</text>
  181. </text>
  182. </view>
  183. <view v-else class="agreement-container">
  184. <text class="agreement-text">
  185. <!-- 添加占位元素防止页面变形 -->
  186. <text style="visibility: hidden">占位符</text>
  187. </text>
  188. </view>
  189. <!-- 注册按钮 -->
  190. <button class="register-btn" @click="Login">
  191. <text v-if="!isLoading">登录</text>
  192. <image
  193. v-else
  194. class="icons-rotation"
  195. src="../../../static/icons/loading.png"
  196. ></image>
  197. </button>
  198. <!-- 或者 -->
  199. <text class="or-text" @click="goToRegistration"
  200. >如果您还没有账号点击注册
  201. <image class="to-icon" src="../../../static/icons/To.png"></image>
  202. </text>
  203. <!-- 第三方登录 -->
  204. <view class="third-party-login">
  205. <view
  206. v-if="isAppleDevice"
  207. class="third-party-btn"
  208. @click="loginWithApple"
  209. >
  210. <image
  211. class="apple-icon"
  212. src="../../../static/icons/appleIcons.png"
  213. mode="aspectFit"
  214. ></image>
  215. <text class="third-party-text">通过 Apple 登录 </text>
  216. </view>
  217. <view class="third-party-btn" @click="loginWithGoogle">
  218. <image
  219. class="google-icon"
  220. src="../../../static/icons/GoogleIcons.png"
  221. mode="aspectFit"
  222. ></image>
  223. <text class="third-party-text">通过 Google 登录</text>
  224. </view>
  225. </view>
  226. <!-- 同意弹窗 -->
  227. <uniPopup ref="agreementPopup" type="dialog">
  228. <view class="popup-content">
  229. <text class="popup-message"
  230. >请阅读并同意<text @click="openAgreement" class="popup-message-link"
  231. >服务协议</text
  232. ><text @click="openPrivacy" class="popup-message-link"
  233. >隐私权限</text
  234. >
  235. </text>
  236. <view class="button-group">
  237. <button class="cancel-button" @click="handleCancel">
  238. <text class="cancel-text">取消</text>
  239. </button>
  240. <button class="agree-button" @click="handleAgree">
  241. <text class="agree-text">同意</text>
  242. </button>
  243. </view>
  244. </view>
  245. </uniPopup>
  246. <footerBar class="static-footer" :type="type"></footerBar>
  247. </view>
  248. </template>
  249. <script setup>
  250. import { computed, ref } from "vue";
  251. // 导入完整的国家列表
  252. import countryList from "./list.js";
  253. import footerBar from "../../../components/footerBar";
  254. import uniPopupDialogVue from "../../../uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue";
  255. import uniPopup from "../../../uni_modules/uni-popup/components/uni-popup/uni-popup.vue";
  256. import { verificationPhone, verificationEmail } from "../login/verification";
  257. import {
  258. LoginApi,
  259. SendEmailCodeApi,
  260. SendPhoneCodeApi,
  261. } from "../../../api/start/login";
  262. import { useUserStore } from "../../../stores/modules/userInfo";
  263. import { useDeviceStore } from "../../../stores/modules/deviceInfo";
  264. const deepChartID = ref("");
  265. const type = ref("");
  266. const email = ref("");
  267. const password = ref("");
  268. const country = ref("+86");
  269. const phone = ref("");
  270. const agreed = ref(false);
  271. const switchType = ref("User"); // 默认是邮箱注册
  272. const { safeAreaInsets } = uni.getSystemInfoSync();
  273. const codeBtnText = ref("获取验证码");
  274. const isCodeBtnDisabled = ref(false); // 添加验证码按钮禁用状态
  275. const checkboxUrl = ref("../../../static/icons/Check-one-false.png");
  276. const verifyCode = ref("");
  277. const account = ref("");
  278. const isLoading = ref(false);
  279. const deviceStore = useDeviceStore();
  280. const isAppleDevice = computed(() => {
  281. if (deviceStore.deviceInfo.brand) {
  282. return deviceStore.deviceInfo.brand.toLowerCase() === "apple";
  283. }
  284. if (deviceStore.deviceInfo.system) {
  285. return deviceStore.deviceInfo.system.includes("ios");
  286. }
  287. return false;
  288. });
  289. // 使用从list.js导入的完整国家列表数据
  290. const countries = ref(
  291. countryList.list.map((item) => ({
  292. name: item.name,
  293. code: `+${item.tel}`,
  294. flag: item.flag,
  295. short: item.short,
  296. en: item.en,
  297. }))
  298. );
  299. // 默认选中的国家(中国)
  300. const selectedCountry = ref(
  301. countries.value.find((country) => country.short === "CN") ||
  302. countries.value[0]
  303. );
  304. // 显示国家选择器
  305. function showCountryPicker() {
  306. uni.showActionSheet({
  307. itemList: countries.value.map(
  308. (country) => `${country.name} ${country.code}`
  309. ),
  310. success: function (res) {
  311. selectedCountry.value = countries.value[res.tapIndex];
  312. country.value = selectedCountry.value.code;
  313. },
  314. });
  315. }
  316. function goToIndex() {
  317. // 返回上一页
  318. uni.navigateTo({
  319. url: "/pages/home/home",
  320. });
  321. }
  322. function goToService() {
  323. // 返回上一页
  324. uni.navigateTo({
  325. url: "/pages/customerServicePlatform/csPlatformIndex",
  326. });
  327. }
  328. function switchUser() {
  329. // 切换到手机注册
  330. switchType.value = "User";
  331. password.value = "";
  332. verifyCode.value = "";
  333. }
  334. function switchEmail() {
  335. // 切换到邮箱注册
  336. switchType.value = "Email";
  337. password.value = "";
  338. verifyCode.value = "";
  339. }
  340. function switchPhone() {
  341. // 切换到手机注册
  342. switchType.value = "Phone";
  343. password.value = "";
  344. verifyCode.value = "";
  345. }
  346. // 登录
  347. async function Login() {
  348. if (!basicVerification()) {
  349. return;
  350. }
  351. const account = changeAccount();
  352. const loginType = changeLoginType();
  353. isLoading.value = true;
  354. const res = await LoginApi({
  355. loginType: loginType,
  356. phoneCountry: country.value, //手机号所属地区
  357. account: account,
  358. verifyCode: verifyCode.value,
  359. password: password.value,
  360. useCode: verifyCode.value ? true : false,
  361. idToken: "",
  362. deviceId: deviceStore.deviceInfo.deviceId,
  363. });
  364. isLoading.value = false;
  365. const message = res.message;
  366. if (res.code === 200) {
  367. // 登录成功
  368. uni.showToast({
  369. title: "登录成功",
  370. icon: "success",
  371. });
  372. const userStore = useUserStore();
  373. userStore.setUserInfo(res.data);
  374. console.log("userInfo为", userStore.userInfo);
  375. // 跳转到首页
  376. uni.redirectTo({
  377. url: "/pages/home/home",
  378. });
  379. } else {
  380. // 登录失败
  381. uni.showToast({
  382. title: message,
  383. icon: "none",
  384. });
  385. }
  386. }
  387. // 基础验证
  388. function basicVerification() {
  389. if (switchType.value === "User") {
  390. if (!deepChartID.value) {
  391. uni.showToast({
  392. title: "请输入用户名",
  393. icon: "none",
  394. });
  395. return false;
  396. }
  397. if (!password.value) {
  398. uni.showToast({
  399. title: "请输入密码",
  400. icon: "none",
  401. });
  402. return false;
  403. }
  404. if (password.value.length < 8) {
  405. uni.showToast({
  406. title: "密码长度不能少于8位",
  407. icon: "none",
  408. });
  409. return false;
  410. }
  411. }
  412. if (switchType.value === "Phone") {
  413. // 登录逻辑
  414. if (!phone.value) {
  415. uni.showToast({
  416. title: "请输入手机号码",
  417. icon: "none",
  418. });
  419. return false;
  420. }
  421. if (!validatePhoneNumber(country.value, phone.value)) {
  422. return false;
  423. }
  424. if (!verifyCode.value) {
  425. uni.showToast({
  426. title: "请输入验证码",
  427. icon: "none",
  428. });
  429. return false;
  430. }
  431. }
  432. if (switchType.value === "Email") {
  433. // 登录逻辑
  434. if (!email.value) {
  435. uni.showToast({
  436. title: "请输入邮箱地址",
  437. icon: "none",
  438. });
  439. return false;
  440. }
  441. const bool = verificationEmail(email.value);
  442. console.log("验证是否成功", bool);
  443. // 检查格式是否正确
  444. if (!bool) {
  445. uni.showToast({
  446. title: "邮箱格式不正确",
  447. icon: "none",
  448. });
  449. return false;
  450. }
  451. if (!verifyCode.value) {
  452. uni.showToast({
  453. title: "请输入验证码",
  454. icon: "none",
  455. });
  456. return false;
  457. }
  458. }
  459. if (!agreed.value) {
  460. // 显示同意弹窗
  461. agreementPopup.value.open();
  462. return;
  463. }
  464. return true;
  465. }
  466. // 注册码码验证
  467. function VerCodeVerfifcation() {
  468. if (switchType.value === "Phone") {
  469. if (!phone.value) {
  470. uni.showToast({
  471. title: "请输入手机号",
  472. icon: "none",
  473. });
  474. return false;
  475. }
  476. const bool = verificationPhone(country.value, phone.value);
  477. console.log("验证是否成功", bool);
  478. // 检查格式是否正确
  479. if (!bool) {
  480. uni.showToast({
  481. title: "手机号格式不正确",
  482. icon: "none",
  483. });
  484. return false;
  485. }
  486. }
  487. if (switchType.value === "Email") {
  488. if (!email.value) {
  489. uni.showToast({
  490. title: "请输入邮箱地址",
  491. icon: "none",
  492. });
  493. return false;
  494. }
  495. const bool = verificationEmail(email.value);
  496. console.log("验证是否成功", bool);
  497. // 检查格式是否正确
  498. if (!bool) {
  499. uni.showToast({
  500. title: "邮箱格式不正确",
  501. icon: "none",
  502. });
  503. return false;
  504. }
  505. }
  506. return true;
  507. }
  508. // 请求账户
  509. function changeAccount() {
  510. if (switchType.value === "User") {
  511. account.value = deepChartID.value;
  512. }
  513. if (switchType.value === "Phone") {
  514. account.value = phone.value;
  515. }
  516. if (switchType.value === "Email") {
  517. account.value = email.value;
  518. }
  519. return account.value;
  520. }
  521. // 改变请求时的type
  522. function changeLoginType() {
  523. if (switchType.value === "User") {
  524. return "DCCODE";
  525. }
  526. if (switchType.value === "Phone") {
  527. return "PHONE";
  528. }
  529. if (switchType.value === "Email") {
  530. return "EMAIL";
  531. }
  532. }
  533. // 添加弹窗引用
  534. const agreementPopup = ref(null);
  535. // 处理同意按钮点击
  536. function handleAgree() {
  537. // 关闭弹窗
  538. agreementPopup.value.close();
  539. // 设置为已同意
  540. agreed.value = true;
  541. checkboxUrl.value = "../../../static/icons/Check-one-true.png";
  542. // 继续登录流程
  543. }
  544. // 处理同意按钮点击
  545. function handleCancel() {
  546. // 关闭弹窗
  547. agreementPopup.value.close();
  548. }
  549. // 苹果登录
  550. function loginWithApple() {
  551. // Apple登录逻辑
  552. console.log("通过Apple登录");
  553. uni.login({
  554. provider: "apple",
  555. success: function (loginRes) {
  556. // 登录成功
  557. uni.getUserInfo({
  558. provider: "apple",
  559. success: function (info) {
  560. console.log(info);
  561. },
  562. });
  563. },
  564. fail: function (err) {
  565. // 登录授权失败
  566. // err.code错误码参考`授权失败错误码(code)说明`
  567. console.log(err);
  568. },
  569. });
  570. }
  571. // 谷歌登录
  572. function loginWithGoogle() {
  573. // Google登录逻辑
  574. console.log("通过Google登录");
  575. uni.login({
  576. provider: "google",
  577. success: function (loginRes) {
  578. // 登录成功
  579. uni.getUserInfo({
  580. provider: "google",
  581. success: function (info) {
  582. console.log(info);
  583. },
  584. });
  585. },
  586. fail: function (err) {
  587. // 登录授权失败
  588. // err.code是错误码
  589. console.log(err);
  590. },
  591. });
  592. }
  593. function goToRegistration() {
  594. // 跳转到登录页
  595. uni.navigateTo({
  596. url: "/pages/start/Registration/Registration",
  597. });
  598. }
  599. function onPhoneInput(e) {
  600. // 确保只允许输入数字
  601. const value = e.detail.value;
  602. // 使用 isNaN 检查是否为有效数字
  603. if (isNaN(value)) {
  604. phone.value = "";
  605. } else {
  606. phone.value = value;
  607. }
  608. }
  609. // 发送验证码
  610. async function sendCode() {
  611. if (!VerCodeVerfifcation()) {
  612. return;
  613. }
  614. // 如果按钮已禁用,则不执行后续逻辑
  615. if (isCodeBtnDisabled.value) return;
  616. if (switchType.value === "Phone") {
  617. // 发送验证码
  618. const res = await SendPhoneCodeApi({
  619. phoneCountry: country.value, //手机号地区
  620. phone: phone.value,
  621. });
  622. console.log("手机验证码:", res.message);
  623. if (!res) {
  624. uni.showToast({
  625. title: "请求失败",
  626. icon: "none",
  627. });
  628. }
  629. }
  630. if (switchType.value === "Email") {
  631. // 发送验证码
  632. const res = await SendEmailCodeApi({
  633. email: email.value,
  634. });
  635. console.log("邮箱验证码:", res.message);
  636. if (!res) {
  637. uni.showToast({
  638. title: "请求失败",
  639. icon: "none",
  640. });
  641. }
  642. }
  643. // 设置按钮为禁用状态
  644. isCodeBtnDisabled.value = true;
  645. codeBtnText.value = "重新发送";
  646. let time = 6;
  647. const timer = setInterval(() => {
  648. time--;
  649. codeBtnText.value = "重新发送 " + time + "s";
  650. if (time <= 0) {
  651. clearInterval(timer);
  652. codeBtnText.value = "重新发送";
  653. // 倒计时结束后启用按钮
  654. isCodeBtnDisabled.value = false;
  655. }
  656. }, 1000);
  657. return;
  658. }
  659. function openAgreement() {
  660. // 打开用户协议
  661. console.log("打开用户协议");
  662. uni.navigateTo({
  663. url: "/pages/start/agreement/agreement",
  664. });
  665. }
  666. function openPrivacy() {
  667. // 打开隐私政策
  668. console.log("打开隐私政策");
  669. uni.navigateTo({
  670. url: "/pages/start/privacy/privacy",
  671. });
  672. }
  673. function recoverPassword() {
  674. // 忘记密码
  675. // console.log("忘记密码");
  676. uni.navigateTo({
  677. url: "/pages/start/recoverPassword/recoverPassword",
  678. });
  679. }
  680. function changeCheckbox() {
  681. agreed.value = !agreed.value;
  682. checkboxUrl.value = agreed.value
  683. ? "../../../static/icons/Check-one-true.png"
  684. : "../../../static/icons/Check-one-false.png";
  685. }
  686. // 验证手机号是否正确
  687. function validatePhoneNumber(countryCode, phoneNumber) {
  688. // 检查是否为空
  689. if (!phoneNumber || phoneNumber.trim() === "") {
  690. uni.showToast({
  691. title: "手机号不能为空",
  692. icon: "none",
  693. });
  694. return false;
  695. }
  696. const bool = verificationPhone(countryCode, phoneNumber);
  697. console.log("验证是否成功", bool);
  698. // 检查格式是否正确
  699. if (!bool) {
  700. uni.showToast({
  701. title: "手机号格式不正确",
  702. icon: "none",
  703. });
  704. return false;
  705. }
  706. // 去掉+号后检查长度(手机号通常在7到15位之间)
  707. const cleanNumber = phoneNumber.replace(/^\+/, "");
  708. if (cleanNumber.length < 7 || cleanNumber.length > 15) {
  709. uni.showToast({
  710. title: "手机号长度不正确",
  711. icon: "none",
  712. });
  713. return false;
  714. }
  715. return true;
  716. }
  717. </script>
  718. <style scoped>
  719. .login-registration-container {
  720. display: flex;
  721. flex-direction: column;
  722. align-items: center;
  723. justify-content: center;
  724. padding: 0 70rpx;
  725. height: 100vh;
  726. background-color: #ffffff;
  727. }
  728. /* 自定义导航栏样式 */
  729. .custom-navbar {
  730. position: absolute;
  731. top: 0;
  732. left: 0;
  733. /* z-index: 999; */
  734. width: 90%;
  735. height: 80rpx;
  736. display: flex;
  737. justify-content: space-between;
  738. align-items: center;
  739. padding: 10rpx 40rpx;
  740. margin-bottom: 20rpx;
  741. }
  742. .nav-left,
  743. .nav-right {
  744. flex: 1;
  745. }
  746. .nav-right {
  747. display: flex;
  748. justify-content: flex-end;
  749. }
  750. .icons {
  751. margin: 20rpx;
  752. width: 40rpx;
  753. height: 40rpx;
  754. /* margin-right: 10rpx; */
  755. }
  756. .icons-rotation {
  757. margin: 20rpx;
  758. width: 40rpx;
  759. height: 40rpx;
  760. /* margin-right: 10rpx; */
  761. animation: rotation 2s linear infinite;
  762. }
  763. @keyframes rotation {
  764. from {
  765. transform: rotate(0deg);
  766. }
  767. to {
  768. transform: rotate(360deg);
  769. }
  770. }
  771. .back-btn,
  772. .headphone-btn {
  773. font-size: 36rpx;
  774. font-weight: bold;
  775. color: #333333;
  776. padding: 10rpx;
  777. }
  778. .logo {
  779. width: 120rpx;
  780. height: 120rpx;
  781. margin-bottom: 60rpx;
  782. border-radius: 20%;
  783. }
  784. .welcome-text {
  785. font-size: 48rpx;
  786. font-weight: bold;
  787. color: #333333;
  788. margin-bottom: 60rpx;
  789. /* text-align: left; */
  790. /* align-self: flex-start; */
  791. }
  792. .switch-container {
  793. display: flex;
  794. margin-bottom: 40rpx;
  795. align-self: flex-start;
  796. }
  797. .switch-item {
  798. font-size: 28rpx;
  799. color: #999999;
  800. padding: 10rpx 20rpx;
  801. position: relative;
  802. }
  803. .switch-item::after {
  804. content: "";
  805. position: absolute;
  806. bottom: 0;
  807. left: 50%;
  808. transform: translateX(-50%);
  809. width: 60%;
  810. /* 控制边框宽度 */
  811. height: 2rpx;
  812. background-color: transparent;
  813. }
  814. .switch-item.active {
  815. color: #333333;
  816. font-weight: 700;
  817. }
  818. .switch-item.active::after {
  819. content: "";
  820. position: absolute;
  821. top: 60rpx;
  822. bottom: 0;
  823. left: 50%;
  824. transform: translateX(-50%);
  825. width: 30%;
  826. /* 控制边框宽度 */
  827. height: 7rpx;
  828. background-color: #333333;
  829. }
  830. .input-container {
  831. width: 100%;
  832. }
  833. /* 添加图标输入框样式 */
  834. .input-with-icon {
  835. display: flex;
  836. align-items: center;
  837. width: 100%;
  838. height: 80rpx;
  839. border-bottom: 2rpx solid #e5e5e5;
  840. margin-bottom: 20rpx;
  841. }
  842. .input-icon {
  843. width: 40rpx;
  844. height: 40rpx;
  845. margin: 0 20rpx;
  846. }
  847. .input-field {
  848. flex: 1;
  849. height: 80rpx;
  850. padding: 15rpx 0;
  851. font-size: 28rpx;
  852. color: #333333;
  853. border: none;
  854. background-color: transparent;
  855. }
  856. .phone-input-container {
  857. display: flex;
  858. align-items: center;
  859. width: 95.8%;
  860. height: 80rpx;
  861. /* border-radius: 20rpx; */
  862. /* border: 2rpx solid #e5e5e5; */
  863. /* background-color: #f5f5f5; */
  864. padding: 0 10rpx;
  865. border-bottom: 2rpx solid #e5e5e5;
  866. margin-bottom: 20rpx;
  867. }
  868. .country-code-selector {
  869. display: flex;
  870. align-items: center;
  871. padding: 0 10rpx;
  872. padding-bottom: 1rpx;
  873. height: 100%;
  874. /* border-right: 2rpx solid #e5e5e5; */
  875. /* background-color: #f5f5f5; */
  876. border-radius: 20rpx 0 0 20rpx;
  877. }
  878. .country-code {
  879. font-size: 28rpx;
  880. color: #333333;
  881. margin-right: 10rpx;
  882. }
  883. .country-flag-img {
  884. width: 40rpx;
  885. height: 40rpx;
  886. margin-right: 10rpx;
  887. }
  888. .arrow-down {
  889. font-size: 20rpx;
  890. color: #999999;
  891. }
  892. .phone-input {
  893. flex: 1;
  894. width: auto;
  895. height: 100%;
  896. border: none;
  897. background-color: transparent;
  898. padding: 0 0rpx;
  899. }
  900. .send-code-btn {
  901. width: 200rpx;
  902. height: 60rpx;
  903. display: inline-flex;
  904. padding: 0rpx 10rpx;
  905. justify-content: center;
  906. align-items: center;
  907. gap: 10px;
  908. border-radius: 4px;
  909. background: #000;
  910. }
  911. .send-code-btn-email {
  912. width: 200rpx;
  913. height: 60rpx;
  914. display: inline-flex;
  915. padding: 0rpx 10rpx;
  916. justify-content: center;
  917. align-items: center;
  918. gap: 10px;
  919. border-radius: 4px;
  920. background: #000;
  921. margin-right: 15rpx;
  922. }
  923. .send-code-btn-disabled {
  924. background: #e6e6e6;
  925. /* 禁用状态下的灰色背景 */
  926. }
  927. .send-code-btn-disabled-text {
  928. color: #999999 !important;
  929. }
  930. .send-code-text {
  931. color: #fff;
  932. font-size: 28rpx;
  933. }
  934. .agreement-container-one {
  935. display: flex;
  936. align-items: center;
  937. align-self: flex-start;
  938. margin-bottom: 80rpx;
  939. }
  940. .agreement-container {
  941. display: flex;
  942. align-items: center;
  943. margin-bottom: 30rpx;
  944. margin-top: -60rpx;
  945. align-self: flex-start;
  946. }
  947. .checkbox {
  948. width: 30rpx;
  949. height: 30rpx;
  950. margin-left: 20rpx;
  951. /* flex: content; */
  952. }
  953. .agreement-text-one {
  954. font-size: 22rpx;
  955. color: #666666;
  956. text-align: center;
  957. margin-left: 10rpx;
  958. }
  959. .agreement-text {
  960. margin-left: 20rpx;
  961. font-size: 24rpx;
  962. color: #666666;
  963. white-space: nowrap;
  964. }
  965. .link {
  966. color: #333333;
  967. font-weight: bold;
  968. text-decoration: underline;
  969. }
  970. .register-btn {
  971. width: 100%;
  972. height: 80rpx;
  973. background-color: #000000;
  974. color: white;
  975. font-size: 32rpx;
  976. font-weight: bold;
  977. border-radius: 40rpx;
  978. margin-bottom: 40rpx;
  979. }
  980. .or-text {
  981. font-size: 24rpx;
  982. color: #999999;
  983. margin-bottom: 40rpx;
  984. }
  985. .to-icon {
  986. width: 10rpx;
  987. height: 16rpx;
  988. }
  989. .third-party-login {
  990. width: 100%;
  991. margin-bottom: 60rpx;
  992. }
  993. .third-party-text {
  994. color: #ffffff;
  995. font-weight: bold;
  996. white-space: pre;
  997. }
  998. .third-party-btn {
  999. width: 100%;
  1000. height: 80rpx;
  1001. background-color: rgb(0, 0, 0);
  1002. border: 2rpx solid #e5e5e5;
  1003. border-radius: 40rpx;
  1004. display: flex;
  1005. align-items: center;
  1006. justify-content: center;
  1007. margin-bottom: 20rpx;
  1008. font-size: 28rpx;
  1009. color: #333333;
  1010. }
  1011. .google-icon,
  1012. .apple-icon {
  1013. width: 60rpx;
  1014. height: 60rpx;
  1015. margin-right: 20rpx;
  1016. }
  1017. .existing-account {
  1018. display: flex;
  1019. align-items: center;
  1020. }
  1021. .account-text {
  1022. font-size: 24rpx;
  1023. color: #666666;
  1024. }
  1025. .login-link {
  1026. font-size: 24rpx;
  1027. font-weight: bold;
  1028. color: #333333;
  1029. margin-left: 10rpx;
  1030. text-decoration: underline;
  1031. }
  1032. .static-footer {
  1033. position: fixed;
  1034. bottom: 0;
  1035. }
  1036. /* 弹窗样式 */
  1037. .popup-content {
  1038. background-color: #ffffff;
  1039. padding: 40rpx;
  1040. text-align: center;
  1041. border-radius: 10rpx;
  1042. width: 550rpx;
  1043. }
  1044. .popup-message {
  1045. font-size: 28rpx;
  1046. color: #000000;
  1047. margin-bottom: 60rpx;
  1048. margin-top: 20rpx;
  1049. text-align: center; /* 水平居中 */
  1050. display: flex; /* 使用flex布局 */
  1051. justify-content: center; /* 水平居中 */
  1052. align-items: center; /* 垂直居中 */
  1053. font-weight: 300;
  1054. }
  1055. .popup-message-link {
  1056. font-weight: 700;
  1057. }
  1058. .button-group {
  1059. display: flex;
  1060. justify-content: space-around;
  1061. }
  1062. .agree-button {
  1063. width: 160rpx;
  1064. height: 56rpx;
  1065. background-color: #000000;
  1066. border-radius: 40rpx;
  1067. display: flex; /* 添加flex布局 */
  1068. align-items: center; /* 垂直居中 */
  1069. justify-content: center; /* 水平居中 */
  1070. }
  1071. .agree-text {
  1072. color: #ffffff;
  1073. font-size: 34rpx;
  1074. /* 添加垂直居中相关样式 */
  1075. display: flex;
  1076. align-items: center;
  1077. justify-content: center;
  1078. line-height: 1; /* 确保文字垂直居中 */
  1079. }
  1080. .cancel-button {
  1081. width: 160rpx;
  1082. height: 56rpx;
  1083. background-color: #e5e5e5;
  1084. border-radius: 40rpx;
  1085. display: flex; /* 添加flex布局 */
  1086. align-items: center; /* 垂直居中 */
  1087. justify-content: center; /* 水平居中 */
  1088. }
  1089. .cancel-text {
  1090. color: #333333;
  1091. font-size: 34rpx;
  1092. /* 添加垂直居中相关样式 */
  1093. display: flex;
  1094. align-items: center;
  1095. justify-content: center;
  1096. line-height: 1; /* 确保文字垂直居中 */
  1097. }
  1098. </style>