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.

1062 lines
22 KiB

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