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.

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