Files
PartsInquiry/frontend/pages/auth/register.vue
2025-09-24 20:35:15 +08:00

507 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="register-container">
<!-- 背景装饰 -->
<view class="background-decoration">
<view class="circle circle-1"></view>
<view class="circle circle-2"></view>
<view class="circle circle-3"></view>
</view>
<!-- 主要内容卡片 -->
<view class="register-card">
<!-- 顶部Logo区域 -->
<view class="header-section">
<view class="logo-container">
<view class="logo-icon">
<svg viewBox="0 0 24 24" class="icon">
<path d="M12 2C13.1 2 14 2.9 14 4C14 5.1 13.1 6 12 6C10.9 6 10 5.1 10 4C10 2.9 10.9 2 12 2ZM21 9V7L15 4V6C15 7.66 13.66 9 12 9S9 7.66 9 6V4L3 7V9C3 10.1 3.9 11 5 11V17C5 18.1 5.9 19 7 19H9C9 20.1 9.9 21 11 21H13C14.1 21 15 20.1 15 19H17C18.1 19 19 18.1 19 17V11C20.1 11 21 10.1 21 9Z"/>
</svg>
</view>
<text class="app-name">配件询价</text>
</view>
<text class="welcome-text">创建账户</text>
<text class="subtitle">请填写以下信息完成注册</text>
</view>
<!-- 表单区域 -->
<view class="form-section">
<!-- 店铺名称 -->
<view class="input-group">
<view class="input-container" :class="{ focused: shopNameFocused, filled: form.shopName }">
<view class="input-icon">
<svg viewBox="0 0 24 24" class="icon">
<path d="M12,3L2,12H5V20H19V12H22L12,3M12,8.75A2.25,2.25 0 0,1 14.25,11A2.25,2.25 0 0,1 12,13.25A2.25,2.25 0 0,1 9.75,11A2.25,2.25 0 0,1 12,8.75Z"/>
</svg>
</view>
<input
class="input-field"
v-model.trim="form.shopName"
type="text"
placeholder="请输入店铺名称"
@focus="shopNameFocused = true"
@blur="shopNameFocused = false"
/>
</view>
</view>
<!-- 姓名 -->
<view class="input-group">
<view class="input-container" :class="{ focused: nameFocused, filled: form.name }">
<view class="input-icon">
<svg viewBox="0 0 24 24" class="icon">
<path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"/>
</svg>
</view>
<input
class="input-field"
v-model.trim="form.name"
type="text"
placeholder="请输入您的姓名"
@focus="nameFocused = true"
@blur="nameFocused = false"
/>
</view>
</view>
<!-- 手机号 -->
<view class="input-group">
<view class="input-container" :class="{ focused: phoneFocused, filled: form.phone }">
<view class="input-icon">
<svg viewBox="0 0 24 24" class="icon">
<path d="M6.62,10.79C8.06,13.62 10.38,15.94 13.21,17.38L15.41,15.18C15.69,14.9 16.08,14.82 16.43,14.93C17.55,15.3 18.75,15.5 20,15.5A1,1 0 0,1 21,16.5V20A1,1 0 0,1 20,21A17,17 0 0,1 3,4A1,1 0 0,1 4,3H7.5A1,1 0 0,1 8.5,4C8.5,5.25 8.7,6.45 9.07,7.57C9.18,7.92 9.1,8.31 8.82,8.59L6.62,10.79Z"/>
</svg>
</view>
<input
class="input-field"
v-model.trim="form.phone"
type="number"
placeholder="请输入手机号"
maxlength="11"
@focus="phoneFocused = true"
@blur="phoneFocused = false"
/>
</view>
</view>
<!-- 密码 -->
<view class="input-group">
<view class="input-container" :class="{ focused: passwordFocused, filled: form.password }">
<view class="input-icon">
<svg viewBox="0 0 24 24" class="icon">
<path d="M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z"/>
</svg>
</view>
<input
class="input-field"
v-model.trim="form.password"
password
placeholder="请输入密码至少6位"
@focus="passwordFocused = true"
@blur="passwordFocused = false"
/>
</view>
</view>
<!-- 确认密码 -->
<view class="input-group">
<view class="input-container" :class="{ focused: confirmPasswordFocused, filled: form.confirmPassword }">
<view class="input-icon">
<svg viewBox="0 0 24 24" class="icon">
<path d="M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z"/>
</svg>
</view>
<input
class="input-field"
v-model.trim="form.confirmPassword"
password
placeholder="请再次输入密码"
@focus="confirmPasswordFocused = true"
@blur="confirmPasswordFocused = false"
/>
</view>
</view>
</view>
<!-- 按钮区域 -->
<view class="actions-section">
<button class="register-button" @click="onRegister">
<text class="button-text">立即注册</text>
</button>
<button class="login-button" @click="onGoLogin">
<text class="button-text">已有账户去登录</text>
</button>
</view>
<!-- 提示信息 -->
<view class="footer-section">
<text class="hint-text">注册即表示您同意我们的服务条款和隐私政策</text>
</view>
</view>
</view>
</template>
<script>
import { post } from '../../common/http.js'
export default {
data() {
return {
form: {
shopName: '',
name: '',
phone: '',
password: '',
confirmPassword: ''
},
shopNameFocused: false,
nameFocused: false,
phoneFocused: false,
passwordFocused: false,
confirmPasswordFocused: false
}
},
methods: {
validate() {
const phone = String(this.form.phone || '').trim();
const ok = /^1[3-9]\d{9}$/.test(phone);
if (!ok) { uni.showToast({ title: '请输入正确的手机号', icon: 'none' }); return false }
if (!this.form.password) { uni.showToast({ title: '请输入密码', icon: 'none' }); return false }
if (this.form.password.length < 6) { uni.showToast({ title: '密码至少6位', icon: 'none' }); return false }
if (!this.form.confirmPassword) { uni.showToast({ title: '请确认密码', icon: 'none' }); return false }
if (this.form.password !== this.form.confirmPassword) { uni.showToast({ title: '两次密码不一致', icon: 'none' }); return false }
return true;
},
async onRegister() {
if (!this.validate()) return;
const phone = String(this.form.phone||'').trim();
const name = String(this.form.name||'').trim();
const password = String(this.form.password||'');
try {
const data = await post('/api/auth/register', { phone, name: name || undefined, password });
if (data && data.token) {
uni.setStorageSync('TOKEN', data.token)
if (data.user && data.user.phone) uni.setStorageSync('USER_MOBILE', data.user.phone)
uni.showToast({ title: '注册成功', icon: 'none' })
setTimeout(() => { uni.reLaunch({ url: '/pages/index/index' }) }, 300)
}
} catch(e) {
const msg = (e && e.message) || '注册失败'
uni.showToast({ title: msg, icon: 'none' })
}
},
onGoLogin() {
uni.navigateTo({
url: '/pages/auth/login'
});
}
}
}
</script>
<style lang="scss">
// 主容器
.register-container {
position: relative;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 40rpx 20rpx;
overflow: hidden;
}
// 背景装饰圆形
.background-decoration {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 0;
.circle {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
&.circle-1 {
width: 220rpx;
height: 220rpx;
top: 8%;
left: 12%;
animation: float 7s ease-in-out infinite;
}
&.circle-2 {
width: 180rpx;
height: 180rpx;
top: 65%;
right: 10%;
animation: float 9s ease-in-out infinite reverse;
}
&.circle-3 {
width: 120rpx;
height: 120rpx;
bottom: 15%;
left: 25%;
animation: float 6s ease-in-out infinite;
}
}
}
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); }
50% { transform: translateY(-25px) rotate(5deg); }
}
// 主卡片容器
.register-card {
position: relative;
z-index: 1;
width: 90%;
max-width: 680rpx;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-radius: 32rpx;
padding: 50rpx 40rpx 45rpx;
box-shadow: 0 25rpx 70rpx rgba(0, 0, 0, 0.12);
border: 1rpx solid rgba(255, 255, 255, 0.3);
}
// 头部区域
.header-section {
text-align: center;
margin-bottom: 45rpx;
.logo-container {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
margin-bottom: 20rpx;
.logo-icon {
width: 60rpx;
height: 60rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 36rpx;
height: 36rpx;
fill: white;
}
}
.app-name {
font-size: 36rpx;
font-weight: 700;
color: #2d3748;
letter-spacing: 1rpx;
}
}
.welcome-text {
display: block;
font-size: 48rpx;
font-weight: 700;
color: #2d3748;
margin-bottom: 8rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.subtitle {
display: block;
font-size: 28rpx;
color: #718096;
font-weight: 400;
}
}
// 表单区域
.form-section {
margin-bottom: 40rpx;
.input-group {
margin-bottom: 24rpx;
.input-container {
position: relative;
background: #f7fafc;
border: 2rpx solid #e2e8f0;
border-radius: 16rpx;
display: flex;
align-items: center;
transition: all 0.3s ease;
&.focused {
border-color: #667eea;
background: #ffffff;
box-shadow: 0 0 0 6rpx rgba(102, 126, 234, 0.1);
transform: translateY(-2rpx);
}
&.filled {
background: #ffffff;
border-color: #cbd5e0;
}
.input-icon {
display: flex;
align-items: center;
justify-content: center;
width: 50rpx;
margin-left: 20rpx;
.icon {
width: 32rpx;
height: 32rpx;
fill: #a0aec0;
transition: fill 0.3s ease;
}
}
&.focused .input-icon .icon {
fill: #667eea;
}
.input-field {
flex: 1;
background: transparent;
border: none;
padding: 24rpx 20rpx 24rpx 12rpx;
font-size: 32rpx;
color: #2d3748;
&::placeholder {
color: #a0aec0;
font-size: 28rpx;
}
}
}
}
}
// 按钮区域
.actions-section {
margin-bottom: 30rpx;
.register-button {
width: 100%;
height: 96rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 16rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&:active {
transform: translateY(2rpx);
box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.3);
}
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.2) 0%, transparent 50%);
opacity: 0;
transition: opacity 0.3s ease;
}
&:active::before {
opacity: 1;
}
.button-text {
font-size: 32rpx;
font-weight: 600;
color: white;
letter-spacing: 1rpx;
}
}
.login-button {
width: 100%;
height: 86rpx;
background: transparent;
border: 2rpx solid #e2e8f0;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&:active {
background: #f7fafc;
border-color: #cbd5e0;
transform: translateY(1rpx);
}
.button-text {
font-size: 28rpx;
font-weight: 500;
color: #718096;
}
}
}
// 页脚区域
.footer-section {
text-align: center;
.hint-text {
display: block;
font-size: 24rpx;
color: #a0aec0;
line-height: 1.6;
margin-bottom: 12rpx;
}
.static-hint {
display: block;
font-size: 22rpx;
color: #a0aec0;
line-height: 1.5;
background: rgba(160, 174, 192, 0.1);
padding: 12rpx 16rpx;
border-radius: 10rpx;
border: 1rpx solid rgba(160, 174, 192, 0.2);
}
}
// 响应式设计
@media (max-width: 750rpx) {
.register-card {
margin: 20rpx;
padding: 40rpx 30rpx 35rpx;
}
.header-section .welcome-text {
font-size: 42rpx;
}
.form-section .input-group {
margin-bottom: 20rpx;
}
}
</style>