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.

461 lines
8.9 KiB

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. <text class="headphone-btn">🎧</text>
  13. </view>
  14. </view>
  15. <!-- Logo -->
  16. <image class="logo" src="/static/logo.png" mode="aspectFit"></image>
  17. <!-- 欢迎语 -->
  18. <text class="welcome-text">登录</text>
  19. <!-- 邮箱/手机号切换 -->
  20. <view class="switch-container">
  21. <text
  22. class="switch-item"
  23. :class="{ active: switchType === 'Email' }"
  24. @click="switchEmail"
  25. >邮箱/用户名</text
  26. >
  27. <text
  28. class="switch-item"
  29. :class="{ active: switchType === 'Phone' }"
  30. @click="switchPhone"
  31. >手机号</text
  32. >
  33. </view>
  34. <!-- 输入框 -->
  35. <view class="input-container">
  36. <input
  37. v-if="switchType === 'Email'"
  38. class="input-field"
  39. type="text"
  40. placeholder="输入邮箱/用户名"
  41. v-model="email"
  42. />
  43. <view v-else class="phone-input-container">
  44. <view class="country-code-selector" @click="showCountryPicker">
  45. <image class="country-flag-img" :src="selectedCountry.flag" mode="aspectFit"></image>
  46. <text class="country-code">{{ selectedCountry.code }}</text>
  47. <text class="arrow-down"></text>
  48. </view>
  49. <input
  50. class="input-field phone-input"
  51. type="number"
  52. placeholder="输入手机号"
  53. v-model="phone"
  54. @input="onPhoneInput"
  55. />
  56. </view>
  57. </view>
  58. <!-- 注册按钮 -->
  59. <button class="register-btn" @click="register">下一步</button>
  60. <!-- 或者 -->
  61. <text class="or-text">或者</text>
  62. <!-- 第三方登录 -->
  63. <view class="third-party-login">
  64. <view class="third-party-btn" @click="loginWithApple">
  65. <image
  66. class="apple-icon"
  67. src="/static/apple-icon.png"
  68. mode="aspectFit"
  69. ></image>
  70. <text class="third-party-text">通过 Apple 继续</text>
  71. </view>
  72. <view class="third-party-btn" @click="loginWithGoogle">
  73. <image
  74. class="google-icon"
  75. src="/static/google-icon.png"
  76. mode="aspectFit"
  77. ></image>
  78. <text class="third-party-text">通过 Google 继续</text>
  79. </view>
  80. </view>
  81. <!-- 已有账号 -->
  82. <view class="existing-account">
  83. <text class="account-text">未注册账号</text>
  84. <text class="login-link" @click="goToRegistration">注册</text>
  85. </view>
  86. </view>
  87. </template>
  88. <script setup>
  89. import { ref } from "vue";
  90. // 导入完整的国家列表
  91. import countryList from './list.js';
  92. const email = ref("");
  93. const phone = ref("");
  94. const agreed = ref(false);
  95. const switchType = ref("Email"); // 默认是邮箱注册
  96. const { safeAreaInsets } = uni.getSystemInfoSync();
  97. // 使用从list.js导入的完整国家列表数据
  98. const countries = ref(countryList.list.map(item => ({
  99. name: item.name,
  100. code: `+${item.tel}`,
  101. flag: item.flag,
  102. short: item.short,
  103. en: item.en
  104. })));
  105. // 默认选中的国家(中国)
  106. const selectedCountry = ref(countries.value.find(country => country.short === 'CN') || countries.value[0]);
  107. // 显示国家选择器
  108. function showCountryPicker() {
  109. uni.showActionSheet({
  110. itemList: countries.value.map(country => `${country.name} ${country.code}`),
  111. success: function (res) {
  112. selectedCountry.value = countries.value[res.tapIndex];
  113. }
  114. });
  115. }
  116. function goToIndex() {
  117. // 返回上一页
  118. uni.navigateTo({ url: "/pages/start/index/index" });
  119. }
  120. function switchEmail() {
  121. // 切换到邮箱注册
  122. switchType.value = "Email";
  123. }
  124. function switchPhone() {
  125. // 切换到手机注册
  126. switchType.value = "Phone";
  127. }
  128. function register() {
  129. if (switchType.value === "Email") {
  130. // 登录逻辑
  131. if (!email.value) {
  132. uni.showToast({
  133. title: "请输入邮箱地址",
  134. icon: "none",
  135. });
  136. return;
  137. }
  138. // 发送登录请求
  139. console.log("登录:", email.value);
  140. }
  141. if(switchType.value === "Phone"){
  142. // 登录逻辑
  143. if (!phone.value) {
  144. uni.showToast({
  145. title: "请输入手机号码",
  146. icon: "none",
  147. });
  148. return;
  149. }
  150. // 发送登录请求
  151. console.log("登录:", phone.value);
  152. }
  153. }
  154. function loginWithApple() {
  155. // Apple登录逻辑
  156. console.log("通过Apple登录");
  157. }
  158. function loginWithGoogle() {
  159. // Google登录逻辑
  160. console.log("通过Google登录");
  161. }
  162. function goToRegistration() {
  163. // 跳转到登录页
  164. uni.navigateTo({
  165. url: "/pages/start/Registration/Registration",
  166. });
  167. }
  168. function onPhoneInput(e) {
  169. // 确保只允许输入数字
  170. const value = e.detail.value;
  171. // 使用 isNaN 检查是否为有效数字
  172. if (isNaN(value)) {
  173. phone.value = '';
  174. } else {
  175. phone.value = value;
  176. }
  177. }
  178. </script>
  179. <style scoped>
  180. .login-registration-container {
  181. display: flex;
  182. flex-direction: column;
  183. align-items: center;
  184. justify-content: center;
  185. padding: 0 40rpx;
  186. height: 100vh;
  187. background-color: #ffffff;
  188. }
  189. /* 自定义导航栏样式 */
  190. .custom-navbar {
  191. position: absolute;
  192. top: 0;
  193. left: 0;
  194. /* z-index: 999; */
  195. width: 90%;
  196. height: 80rpx;
  197. display: flex;
  198. justify-content: space-between;
  199. align-items: center;
  200. padding: 10rpx 40rpx;
  201. margin-bottom: 20rpx;
  202. }
  203. .nav-left,
  204. .nav-right {
  205. flex: 1;
  206. }
  207. .nav-right {
  208. display: flex;
  209. justify-content: flex-end;
  210. }
  211. .back-btn,
  212. .headphone-btn {
  213. font-size: 36rpx;
  214. font-weight: bold;
  215. color: #333333;
  216. padding: 10rpx;
  217. }
  218. .logo {
  219. width: 120rpx;
  220. height: 120rpx;
  221. margin-bottom: 60rpx;
  222. border-radius: 20%;
  223. }
  224. .welcome-text {
  225. font-size: 48rpx;
  226. font-weight: bold;
  227. color: #333333;
  228. margin-bottom: 60rpx;
  229. text-align: left;
  230. align-self: flex-start;
  231. }
  232. .switch-container {
  233. display: flex;
  234. margin-bottom: 40rpx;
  235. align-self: flex-start;
  236. }
  237. .switch-item {
  238. font-size: 28rpx;
  239. color: #999999;
  240. padding: 10rpx 20rpx;
  241. position: relative;
  242. }
  243. .switch-item::after {
  244. content: "";
  245. position: absolute;
  246. bottom: 0;
  247. left: 50%;
  248. transform: translateX(-50%);
  249. width: 60%; /* 控制边框宽度 */
  250. height: 2rpx;
  251. background-color: transparent;
  252. }
  253. .switch-item.active {
  254. color: #333333;
  255. font-weight: 700;
  256. }
  257. .switch-item.active::after {
  258. content: "";
  259. position: absolute;
  260. top: 60rpx;
  261. bottom: 0;
  262. left: 50%;
  263. transform: translateX(-50%);
  264. width: 30%; /* 控制边框宽度 */
  265. height: 7rpx;
  266. background-color: #333333;
  267. }
  268. .input-container {
  269. width: 100%;
  270. margin-bottom: 40rpx;
  271. }
  272. .input-field {
  273. width: 90%;
  274. height: 80rpx;
  275. border-radius: 20rpx;
  276. border: 2rpx solid #e5e5e5;
  277. padding: 0 30rpx;
  278. font-size: 28rpx;
  279. color: #333333;
  280. background-color: #f5f5f5;
  281. }
  282. .phone-input-container {
  283. display: flex;
  284. align-items: center;
  285. width: 95.8%;
  286. height: 80rpx;
  287. border-radius: 20rpx;
  288. border: 2rpx solid #e5e5e5;
  289. background-color: #f5f5f5;
  290. padding: 0 10rpx;
  291. }
  292. .country-code-selector {
  293. display: flex;
  294. align-items: center;
  295. padding: 0 20rpx;
  296. height: 100%;
  297. border-right: 2rpx solid #e5e5e5;
  298. background-color: #f5f5f5;
  299. border-radius: 20rpx 0 0 20rpx;
  300. }
  301. .country-code {
  302. font-size: 28rpx;
  303. color: #333333;
  304. margin-right: 10rpx;
  305. }
  306. .country-flag-img {
  307. width: 40rpx;
  308. height: 40rpx;
  309. margin-right: 10rpx;
  310. }
  311. .arrow-down {
  312. font-size: 20rpx;
  313. color: #999999;
  314. }
  315. .phone-input {
  316. flex: 1;
  317. width: auto;
  318. height: 100%;
  319. border: none;
  320. background-color: transparent;
  321. padding: 0 20rpx;
  322. }
  323. .agreement-container {
  324. /* display: flex; */
  325. align-items: center;
  326. margin-bottom: 40rpx;
  327. align-self: flex-start;
  328. }
  329. .checkbox {
  330. width: 10rpx;
  331. height: 10rpx;
  332. margin-right: 30rpx;
  333. /* flex: content; */
  334. }
  335. .agreement-text {
  336. margin-left: 20rpx;
  337. font-size: 24rpx;
  338. color: #666666;
  339. }
  340. .link {
  341. color: #333333;
  342. font-weight: bold;
  343. text-decoration: underline;
  344. }
  345. .register-btn {
  346. width: 100%;
  347. height: 80rpx;
  348. background-color: #333333;
  349. color: white;
  350. font-size: 32rpx;
  351. font-weight: bold;
  352. border-radius: 40rpx;
  353. margin-bottom: 40rpx;
  354. }
  355. .or-text {
  356. font-size: 24rpx;
  357. color: #999999;
  358. margin-bottom: 40rpx;
  359. }
  360. .third-party-login {
  361. width: 100%;
  362. margin-bottom: 60rpx;
  363. }
  364. .third-party-text {
  365. font-weight: bold;
  366. }
  367. .third-party-btn {
  368. width: 100%;
  369. height: 80rpx;
  370. background-color: white;
  371. border: 2rpx solid #e5e5e5;
  372. border-radius: 40rpx;
  373. display: flex;
  374. align-items: center;
  375. justify-content: center;
  376. margin-bottom: 20rpx;
  377. font-size: 28rpx;
  378. color: #333333;
  379. }
  380. .apple-icon {
  381. width: 30rpx;
  382. height: 30rpx;
  383. margin-right: 20rpx;
  384. }
  385. .google-icon {
  386. width: 30rpx;
  387. height: 30rpx;
  388. margin-right: 20rpx;
  389. }
  390. .existing-account {
  391. display: flex;
  392. align-items: center;
  393. }
  394. .account-text {
  395. font-size: 24rpx;
  396. color: #666666;
  397. }
  398. .login-link {
  399. font-size: 24rpx;
  400. font-weight: bold;
  401. color: #333333;
  402. margin-left: 10rpx;
  403. text-decoration: underline;
  404. }
  405. </style>