2025-09-15

This commit is contained in:
2025-09-15 21:03:25 +08:00
parent 7f7ef99c18
commit 178bd0d1e9
26 changed files with 1606 additions and 25 deletions

View File

@@ -12,21 +12,24 @@
<view class="login-form">
<u-form :model="userLogin.userForm" ref="userLoginRef" :border-bottom="false" :error-type="['message']"
label-width="0">
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/login/user.png" prop="username">
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/user.png" prop="username">
<u-input v-model="userLogin.userForm.username" placeholder="请输入用户名或手机号"
placeholder-style="color: #737373;" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/login/Lock.png" prop="password">
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Lock.png" prop="password">
<u-input type="password" v-model="userLogin.userForm.password" placeholder="请输入密码"
placeholder-style="color: #737373;" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/login/Globe.png" prop="code">
<u-input v-model="userLogin.userForm.code" placeholder="请输入验证码"
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Globe.png" prop="captcha">
<u-input v-model="userLogin.userForm.captcha" placeholder="请输入验证码"
placeholder-style="color: #737373;" />
<template v-slot:right>
<image class="captcha-img" :src="captcha" mode=""></image>
</template>
</u-form-item>
<view class="reflash" @click="reflash">
<image class="reflash-icon" src="/static/login/Repeat.png" mode=""></image>
刷新
<image class="reflash-icon" src="/static/icon/Repeat.png" mode=""></image>
刷新验证码
</view>
<view class="rember">
<u-checkbox v-model="userLogin.userForm.is_rember">记住我</u-checkbox>
@@ -35,8 +38,8 @@
<u-button class="submit-btn" :ripple="true" shape="circle" type="primary" @click="submit">登录</u-button>
<view class="register">
<view class="register-text">没有账号</view>
<view class="register-link">点击注册
<image class="register-link-icon" src="/static/Chevron right.png" mode=""></image>
<view class="register-link" @click="handleRegister">点击注册
<image class="register-link-icon" src="/static/icon/Chevron right.png" mode=""></image>
</view>
</view>
</u-form>
@@ -45,15 +48,24 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { onMounted, reactive, ref } from 'vue';
import { onLoad, onReady } from '@dcloudio/uni-app';
import { captchaAPI } from '@/api/captcha.js';
// 表单图标样式
const inputIcon = {
width: '32rpx',
verticalAlign: 'middle'
}
// 登录表单
const captcha = ref()
const userLoginRef = ref()
const userLogin = reactive({
userForm: {
username: '',
password: '',
code: '',
captcha: '',
is_rember: false
},
ruls: {
@@ -81,14 +93,29 @@
}
})
// 初始化绑定
onReady(() => {
userLoginRef.value.setRules(userLogin.ruls);
});
onMounted(() => {
loadCaptcha()
})
// 刷新
const reflash = () => {
userLoginRef.value.resetFields()
// userLoginRef.value.resetFields()
loadCaptcha()
}
// 请求验证码
const loadCaptcha = () => {
captchaAPI.generate().then(res => {
captcha.value = res.data.image
})
}
// 登录处理
const submit = () => {
userLoginRef.value.validate((valid : any) => {
if (valid) {
@@ -97,9 +124,11 @@
});
}
const inputIcon = {
width: '32rpx',
verticalAlign: 'middle'
// 注册
const handleRegister = () => {
uni.redirectTo({
url: '/pages/register/register'
})
}
</script>
@@ -145,6 +174,11 @@
.login-form {
padding: 10rpx 32rpx;
.captcha-img {
width: 200rpx;
height: 80rpx;
}
.reflash {
width: 100%;
display: flex;
@@ -192,7 +226,7 @@
font-style: Expanded Semibold;
font-size: 40rpx;
leading-trim: NONE;
line-height: 28px;
line-height: 46rpx;
letter-spacing: 0%;
text-align: center;
}
@@ -207,7 +241,7 @@
// 文字
font-family: Work Sans;
font-weight: 400;
font-size: 13px;
font-size: 26rpx;
leading-trim: NONE;
line-height: 100%;
letter-spacing: -2%;

490
pages/register/register.vue Normal file
View File

@@ -0,0 +1,490 @@
<template>
<view class="register-container">
<view class="register-title">
<view class="title">
用户注册
</view>
<view class="sub-title">
创建你的账号欢迎来到炬融圈
</view>
</view>
<view class="register-main">
<u-form :model="userRegister.userRegisterForm" class="register-form" ref="userRegisterRef"
:border-bottom="false" :error-type="['message']" label-width="0">
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Phone.png" prop="phone">
<u-input v-model="userRegister.userRegisterForm.phone" placeholder="请输入手机号" maxlength="11"
type="number" placeholder-style="color: #737373;" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Mail.png" prop="smsCode">
<u-input v-model="userRegister.userRegisterForm.smsCode" placeholder="请输入短信验证码" maxlength="6"
type="number" placeholder-style="color: #737373;" />
<template v-slot:right>
<u-verification-code ref="msgCodeRef" @change="codeMsgChange"></u-verification-code>
<u-button :disabled="!canSendSMS" size="mini" type="primary"
@tap="getMsgCode">{{msgCodeBtn}}</u-button>
</template>
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Map pin.png" prop="regionLabel">
<u-input type="select" v-model="userRegister.userRegisterForm.regionLabel" placeholder="请选择省市区"
placeholder-style="color: #737373;" @click="showRegitionPicker = true" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Lock.png" prop="password">
<u-input type="password" v-model="userRegister.userRegisterForm.password" placeholder="请输入密码"
maxlength="20" placeholder-style="color: #737373;" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Lock.png" prop="confirmPassword">
<u-input type="password" v-model="userRegister.userRegisterForm.confirmPassword" maxlength="20"
placeholder="请输入确认密码" placeholder-style="color: #737373;" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Globe.png" prop="captcha">
<u-input v-model="userRegister.userRegisterForm.captcha" placeholder="请输入验证码" maxlength="4"
placeholder-style="color: #737373;" />
<template v-slot:right>
<image @click="loadCaptcha" class="captcha-img" :src="captcha" mode=""></image>
</template>
</u-form-item>
</u-form>
<view class="reflash" @click="loadCaptcha">
<image class="reflash-icon" src="/static/icon/Repeat.png" mode=""></image>
刷新验证码
</view>
<u-checkbox v-model="is_read" size="26" class="must-read" :label-disabled="true">
我已阅读并同意<span @click="showFile1=true">用户协议</span><span @click="showFile2=true">隐私政策</span>
</u-checkbox>
<u-button type="primary" class="register-btn" @click="handleRegister">立即注册</u-button>
<view class="login">
<view class="login-text">没有账号</view>
<view class="login-link" @click="handleLogin">立即登录</view>
</view>
</view>
<!-- 省市区 -->
<u-select v-model="showRegitionPicker" :list="regionOptions" mode="mutil-column-auto" label-name="label"
value-name="code" child-name="children" @confirm="handleRegion"></u-select>
<!-- 协议1 -->
<u-popup v-model="showFile1" mode="bottom" border-radius="14" :closeable="true">
<view class="file">
<h3>用户协议</h3>
<p>1. 用户应当遵守法律法规不得发布违法违规内容</p>
<p>2. 用户对自己发布的内容承担全部责任</p>
<p>3. 平台有权对违规内容进行删除或限制</p>
<p>4. 用户应当保护好自己的账号安全</p>
<p>5. 平台保留修改本协议的权利</p>
</view>
</u-popup>
<!-- 协议2 -->
<u-popup v-model="showFile2" mode="bottom" border-radius="14" :closeable="true">
<view class="file">
<h3>隐私政策</h3>
<p>1. 我们重视用户隐私保护</p>
<p>2. 我们只收集必要的用户信息</p>
<p>3. 用户信息仅用于提供服务</p>
<p>4. 我们不会向第三方泄露用户信息</p>
<p>5. 用户有权查看修改或删除个人信息</p>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import {
onMounted,
reactive,
ref,
computed
} from 'vue';
import {
onReady
} from '@dcloudio/uni-app';
import {
captchaAPI
} from '../../api/captcha.js';
import {
commonAPI
} from '../../api/common.js';
import {
authAPI
} from '../../api/auth.js';
// 输入框图标样式
const inputIcon = {
width: '32rpx',
verticalAlign: 'middle'
}
// 省市区
const showRegitionPicker = ref(false)
const regionOptions = ref()
// 加载省市区
const loadRegion = () => {
commonAPI.getRegion().then(res => {
if (res.success) {
regionOptions.value = res.data
}
})
}
// 选择省市区
const handleRegion = (e) => {
console.log(e);
userRegister.userRegisterForm.regionLabel = e[0].label + "/" + e[1].label + "/" + e[2].label
userRegister.userRegisterForm.region = e[2].value
}
// 验证码
const captcha = ref()
const captchaId = ref()
// 请求验证码
const loadCaptcha = () => {
captchaAPI.generate().then(res => {
captcha.value = res.data.image
captchaId.value = res.data.captchaId
})
}
// 校验规则
const validatePassword = (rule, value, callback) => {
if (!value) {
callback(new Error('请输入密码'));
} else if (value.length < 6) {
callback(new Error('密码至少6个字符'));
} else if (value.length > 20) {
callback(new Error('密码不能超过20个字符'));
} else if (!/(?=.*[a-zA-Z])(?=.*\d)/.test(value)) {
callback(new Error('密码必须包含字母和数字'));
} else {
// 如果确认密码已输入,重新验证确认密码
if (userRegister.userRegisterForm.confirmPassword) {
userRegisterRef.value?.validateField('confirmPassword');
}
callback();
}
};
const validateConfirmPassword = (rule, value, callback) => {
if (!value) {
callback(new Error('请确认密码'));
} else if (value !== userRegister.userRegisterForm.password) {
callback(new Error('两次输入的密码不一致'));
} else {
callback();
}
};
// 注册表单
const userRegisterRef = ref()
const userRegister = reactive({
userRegisterForm: {
username: '13758452159',
phone: '13758452159',
smsCode: 'asrfdv',
region: '',
regionLabel: '',
password: 's123456s',
confirmPassword: 's123456s',
captcha: 'vfjs',
},
rules: {
phone: [{
required: true,
message: '请输入手机号',
trigger: ['blur']
},
{
pattern: /^1[3-9]\d{9}$/,
message: '请输入正确的手机号格式',
trigger: ['blur']
}
],
smsCode: [{
required: true,
message: '请输入短信验证码',
trigger: ['blur']
},
{
pattern: /^\d{6}$/,
message: '短信验证码为6位数字',
trigger: ['blur']
},
],
regionLabel: [{
required: true,
message: '请选择省市区',
trigger: ['change']
}],
password: [{
validator: validatePassword,
trigger: ['blur']
}],
confirmPassword: [{
validator: validateConfirmPassword,
trigger: ['blur']
}],
captcha: [{
required: true,
message: '请输入验证码',
trigger: ['blur']
},
{
min: 4,
max: 4,
message: '验证码长度为4位',
trigger: 'blur'
}
],
}
})
// 注册处理
const handleRegister = async () => {
if (!is_read.value) {
uni.showToast({
title: '请先同意协议',
icon: 'none'
})
return
}
// 等待表单验证完成
const valid = await userRegisterRef.value.validate();
if (valid) {
console.log(valid);
}
// userRegisterRef.value.validate((valid : any) => {
// if (valid) {
// // 验证验证码
// captchaAPI.verify({
// captchaId: captchaId.value,
// captchaText: userRegister.userRegisterForm.captcha
// }).then(verifyResponse => {
// console.log(verifyResponse);
// if (!verifyResponse.data.success) {
// uni.showToast({
// title: verifyResponse.data.message || '验证码错误',
// icon: 'error'
// })
// // 重新加载验证码
// loadCaptcha()
// return
// }
// })
// const registerData = {
// username: userRegister.userRegisterForm.phone,
// phone: userRegister.userRegisterForm.phone,
// city: userRegister.userRegisterForm.region,
// password: userRegister.userRegisterForm.password,
// smsCode: userRegister.userRegisterForm.smsCode,
// captchaId: captchaId.value,
// captchaText: userRegister.userRegisterForm.captcha,
// province: userRegister.userRegisterForm.region,
// }
// authAPI.register(registerData).then(response => {
// // 直接注册成功的情况
// // setToken(response.data.token)
// // setUser(response.data.user)
// console.log(response);
// })
// }
// })
}
// 手机验证码
const msgCodeBtn = ref()
const msgCodeRef = ref()
// 手机验证码变化
const codeMsgChange = (text) => {
msgCodeBtn.value = text;
}
// 是否能够发送手机验证码
const canSendSMS = computed(() => {
const phoneRegex = /^1[3-9]\d{9}$/;
return phoneRegex.test(userRegister.userRegisterForm.phone);
});
// 获取手机验证码
const getMsgCode = () => {
// 校验手机号
if (msgCodeRef.value.canGetCode) {
console.log("发送验证码");
msgCodeRef.value.start();
} else {
uni.showToast({
title: '等待...'
})
}
}
// 是否阅读
const is_read = ref(false)
const showFile1 = ref(false)
const showFile2 = ref(false)
// 跳转登录页面
const handleLogin = () => {
uni.redirectTo({
url: '/pages/login/login'
})
}
onMounted(() => {
loadCaptcha()
loadRegion()
})
onReady(() => {
userRegisterRef.value.setRules(userRegister.rules)
})
</script>
<style scoped lang="scss">
.register-container {
width: 100%;
height: 100vh;
background: linear-gradient(180deg, #BAC9FF 0%, #FFFFFF 100%);
.register-title {
padding-top: 114rpx;
.title {
font-family: SF Pro;
font-weight: 650;
font-style: Expanded Semibold;
font-size: 48rpx;
leading-trim: NONE;
line-height: 80rpx;
letter-spacing: 0%;
text-align: center;
color: #000000;
}
.sub-title {
font-family: Work Sans;
font-weight: 400;
font-size: 26rpx;
leading-trim: NONE;
line-height: 100%;
letter-spacing: -2%;
text-align: center;
color: #5B5B5B;
}
}
.register-main {
.register-form {
padding: 20rpx 98rpx 10rpx;
}
.captcha-img {
width: 200rpx;
height: 80rpx;
}
.reflash {
width: 90%;
margin-bottom: 30rpx;
display: flex;
justify-content: flex-end;
align-items: center;
// 文字
font-family: Work Sans;
font-weight: 400;
font-size: 26rpx;
leading-trim: NONE;
line-height: 100%;
letter-spacing: -2%;
color: #3781EF;
.reflash-icon {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
}
}
.must-read {
padding: 0 76rpx;
font-family: Work Sans;
font-weight: 400;
leading-trim: NONE;
line-height: 100%;
letter-spacing: -2%;
text-align: center;
color: #000000;
text-align: left;
span {
font-family: Work Sans;
font-weight: 400;
font-size: 26rpxpx;
leading-trim: NONE;
line-height: 100%;
letter-spacing: -2%;
text-align: center;
color: #3781EF;
}
}
.register-btn {
margin: 40rpx 54rpx 20rpx;
font-family: SF Pro;
font-weight: 650;
font-style: Expanded Semibold;
font-size: 40rpx;
leading-trim: NONE;
line-height: 46rpx;
letter-spacing: 0%;
text-align: center;
}
.login {
margin: 40rpx 0 80rpx;
padding-bottom: 80rpx;
display: flex;
justify-content: center;
align-items: center;
// 文字
font-family: Work Sans;
font-weight: 400;
font-size: 26rpx;
leading-trim: NONE;
line-height: 100%;
letter-spacing: -2%;
text-align: center;
.login-text {
color: #737373;
}
.login-link {
display: flex;
justify-content: center;
align-items: center;
color: #3781EF;
}
}
}
.file {
padding: 80rpx 40rpx;
}
}
</style>