Browse Source

完成登录注册页面布局

wangyi/feature-20251022162725-启动页登录注册
Ethereal 1 month ago
parent
commit
04c80b494d
  1. 9
      components/login-prompt.vue
  2. 526
      pages/start/Registration/Registration.vue
  3. 11
      pages/start/login/login.vue

9
components/login-prompt.vue

@ -10,7 +10,7 @@
<button class="visitor-btn" @click="continueAsVisitor">
以访客身份继续
</button>
<text class="prompt-title-small">如果您还没有账号点击注册</text>
<text class="prompt-title-small" @click="goRegister">如果您还没有账号点击注册</text>
</view>
</view>
</template>
@ -49,6 +49,13 @@ const goLogin = () => {
});
hide();
};
//
const goRegister = () => {
uni.navigateTo({
url: "/pages/start/Registration/Registration",
});
hide();
};
// 访
const continueAsVisitor = () => {

526
pages/start/Registration/Registration.vue

@ -1,12 +1,25 @@
<template>
<view class="login-registration-container">
<!-- 自定义导航栏 -->
<view class="custom-navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
<view class="nav-left">
<text class="back-btn" @click="goToLogin"></text>
</view>
<view
class="custom-navbar"
:style="{ paddingTop: safeAreaInsets?.top + 'px' }"
>
<!-- <view class="nav-left">
<text class="back-btn" @click="goToIndex"></text>
</view> -->
<view class="nav-right">
<text class="headphone-btn">🎧</text>
<image
class="icons"
src="../../../static/icons/Headset.png"
alt="联系客服"
/>
<image
class="icons"
@click="goToIndex"
src="../../../static/icons/Frame.png"
alt="返回首页"
/>
</view>
</view>
@ -14,95 +27,186 @@
<!-- <image class="logo" src="/static/logo.png" mode="aspectFit"></image> -->
<!-- 欢迎语 -->
<text class="welcome-text">欢迎来到 DeepChart</text>
<text class="welcome-text">欢迎来到DeepChart</text>
<!-- 邮箱/手机号切换 -->
<view class="switch-container">
<text
class="switch-item"
:class="{ active: switchType === 'Email' }"
@click="switchEmail">邮箱</text>
@click="switchEmail"
>邮箱</text
>
<text
class="switch-item"
:class="{ active: switchType === 'Phone' }"
@click="switchPhone">手机号</text>
@click="switchPhone"
>手机号</text
>
</view>
<!-- 输入框 -->
<view class="input-container">
<input
v-if="switchType === 'Email'"
class="input-field"
type="text"
placeholder="输入邮箱地址"
v-model="email"
/>
<input
v-else
class="input-field"
type="text"
placeholder="输入手机号"
v-model="phone"
/>
<view v-if="switchType === 'Email'">
<!-- 修改邮箱输入框容器将图标包含在内 -->
<view class="input-with-icon">
<image
class="input-icon"
src="../../../static/icons/Mail.png"
alt=""
/>
<input
class="input-field"
type="text"
placeholder="请输入邮箱"
v-model="email"
/>
<view>
<button
class="send-code-btn-email"
:disabled="isCodeBtnDisabled"
:class="{ 'send-code-btn-disabled': isCodeBtnDisabled }"
@click="sendCode"
>
<text
class="send-code-text"
:class="{ 'send-code-btn-disabled-text': isCodeBtnDisabled }"
>{{ codeBtnText }}</text
>
</button>
</view>
</view>
<view class="input-with-icon">
<image
class="input-icon"
src="../../../static/icons/Text-recognition.png"
alt=""
/>
<input
class="input-field"
type="text"
placeholder="请输入验证码"
v-model="password"
/>
</view>
</view>
<view v-if="switchType === 'Phone'" class="phone-input-container">
<view class="country-code-selector" @click="showCountryPicker">
<image
class="country-flag-img"
src="../../../static/icons/Iphone.png"
mode="aspectFit"
></image>
<text class="country-code">{{ selectedCountry.code }}</text>
<!-- <text class="arrow-down"></text> -->
</view>
<input
class="input-field phone-input"
type="number"
placeholder="输入手机号"
v-model="phone"
@input="onPhoneInput"
/>
<view>
<button
class="send-code-btn"
:disabled="isCodeBtnDisabled"
:class="{ 'send-code-btn-disabled': isCodeBtnDisabled }"
@click="sendCode"
>
<text
class="send-code-text"
:class="{ 'send-code-btn-disabled-text': isCodeBtnDisabled }"
>{{ codeBtnText }}</text
>
</button>
</view>
</view>
<view v-if="switchType === 'Phone'" class="input-with-icon">
<image
class="input-icon"
src="../../../static/icons/Text-recognition.png"
alt=""
/>
<input
class="input-field"
type="text"
placeholder="请输入验证码"
v-model="password"
/>
</view>
</view>
<!-- 用户协议 -->
<view class="agreement-container">
<checkbox class="checkbox" @click="checkboxClick"/>
<text class="agreement-text"
<view @click="changeCheckbox" class="agreement-container-one">
<image class="checkbox" :src="checkboxUrl"></image>
<text class="agreement-text-one"
>接受 <text class="link" @click="openAgreement">用户协议</text>
<text class="link" @click="openPrivacy">隐私政策</text></text
>
</view>
<!-- 注册按钮 -->
<button class="register-btn" @click="register">注册</button>
<!-- 或者 -->
<text class="or-text">或者</text>
<text class="or-text" @click="goToLogin"
>已有账号登录
</text>
<!-- 第三方登录 -->
<view class="third-party-login">
<view class="third-party-btn" @click="loginWithApple">
<image
class="apple-icon"
src="/static/apple-icon.png"
mode="aspectFit"
></image>
<text class="third-party-text">通过 Apple 继续</text>
</view>
<view class="third-party-btn" @click="loginWithGoogle">
<image
class="google-icon"
src="/static/google-icon.png"
mode="aspectFit"
></image>
<text class="third-party-text">通过 Google 继续</text>
</view>
</view>
<!-- 已有账号 -->
<view class="existing-account">
<text class="account-text">已有账号</text>
<text class="login-link" @click="goToLogin">登录</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { ref } from "vue";
//
import countryList from "../login/list";
const email = ref("");
const password = ref("");
const phone = ref("");
const agreed = ref(false);
const switchType = ref("Email"); //
const { safeAreaInsets } = uni.getSystemInfoSync()
const { safeAreaInsets } = uni.getSystemInfoSync();
const codeBtnText = ref("获取验证码");
const isCodeBtnDisabled = ref(false); //
const checkboxUrl = ref("../../../static/icons/Check-one-false.png");
// 使list.js
const countries = ref(
countryList.list.map((item) => ({
name: item.name,
code: `+${item.tel}`,
flag: item.flag,
short: item.short,
en: item.en,
}))
);
//
const selectedCountry = ref(
countries.value.find((country) => country.short === "CN") ||
countries.value[0]
);
//
function showCountryPicker() {
uni.showActionSheet({
itemList: countries.value.map(
(country) => `${country.name} ${country.code}`
),
success: function (res) {
selectedCountry.value = countries.value[res.tapIndex];
},
});
}
function goBack() {
function goToIndex() {
//
uni.navigateBack(-1);
uni.navigateTo({
url: "/pages/start/index/index",
});
}
function switchEmail() {
@ -115,8 +219,76 @@ function switchPhone() {
switchType.value = "Phone";
}
function checkboxClick() {
agreed.value = !agreed.value;
function register() {
if (switchType.value === "Email") {
//
if (!email.value) {
uni.showToast({
title: "请输入邮箱地址",
icon: "none",
});
return;
}
//
console.log("登录:", email.value);
}
if (switchType.value === "Phone") {
//
if (!phone.value) {
uni.showToast({
title: "请输入手机号码",
icon: "none",
});
return;
}
//
console.log("登录:", phone.value);
}
}
function goToLogin() {
//
uni.navigateTo({
url: "/pages/start/login/login",
});
}
function onPhoneInput(e) {
//
const value = e.detail.value;
// 使 isNaN
if (isNaN(value)) {
phone.value = "";
} else {
phone.value = value;
}
}
function sendCode() {
//
if (isCodeBtnDisabled.value) return;
//
isCodeBtnDisabled.value = true;
codeBtnText.value = "重新发送";
let time = 6;
const timer = setInterval(() => {
time--;
codeBtnText.value = "重新发送 " + time + "s";
if (time <= 0) {
clearInterval(timer);
codeBtnText.value = "重新发送";
//
isCodeBtnDisabled.value = false;
}
}, 1000);
return;
}
function openAgreement() {
@ -130,59 +302,17 @@ function openAgreement() {
function openPrivacy() {
//
console.log("打开隐私政策");
uni.navigateTo({
uni.navigateTo({
url: "/pages/start/privacy/privacy",
});
}
function register() {
//
if (switchType.value === "Email" && !email.value) {
uni.showToast({
title: "请输入邮箱地址",
icon: "none",
});
return;
}
if (switchType.value === "Phone" && !phone.value) {
uni.showToast({
title: "请输入手机号",
icon: "none",
});
return;
}
if (!agreed.value) {
uni.showToast({
title: "请同意用户协议和隐私政策",
icon: "none",
});
return;
}
//
if (switchType.value === "Email") {
console.log("邮箱注册:", email.value);
} else {
console.log("手机号注册:", phone.value);
}
}
function loginWithApple() {
// Apple
console.log("通过Apple登录");
}
function loginWithGoogle() {
// Google
console.log("通过Google登录");
}
function goToLogin() {
//
uni.navigateTo({
url: "/pages/start/login/login",
});
function changeCheckbox() {
agreed.value = !agreed.value;
checkboxUrl.value = agreed.value
? "../../../static/icons/Check-one-true.png"
: "../../../static/icons/Check-one-false.png";
}
</script>
@ -192,7 +322,7 @@ function goToLogin() {
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 40rpx;
padding: 0 70rpx;
height: 100vh;
background-color: #ffffff;
}
@ -222,6 +352,13 @@ function goToLogin() {
justify-content: flex-end;
}
.icons {
margin: 20rpx;
width: 40rpx;
height: 40rpx;
/* margin-right: 10rpx; */
}
.back-btn,
.headphone-btn {
font-size: 36rpx;
@ -245,6 +382,7 @@ function goToLogin() {
/* text-align: left; */
/* align-self: flex-start; */
}
.switch-container {
display: flex;
margin-bottom: 40rpx;
@ -259,12 +397,13 @@ function goToLogin() {
}
.switch-item::after {
content: '';
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60%; /* 控制边框宽度 */
width: 60%;
/* 控制边框宽度 */
height: 2rpx;
background-color: transparent;
}
@ -275,47 +414,165 @@ function goToLogin() {
}
.switch-item.active::after {
content: '';
content: "";
position: absolute;
top: 60rpx;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 30%; /* 控制边框宽度 */
width: 30%;
/* 控制边框宽度 */
height: 7rpx;
background-color: #333333;
}
.input-container {
width: 100%;
margin-bottom: 40rpx;
}
/* 添加图标输入框样式 */
.input-with-icon {
display: flex;
align-items: center;
width: 100%;
height: 80rpx;
border-bottom: 2rpx solid #e5e5e5;
margin-bottom: 20rpx;
}
.input-icon {
width: 40rpx;
height: 40rpx;
margin: 0 20rpx;
}
.input-field {
width: 90%;
flex: 1;
height: 80rpx;
border-radius: 20rpx;
border: 2rpx solid #e5e5e5;
padding: 0 30rpx;
padding: 15rpx 0;
font-size: 28rpx;
color: #333333;
background-color: #f5f5f5;
border: none;
background-color: transparent;
}
.phone-input-container {
display: flex;
align-items: center;
width: 95.8%;
height: 80rpx;
/* border-radius: 20rpx; */
/* border: 2rpx solid #e5e5e5; */
/* background-color: #f5f5f5; */
padding: 0 10rpx;
border-bottom: 2rpx solid #e5e5e5;
margin-bottom: 20rpx;
}
.country-code-selector {
display: flex;
align-items: center;
padding: 0 10rpx;
padding-bottom: 1rpx;
height: 100%;
/* border-right: 2rpx solid #e5e5e5; */
/* background-color: #f5f5f5; */
border-radius: 20rpx 0 0 20rpx;
}
.country-code {
font-size: 28rpx;
color: #333333;
margin-right: 10rpx;
}
.country-flag-img {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
.arrow-down {
font-size: 20rpx;
color: #999999;
}
.phone-input {
flex: 1;
width: auto;
height: 100%;
border: none;
background-color: transparent;
padding: 0 0rpx;
}
.send-code-btn {
width: 200rpx;
height: 60rpx;
display: inline-flex;
padding: 0rpx 10rpx;
justify-content: center;
align-items: center;
gap: 10px;
border-radius: 4px;
background: #000;
}
.send-code-btn-email {
width: 200rpx;
height: 60rpx;
display: inline-flex;
padding: 0rpx 10rpx;
justify-content: center;
align-items: center;
gap: 10px;
border-radius: 4px;
background: #000;
margin-right: 15rpx;
}
.send-code-btn-disabled {
background: #e6e6e6;
/* 禁用状态下的灰色背景 */
}
.send-code-btn-disabled-text {
color: #999999 !important;
}
.send-code-text {
color: #fff;
font-size: 28rpx;
}
.agreement-container-one {
display: flex;
align-items: center;
align-self: flex-start;
margin-bottom: 80rpx;
}
.agreement-container {
/* display: flex; */
display: flex;
align-items: center;
margin-bottom: 40rpx;
margin-top: -75.5rpx;
align-self: flex-start;
}
.checkbox {
width: 10rpx;
height: 10rpx;
margin-right: 30rpx;
width: 30rpx;
height: 30rpx;
margin-left: 20rpx;
/* flex: content; */
}
.agreement-text-one {
font-size: 22rpx;
color: #666666;
text-align: center;
margin-left: 10rpx;
}
.agreement-text {
margin-left: 20rpx;
font-size: 24rpx;
@ -331,7 +588,7 @@ function goToLogin() {
.register-btn {
width: 100%;
height: 80rpx;
background-color: #333333;
background-color: #000000;
color: white;
font-size: 32rpx;
font-weight: bold;
@ -340,25 +597,29 @@ function goToLogin() {
}
.or-text {
flex-direction: column;
font-size: 24rpx;
color: #999999;
margin-bottom: 40rpx;
margin-bottom: 100rpx;
}
.third-party-login {
width: 100%;
margin-bottom: 60rpx;
}
.third-party-text {
color: #ffffff;
font-weight: bold;
white-space: pre;
}
.third-party-btn {
width: 100%;
height: 80rpx;
background-color: white;
border: 2rpx solid rgb(249, 249, 249);
border-radius: 20rpx;
background-color: rgb(0, 0, 0);
border: 2rpx solid #e5e5e5;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
@ -367,15 +628,10 @@ function goToLogin() {
color: #333333;
}
.google-icon,
.apple-icon {
width: 30rpx;
height: 30rpx;
margin-right: 20rpx;
}
.google-icon {
width: 30rpx;
height: 30rpx;
width: 60rpx;
height: 60rpx;
margin-right: 20rpx;
}

11
pages/start/login/login.vue

@ -187,6 +187,12 @@
><text @click="recoverPassword">忘记ID/密码</text>
</text>
</view>
<view v-else class="agreement-container">
<text class="agreement-text">
<!-- 添加占位元素防止页面变形 -->
<text style="visibility: hidden;">占位符</text>
</text>
</view>
<!-- 注册按钮 -->
<button class="register-btn" @click="register">登录</button>
@ -667,8 +673,8 @@ function changeCheckbox(){
.agreement-container {
display: flex;
align-items: center;
margin-bottom: 40rpx;
margin-top: -75.5rpx;
margin-bottom: 30rpx;
margin-top: -60rpx;
align-self: flex-start;
}
@ -690,6 +696,7 @@ function changeCheckbox(){
margin-left: 20rpx;
font-size: 24rpx;
color: #666666;
white-space: nowrap;
}
.link {

Loading…
Cancel
Save