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.

654 lines
13 KiB

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. src="../../../static/icons/Headset.png"
  15. alt="联系客服"
  16. />
  17. <image
  18. class="icons"
  19. @click="goToIndex"
  20. src="../../../static/icons/Frame.png"
  21. alt="返回首页"
  22. />
  23. </view>
  24. </view>
  25. <!-- Logo -->
  26. <!-- <image class="logo" src="/static/logo.png" mode="aspectFit"></image> -->
  27. <!-- 欢迎语 -->
  28. <text class="welcome-text">欢迎来到DeepChart</text>
  29. <!-- 邮箱/手机号切换 -->
  30. <view class="switch-container">
  31. <text
  32. class="switch-item"
  33. :class="{ active: switchType === 'Email' }"
  34. @click="switchEmail"
  35. >邮箱</text
  36. >
  37. <text
  38. class="switch-item"
  39. :class="{ active: switchType === 'Phone' }"
  40. @click="switchPhone"
  41. >手机号</text
  42. >
  43. </view>
  44. <!-- 输入框 -->
  45. <view class="input-container">
  46. <view v-if="switchType === 'Email'">
  47. <!-- 修改邮箱输入框容器将图标包含在内 -->
  48. <view class="input-with-icon">
  49. <image
  50. class="input-icon"
  51. src="../../../static/icons/Mail.png"
  52. alt=""
  53. />
  54. <input
  55. class="input-field"
  56. type="text"
  57. placeholder="请输入邮箱"
  58. v-model="email"
  59. />
  60. <view>
  61. <button
  62. class="send-code-btn-email"
  63. :disabled="isCodeBtnDisabled"
  64. :class="{ 'send-code-btn-disabled': isCodeBtnDisabled }"
  65. @click="sendCode"
  66. >
  67. <text
  68. class="send-code-text"
  69. :class="{ 'send-code-btn-disabled-text': isCodeBtnDisabled }"
  70. >{{ codeBtnText }}</text
  71. >
  72. </button>
  73. </view>
  74. </view>
  75. <view class="input-with-icon">
  76. <image
  77. class="input-icon"
  78. src="../../../static/icons/Text-recognition.png"
  79. alt=""
  80. />
  81. <input
  82. class="input-field"
  83. type="text"
  84. placeholder="请输入验证码"
  85. v-model="password"
  86. />
  87. </view>
  88. </view>
  89. <view v-if="switchType === 'Phone'" class="phone-input-container">
  90. <view class="country-code-selector" @click="showCountryPicker">
  91. <image
  92. class="country-flag-img"
  93. src="../../../static/icons/Iphone.png"
  94. mode="aspectFit"
  95. ></image>
  96. <text class="country-code">{{ selectedCountry.code }}</text>
  97. <!-- <text class="arrow-down"></text> -->
  98. </view>
  99. <input
  100. class="input-field phone-input"
  101. type="number"
  102. placeholder="输入手机号"
  103. v-model="phone"
  104. @input="onPhoneInput"
  105. />
  106. <view>
  107. <button
  108. class="send-code-btn"
  109. :disabled="isCodeBtnDisabled"
  110. :class="{ 'send-code-btn-disabled': isCodeBtnDisabled }"
  111. @click="sendCode"
  112. >
  113. <text
  114. class="send-code-text"
  115. :class="{ 'send-code-btn-disabled-text': isCodeBtnDisabled }"
  116. >{{ codeBtnText }}</text
  117. >
  118. </button>
  119. </view>
  120. </view>
  121. <view v-if="switchType === 'Phone'" class="input-with-icon">
  122. <image
  123. class="input-icon"
  124. src="../../../static/icons/Text-recognition.png"
  125. alt=""
  126. />
  127. <input
  128. class="input-field"
  129. type="text"
  130. placeholder="请输入验证码"
  131. v-model="password"
  132. />
  133. </view>
  134. </view>
  135. <!-- 用户协议 -->
  136. <view @click="changeCheckbox" class="agreement-container-one">
  137. <image class="checkbox" :src="checkboxUrl"></image>
  138. <text class="agreement-text-one"
  139. >接受 <text class="link" @click="openAgreement">用户协议</text>
  140. <text class="link" @click="openPrivacy">隐私政策</text></text
  141. >
  142. </view>
  143. <!-- 注册按钮 -->
  144. <button class="register-btn" @click="register">注册</button>
  145. <!-- 或者 -->
  146. <text class="or-text" @click="goToLogin"
  147. >已有账号登录
  148. </text>
  149. </view>
  150. </template>
  151. <script setup>
  152. import { ref } from "vue";
  153. // 导入完整的国家列表
  154. import countryList from "../login/list";
  155. const email = ref("");
  156. const password = ref("");
  157. const phone = ref("");
  158. const agreed = ref(false);
  159. const switchType = ref("Email"); // 默认是邮箱注册
  160. const { safeAreaInsets } = uni.getSystemInfoSync();
  161. const codeBtnText = ref("获取验证码");
  162. const isCodeBtnDisabled = ref(false); // 添加验证码按钮禁用状态
  163. const checkboxUrl = ref("../../../static/icons/Check-one-false.png");
  164. // 使用从list.js导入的完整国家列表数据
  165. const countries = ref(
  166. countryList.list.map((item) => ({
  167. name: item.name,
  168. code: `+${item.tel}`,
  169. flag: item.flag,
  170. short: item.short,
  171. en: item.en,
  172. }))
  173. );
  174. // 默认选中的国家(中国)
  175. const selectedCountry = ref(
  176. countries.value.find((country) => country.short === "CN") ||
  177. countries.value[0]
  178. );
  179. // 显示国家选择器
  180. function showCountryPicker() {
  181. uni.showActionSheet({
  182. itemList: countries.value.map(
  183. (country) => `${country.name} ${country.code}`
  184. ),
  185. success: function (res) {
  186. selectedCountry.value = countries.value[res.tapIndex];
  187. },
  188. });
  189. }
  190. function goToIndex() {
  191. // 返回上一页
  192. uni.navigateTo({
  193. url: "/pages/start/index/index",
  194. });
  195. }
  196. function switchEmail() {
  197. // 切换到邮箱注册
  198. switchType.value = "Email";
  199. }
  200. function switchPhone() {
  201. // 切换到手机注册
  202. switchType.value = "Phone";
  203. }
  204. function register() {
  205. if (switchType.value === "Email") {
  206. // 登录逻辑
  207. if (!email.value) {
  208. uni.showToast({
  209. title: "请输入邮箱地址",
  210. icon: "none",
  211. });
  212. return;
  213. }
  214. // 发送登录请求
  215. console.log("登录:", email.value);
  216. }
  217. if (switchType.value === "Phone") {
  218. // 登录逻辑
  219. if (!phone.value) {
  220. uni.showToast({
  221. title: "请输入手机号码",
  222. icon: "none",
  223. });
  224. return;
  225. }
  226. // 发送登录请求
  227. console.log("登录:", phone.value);
  228. }
  229. }
  230. function goToLogin() {
  231. // 跳转到登录页
  232. uni.navigateTo({
  233. url: "/pages/start/login/login",
  234. });
  235. }
  236. function onPhoneInput(e) {
  237. // 确保只允许输入数字
  238. const value = e.detail.value;
  239. // 使用 isNaN 检查是否为有效数字
  240. if (isNaN(value)) {
  241. phone.value = "";
  242. } else {
  243. phone.value = value;
  244. }
  245. }
  246. function sendCode() {
  247. // 如果按钮已禁用,则不执行后续逻辑
  248. if (isCodeBtnDisabled.value) return;
  249. // 设置按钮为禁用状态
  250. isCodeBtnDisabled.value = true;
  251. codeBtnText.value = "重新发送";
  252. let time = 6;
  253. const timer = setInterval(() => {
  254. time--;
  255. codeBtnText.value = "重新发送 " + time + "s";
  256. if (time <= 0) {
  257. clearInterval(timer);
  258. codeBtnText.value = "重新发送";
  259. // 倒计时结束后启用按钮
  260. isCodeBtnDisabled.value = false;
  261. }
  262. }, 1000);
  263. return;
  264. }
  265. function openAgreement() {
  266. // 打开用户协议
  267. console.log("打开用户协议");
  268. uni.navigateTo({
  269. url: "/pages/start/agreement/agreement",
  270. });
  271. }
  272. function openPrivacy() {
  273. // 打开隐私政策
  274. console.log("打开隐私政策");
  275. uni.navigateTo({
  276. url: "/pages/start/privacy/privacy",
  277. });
  278. }
  279. function changeCheckbox() {
  280. agreed.value = !agreed.value;
  281. checkboxUrl.value = agreed.value
  282. ? "../../../static/icons/Check-one-true.png"
  283. : "../../../static/icons/Check-one-false.png";
  284. }
  285. </script>
  286. <style scoped>
  287. .login-registration-container {
  288. display: flex;
  289. flex-direction: column;
  290. align-items: center;
  291. justify-content: center;
  292. padding: 0 70rpx;
  293. height: 100vh;
  294. background-color: #ffffff;
  295. }
  296. /* 自定义导航栏样式 */
  297. .custom-navbar {
  298. position: absolute;
  299. top: 0;
  300. left: 0;
  301. /* z-index: 999; */
  302. width: 90%;
  303. height: 80rpx;
  304. display: flex;
  305. justify-content: space-between;
  306. align-items: center;
  307. padding: 10rpx 40rpx;
  308. margin-bottom: 20rpx;
  309. }
  310. .nav-left,
  311. .nav-right {
  312. flex: 1;
  313. }
  314. .nav-right {
  315. display: flex;
  316. justify-content: flex-end;
  317. }
  318. .icons {
  319. margin: 20rpx;
  320. width: 40rpx;
  321. height: 40rpx;
  322. /* margin-right: 10rpx; */
  323. }
  324. .back-btn,
  325. .headphone-btn {
  326. font-size: 36rpx;
  327. font-weight: bold;
  328. color: #333333;
  329. padding: 10rpx;
  330. }
  331. .logo {
  332. width: 120rpx;
  333. height: 120rpx;
  334. margin-bottom: 60rpx;
  335. border-radius: 20%;
  336. }
  337. .welcome-text {
  338. font-size: 48rpx;
  339. font-weight: bold;
  340. color: #333333;
  341. margin-bottom: 60rpx;
  342. /* text-align: left; */
  343. /* align-self: flex-start; */
  344. }
  345. .switch-container {
  346. display: flex;
  347. margin-bottom: 40rpx;
  348. align-self: flex-start;
  349. }
  350. .switch-item {
  351. font-size: 28rpx;
  352. color: #999999;
  353. padding: 10rpx 20rpx;
  354. position: relative;
  355. }
  356. .switch-item::after {
  357. content: "";
  358. position: absolute;
  359. bottom: 0;
  360. left: 50%;
  361. transform: translateX(-50%);
  362. width: 60%;
  363. /* 控制边框宽度 */
  364. height: 2rpx;
  365. background-color: transparent;
  366. }
  367. .switch-item.active {
  368. color: #333333;
  369. font-weight: 700;
  370. }
  371. .switch-item.active::after {
  372. content: "";
  373. position: absolute;
  374. top: 60rpx;
  375. bottom: 0;
  376. left: 50%;
  377. transform: translateX(-50%);
  378. width: 30%;
  379. /* 控制边框宽度 */
  380. height: 7rpx;
  381. background-color: #333333;
  382. }
  383. .input-container {
  384. width: 100%;
  385. }
  386. /* 添加图标输入框样式 */
  387. .input-with-icon {
  388. display: flex;
  389. align-items: center;
  390. width: 100%;
  391. height: 80rpx;
  392. border-bottom: 2rpx solid #e5e5e5;
  393. margin-bottom: 20rpx;
  394. }
  395. .input-icon {
  396. width: 40rpx;
  397. height: 40rpx;
  398. margin: 0 20rpx;
  399. }
  400. .input-field {
  401. flex: 1;
  402. height: 80rpx;
  403. padding: 15rpx 0;
  404. font-size: 28rpx;
  405. color: #333333;
  406. border: none;
  407. background-color: transparent;
  408. }
  409. .phone-input-container {
  410. display: flex;
  411. align-items: center;
  412. width: 95.8%;
  413. height: 80rpx;
  414. /* border-radius: 20rpx; */
  415. /* border: 2rpx solid #e5e5e5; */
  416. /* background-color: #f5f5f5; */
  417. padding: 0 10rpx;
  418. border-bottom: 2rpx solid #e5e5e5;
  419. margin-bottom: 20rpx;
  420. }
  421. .country-code-selector {
  422. display: flex;
  423. align-items: center;
  424. padding: 0 10rpx;
  425. padding-bottom: 1rpx;
  426. height: 100%;
  427. /* border-right: 2rpx solid #e5e5e5; */
  428. /* background-color: #f5f5f5; */
  429. border-radius: 20rpx 0 0 20rpx;
  430. }
  431. .country-code {
  432. font-size: 28rpx;
  433. color: #333333;
  434. margin-right: 10rpx;
  435. }
  436. .country-flag-img {
  437. width: 40rpx;
  438. height: 40rpx;
  439. margin-right: 10rpx;
  440. }
  441. .arrow-down {
  442. font-size: 20rpx;
  443. color: #999999;
  444. }
  445. .phone-input {
  446. flex: 1;
  447. width: auto;
  448. height: 100%;
  449. border: none;
  450. background-color: transparent;
  451. padding: 0 0rpx;
  452. }
  453. .send-code-btn {
  454. width: 200rpx;
  455. height: 60rpx;
  456. display: inline-flex;
  457. padding: 0rpx 10rpx;
  458. justify-content: center;
  459. align-items: center;
  460. gap: 10px;
  461. border-radius: 4px;
  462. background: #000;
  463. }
  464. .send-code-btn-email {
  465. width: 200rpx;
  466. height: 60rpx;
  467. display: inline-flex;
  468. padding: 0rpx 10rpx;
  469. justify-content: center;
  470. align-items: center;
  471. gap: 10px;
  472. border-radius: 4px;
  473. background: #000;
  474. margin-right: 15rpx;
  475. }
  476. .send-code-btn-disabled {
  477. background: #e6e6e6;
  478. /* 禁用状态下的灰色背景 */
  479. }
  480. .send-code-btn-disabled-text {
  481. color: #999999 !important;
  482. }
  483. .send-code-text {
  484. color: #fff;
  485. font-size: 28rpx;
  486. }
  487. .agreement-container-one {
  488. display: flex;
  489. align-items: center;
  490. align-self: flex-start;
  491. margin-bottom: 80rpx;
  492. }
  493. .agreement-container {
  494. display: flex;
  495. align-items: center;
  496. margin-bottom: 40rpx;
  497. margin-top: -75.5rpx;
  498. align-self: flex-start;
  499. }
  500. .checkbox {
  501. width: 30rpx;
  502. height: 30rpx;
  503. margin-left: 20rpx;
  504. /* flex: content; */
  505. }
  506. .agreement-text-one {
  507. font-size: 22rpx;
  508. color: #666666;
  509. text-align: center;
  510. margin-left: 10rpx;
  511. }
  512. .agreement-text {
  513. margin-left: 20rpx;
  514. font-size: 24rpx;
  515. color: #666666;
  516. }
  517. .link {
  518. color: #333333;
  519. font-weight: bold;
  520. text-decoration: underline;
  521. }
  522. .register-btn {
  523. width: 100%;
  524. height: 80rpx;
  525. background-color: #000000;
  526. color: white;
  527. font-size: 32rpx;
  528. font-weight: bold;
  529. border-radius: 40rpx;
  530. margin-bottom: 40rpx;
  531. }
  532. .or-text {
  533. flex-direction: column;
  534. font-size: 24rpx;
  535. color: #999999;
  536. margin-bottom: 100rpx;
  537. }
  538. .third-party-login {
  539. width: 100%;
  540. margin-bottom: 60rpx;
  541. }
  542. .third-party-text {
  543. color: #ffffff;
  544. font-weight: bold;
  545. white-space: pre;
  546. }
  547. .third-party-btn {
  548. width: 100%;
  549. height: 80rpx;
  550. background-color: rgb(0, 0, 0);
  551. border: 2rpx solid #e5e5e5;
  552. border-radius: 40rpx;
  553. display: flex;
  554. align-items: center;
  555. justify-content: center;
  556. margin-bottom: 20rpx;
  557. font-size: 28rpx;
  558. color: #333333;
  559. }
  560. .google-icon,
  561. .apple-icon {
  562. width: 60rpx;
  563. height: 60rpx;
  564. margin-right: 20rpx;
  565. }
  566. .existing-account {
  567. display: flex;
  568. align-items: center;
  569. }
  570. .account-text {
  571. font-size: 24rpx;
  572. color: #666666;
  573. }
  574. .login-link {
  575. font-size: 24rpx;
  576. font-weight: bold;
  577. color: #333333;
  578. margin-left: 10rpx;
  579. text-decoration: underline;
  580. }
  581. </style>