716 lines
20 KiB
Plaintext
716 lines
20 KiB
Plaintext
<template>
|
||
<view class="page">
|
||
<!-- 顶部:头像 + 登录状态入口(左),右上角蓝牙/WiFi/信号/时间(与 activate-device 页一致) -->
|
||
<view class="header">
|
||
<view class="header-user" @click="onHeaderUserClick">
|
||
<image class="header-avatar" src="/static/images/img-virtual.png" mode="aspectFill"></image>
|
||
<text class="header-name">{{ isLoggedIn ? '已登录' : '未登录' }}</text>
|
||
</view>
|
||
<view class="header-spacer"></view>
|
||
<view class="header-status">
|
||
<image class="status-icon" src="/static/icons/status-bluetooth.png" mode="aspectFit"></image>
|
||
<image class="status-icon status-icon-gap" src="/static/icons/status-wifi.png" mode="aspectFit"></image>
|
||
<image class="status-icon status-icon-gap" src="/static/icons/status-cellular.png" mode="aspectFit"></image>
|
||
<text class="header-time">{{ clockText }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="content">
|
||
<!-- 左大卡:宣传位(限定 5 张,自动轮巡 + 左右滑动浏览) -->
|
||
<view class="card main-card">
|
||
<swiper
|
||
class="card-swiper"
|
||
:autoplay="true"
|
||
:circular="true"
|
||
:interval="4000"
|
||
:duration="400"
|
||
:indicator-dots="true"
|
||
indicator-color="rgba(255, 255, 255, 0.4)"
|
||
indicator-active-color="#FFFFFF"
|
||
>
|
||
<swiper-item v-for="(item, index) in promoImages" :key="index" @click="onPromoClick(index)">
|
||
<image class="card-bg" :src="item" mode="aspectFill"></image>
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
<!-- 右列 -->
|
||
<view class="right-col">
|
||
<!-- 右上卡:推荐位(限定 3 张,自动轮巡 + 左右滑动浏览) -->
|
||
<view class="card top-card">
|
||
<swiper
|
||
class="card-swiper"
|
||
:autoplay="true"
|
||
:circular="true"
|
||
:interval="4000"
|
||
:duration="400"
|
||
:indicator-dots="true"
|
||
indicator-color="rgba(255, 255, 255, 0.4)"
|
||
indicator-active-color="#FFFFFF"
|
||
>
|
||
<swiper-item v-for="(item, index) in recoImages" :key="index" @click="onRecoClick(index)">
|
||
<image class="card-bg" :src="item" mode="aspectFill"></image>
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
<!-- 下排两卡 -->
|
||
<view class="bottom-row">
|
||
<view class="card func-card func-left" @click="onVirtualClick">
|
||
<image class="card-bg" src="/static/images/img-virtual.png" mode="aspectFill"></image>
|
||
<view class="func-badge">
|
||
<image class="func-icon" src="/static/icons/icon-virtual.png" mode="aspectFit"></image>
|
||
<text class="func-text">虚拟体验</text>
|
||
</view>
|
||
</view>
|
||
<view class="card func-card func-right" @click="showModal = true">
|
||
<image class="card-bg" src="/static/images/img-login.png" mode="aspectFill"></image>
|
||
<view class="func-badge">
|
||
<image class="func-icon" src="/static/icons/icon-login.png" mode="aspectFit"></image>
|
||
<text class="func-text">立即登陆</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ============== 登录弹窗 ============== -->
|
||
<view v-if="showModal" class="mask" @click="onMaskClick">
|
||
<view class="modal" @click.stop>
|
||
<!-- 关闭 X -->
|
||
<view class="modal-close" @click="showModal = false">
|
||
<view class="modal-close-line1"></view>
|
||
<view class="modal-close-line2"></view>
|
||
</view>
|
||
<!-- 左侧插画(新容器:蓝描边 + 图居中 aspectFit,不裁切) -->
|
||
<view class="modal-banner-wrap">
|
||
<image class="modal-banner" src="/static/images/login-banner.png" mode="aspectFit"></image>
|
||
</view>
|
||
<!-- 右侧表单 -->
|
||
<view class="modal-form">
|
||
<text class="modal-switch">账号密码登录</text>
|
||
|
||
<!-- 手机号 -->
|
||
<view class="field" :class="{ fieldFocus: focusType === 'phone' }">
|
||
<view class="field-icon">
|
||
<view class="icon-user-1"></view>
|
||
<view class="icon-user-2"></view>
|
||
</view>
|
||
<input
|
||
class="field-input"
|
||
v-model="phone"
|
||
type="number"
|
||
maxlength="11"
|
||
placeholder="请填写手机号"
|
||
placeholder-class="field-placeholder"
|
||
@focus="focusType = 'phone'"
|
||
@blur="focusType = ''"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 验证码:必填,限制 4 位数字,点击唤起数字键盘 -->
|
||
<view class="field" :class="{ fieldFocus: focusType === 'code' }">
|
||
<view class="field-icon">
|
||
<view class="icon-sms-box"></view>
|
||
<view class="icon-sms-flap"></view>
|
||
</view>
|
||
<input
|
||
class="field-input"
|
||
v-model="code"
|
||
type="number"
|
||
maxlength="4"
|
||
placeholder="请填写验证码"
|
||
placeholder-class="field-placeholder"
|
||
@focus="focusType = 'code'"
|
||
@blur="focusType = ''"
|
||
/>
|
||
<text class="code-btn" :class="{ disabled: smsCountdown > 0 }" @click="onGetSms">
|
||
{{ smsBtnText }}
|
||
</text>
|
||
</view>
|
||
|
||
<!-- 提交按钮 -->
|
||
<view class="submit-btn" @click="onSubmitLogin">
|
||
<text class="submit-text">注册或登录</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
// ====== 宣传位 / 推荐位轮播数据 ======
|
||
// 宣传位:限定 5 张(暂用现有素材循环占位,接入投放系统后替换为真实图片列表)
|
||
const promoImages = ref<string[]>([
|
||
'/static/images/bg-main.png',
|
||
'/static/images/bg-top-right.png',
|
||
'/static/images/img-virtual.png',
|
||
'/static/images/img-login.png',
|
||
'/static/images/login-banner.png'
|
||
])
|
||
// 推荐位:限定 3 张
|
||
const recoImages = ref<string[]>([
|
||
'/static/images/bg-top-right.png',
|
||
'/static/images/bg-main.png',
|
||
'/static/images/img-login.png'
|
||
])
|
||
|
||
// 查看投放内容(预留:后续接入真实投放详情/跳转链接)
|
||
function onPromoClick(index : number) : void {
|
||
uni.showToast({ title: '查看投放内容 ' + (index + 1).toString(), icon: 'none' })
|
||
}
|
||
|
||
function onRecoClick(index : number) : void {
|
||
uni.showToast({ title: '查看投放内容 ' + (index + 1).toString(), icon: 'none' })
|
||
}
|
||
|
||
// ====== 登录弹窗状态 ======
|
||
const showModal = ref<boolean>(false)
|
||
const isLoggedIn = ref<boolean>(false)
|
||
const phone = ref<string>('13513321454')
|
||
const code = ref<string>('1234')
|
||
const focusType = ref<string>('')
|
||
// 验证码 60s 倒计时
|
||
const smsCountdown = ref<number>(0)
|
||
// 上次成功获取验证码的时间戳(用于 5s/次 频次限制)
|
||
let lastGetTs : number = 0
|
||
// 倒计时定时器句柄(-1 表示无)
|
||
let _smsTimer : number = -1
|
||
|
||
// 顶部「未登录」入口:未登录时打开登录弹窗,已登录时提示
|
||
function onHeaderUserClick() : void {
|
||
if (isLoggedIn.value) {
|
||
uni.showToast({ title: '已登录', icon: 'none' })
|
||
return
|
||
}
|
||
showModal.value = true
|
||
}
|
||
|
||
// 关闭弹窗:点击遮罩空白处
|
||
function onMaskClick() : void {
|
||
showModal.value = false
|
||
}
|
||
|
||
// 虚拟体验:暂未开放
|
||
function onVirtualClick() : void {
|
||
uni.showToast({ title: '暂未开放', icon: 'none' })
|
||
}
|
||
|
||
// 校验手机号(必填,11 位有效数字,1 开头)
|
||
function isValidPhone(p : string) : boolean {
|
||
if (p.length != 11) return false
|
||
if (!p.startsWith('1')) return false
|
||
for (let i = 0; i < p.length; i++) {
|
||
if (p[i] < '0' || p[i] > '9') return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
// ====== 验证码按钮文案:倒计时中显示「Ns」,倒计时结束显示「重新获取」,初始「获取验证码」 ======
|
||
const hasGotOnce = ref<boolean>(false)
|
||
const smsBtnText = computed<string>((): string => {
|
||
if (smsCountdown.value > 0) return smsCountdown.value.toString() + 's'
|
||
if (hasGotOnce.value) return '重新获取'
|
||
return '获取验证码'
|
||
})
|
||
|
||
// ====== 每日获取次数限制:手机号 / 10 次 / 天(本地按 手机号+日期 计数,接入 API 后由服务端校验) ======
|
||
const SMS_DAILY_LIMIT = 10
|
||
|
||
function smsCountKey() : string {
|
||
const d = new Date()
|
||
return 'sms_count_' + phone.value + '_' + d.getFullYear().toString() + '-' + (d.getMonth() + 1).toString() + '-' + d.getDate().toString()
|
||
}
|
||
|
||
function getTodaySmsCount() : number {
|
||
const v = uni.getStorageSync(smsCountKey())
|
||
if (v == null) return 0
|
||
const n = parseInt(v as string)
|
||
if (isNaN(n)) return 0
|
||
return n
|
||
}
|
||
|
||
function incrTodaySmsCount() : void {
|
||
uni.setStorageSync(smsCountKey(), (getTodaySmsCount() + 1).toString())
|
||
}
|
||
|
||
// 60s 倒计时循环
|
||
function startTick() : void {
|
||
_smsTimer = setTimeout(() : void => {
|
||
smsCountdown.value -= 1
|
||
if (smsCountdown.value > 0) {
|
||
startTick()
|
||
} else {
|
||
_smsTimer = -1
|
||
}
|
||
}, 1000)
|
||
}
|
||
|
||
// 点击【获取验证码】:验证手机号 → 频次/次数校验 → 发送 + 60s 倒计时
|
||
function onGetSms() : void {
|
||
if (smsCountdown.value > 0) return
|
||
// 验证失败:toast「请填写正确的手机号」
|
||
if (!isValidPhone(phone.value)) {
|
||
uni.showToast({ title: '请填写正确的手机号', icon: 'none' })
|
||
return
|
||
}
|
||
// 获取频次:5s/次,超过 toast「间隔时间过短」
|
||
const now = Date.now()
|
||
if (lastGetTs > 0 && now - lastGetTs < 5000) {
|
||
uni.showToast({ title: '间隔时间过短', icon: 'none' })
|
||
return
|
||
}
|
||
// 获取次数:手机号/10次/天,超出 toast「获取次数今日已达上限」
|
||
if (getTodaySmsCount() >= SMS_DAILY_LIMIT) {
|
||
uni.showToast({ title: '获取次数今日已达上限', icon: 'none' })
|
||
return
|
||
}
|
||
lastGetTs = now
|
||
incrTodaySmsCount()
|
||
hasGotOnce.value = true
|
||
// TODO: 接入真实短信发送 API
|
||
smsCountdown.value = 60
|
||
startTick()
|
||
}
|
||
|
||
// 点击【注册或登录】:验证编辑信息
|
||
function onSubmitLogin() : void {
|
||
if (!isValidPhone(phone.value)) {
|
||
uni.showToast({ title: '请填写正确的手机号', icon: 'none' })
|
||
return
|
||
}
|
||
// 验证码:必填,4 位数字
|
||
if (code.value.length != 4) {
|
||
uni.showToast({ title: '请填写正确的验证码', icon: 'none' })
|
||
return
|
||
}
|
||
// TODO: 接入真实注册登录 API + 设备绑定状态查询
|
||
isLoggedIn.value = true
|
||
showModal.value = false
|
||
// 验证成功 → 进入【添加设备】页面
|
||
uni.navigateTo({ url: '/pages/activate-device/activate-device' })
|
||
}
|
||
|
||
// ====== 顶部状态栏时间(与 activate-device 页一致:HH:mm 每秒刷新) ======
|
||
const clockText = ref<string>('00:00')
|
||
let _clockTimer : number = -1
|
||
|
||
function pad2(n : number) : string {
|
||
return n < 10 ? '0' + n.toString() : n.toString()
|
||
}
|
||
|
||
function refreshClock() : void {
|
||
const d = new Date()
|
||
clockText.value = pad2(d.getHours()) + ':' + pad2(d.getMinutes())
|
||
}
|
||
|
||
function startClock() : void {
|
||
refreshClock()
|
||
_clockTimer = setInterval(() : void => {
|
||
refreshClock()
|
||
}, 1000)
|
||
}
|
||
|
||
onLoad(() : void => {
|
||
startClock()
|
||
})
|
||
|
||
// 页面卸载时清理倒计时定时器 + 时钟定时器
|
||
onUnload(() : void => {
|
||
if (_smsTimer != -1) {
|
||
clearTimeout(_smsTimer)
|
||
_smsTimer = -1
|
||
}
|
||
if (_clockTimer != -1) {
|
||
clearInterval(_clockTimer)
|
||
_clockTimer = -1
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style>
|
||
/* ==================== 登录引导页基础 ==================== */
|
||
.page {
|
||
width: 750rpx;
|
||
height: 100%;
|
||
background-color: #040912;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 顶部栏:设计稿 1920×104 → 750×40.63rpx;头像 60×60 在 (60,22),文字 36px 在 (144,28),右侧蓝牙/WiFi/信号/时间 */
|
||
.header {
|
||
width: 100%;
|
||
height: 40.63rpx; /* 104 → 40.63rpx */
|
||
flex-direction: row;
|
||
align-items: center;
|
||
padding-left: 23.44rpx; /* 60 → 23.44rpx */
|
||
padding-right: 23.44rpx; /* 右侧与 activate-device 页一致 */
|
||
}
|
||
|
||
.header-user {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 头像 60×60 → 23.44rpx 圆形 */
|
||
.header-avatar {
|
||
width: 23.44rpx;
|
||
height: 23.44rpx;
|
||
border-radius: 11.72rpx; /* 50% */
|
||
}
|
||
|
||
/* 「未登录」36px Regular 白;与头像间距 24 → 9.38rpx */
|
||
.header-name {
|
||
margin-left: 9.38rpx;
|
||
font-size: 14.06rpx; /* 36 → 14.06rpx */
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.header-spacer {
|
||
flex: 1;
|
||
}
|
||
|
||
.header-status {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 三个状态栏图标:均为 23.44rpx(60×60 Figma px),相邻间距 24 → 9.38rpx */
|
||
.status-icon {
|
||
width: 23.44rpx;
|
||
height: 23.44rpx;
|
||
}
|
||
|
||
.status-icon-gap {
|
||
margin-left: 9.38rpx;
|
||
}
|
||
|
||
/* 时间:与信号图标间距 24 → 9.38rpx;36px Regular 白;行高 14.06rpx 与图标对齐 */
|
||
.header-time {
|
||
margin-left: 9.38rpx;
|
||
font-size: 14.06rpx;
|
||
line-height: 14.06rpx;
|
||
color: #FFFFFF;
|
||
text-align: right;
|
||
}
|
||
|
||
.content {
|
||
flex: 1;
|
||
flex-direction: row;
|
||
padding-left: 23.44rpx; /* 60 → 23.44rpx */
|
||
padding-right: 23.44rpx;
|
||
padding-bottom: 23.44rpx;
|
||
padding-top: 14.06rpx; /* 设计稿卡片 y=140,header 高 104 → 间距 36 → 14.06rpx */
|
||
}
|
||
|
||
.card {
|
||
background-color: #D8D8D8;
|
||
overflow: hidden;
|
||
position: relative;
|
||
border-radius: 7.81rpx; /* 20 → 7.81rpx */
|
||
}
|
||
|
||
.card-bg {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
/* 轮播铺满卡片(宣传位 / 推荐位) */
|
||
.card-swiper {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.main-card {
|
||
width: 343.75rpx; /* 880 → 343.75rpx */
|
||
height: 100%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.right-col {
|
||
flex: 1;
|
||
margin-left: 10.94rpx; /* 28 → 10.94rpx */
|
||
flex-direction: column;
|
||
}
|
||
|
||
.top-card {
|
||
flex: 486;
|
||
width: 100%;
|
||
}
|
||
|
||
.bottom-row {
|
||
flex: 486;
|
||
margin-top: 10.94rpx;
|
||
flex-direction: row;
|
||
width: 100%;
|
||
}
|
||
|
||
.func-card {
|
||
flex: 1;
|
||
width: 0;
|
||
height: 100%;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.func-right {
|
||
margin-left: 10.94rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* 徽标 192×48 → 75×18.75rpx;圆角 20 → 7.81rpx */
|
||
.func-badge {
|
||
width: 75rpx;
|
||
height: 18.75rpx;
|
||
border-radius: 7.81rpx;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #242738;
|
||
box-shadow: 0 0.78rpx 3.13rpx rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
/* 图标 36×36 → 14.06rpx;文字 36 Heavy→14.06rpx;间距 13→5.08rpx */
|
||
.func-icon {
|
||
width: 14.06rpx;
|
||
height: 14.06rpx;
|
||
}
|
||
|
||
.func-text {
|
||
color: #FFFFFF;
|
||
font-weight: 900;
|
||
font-size: 14.06rpx;
|
||
margin-left: 5.08rpx;
|
||
}
|
||
|
||
/* ==================== 登录弹窗 ==================== */
|
||
/* 设计稿:1920 基准;遮罩 1920×1200 rgba(31,35,41,0.6) */
|
||
.mask {
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(31, 35, 41, 0.6);
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 999;
|
||
}
|
||
|
||
/* 弹窗 1280×720 → 500 × 281.25rpx;背景 #030A16;圆角 20 → 7.81rpx;相对画板 320/240 居中 */
|
||
.modal {
|
||
width: 500rpx;
|
||
height: 281.25rpx;
|
||
background-color: #030A16;
|
||
border-radius: 7.81rpx;
|
||
flex-direction: row;
|
||
position: relative;
|
||
overflow: hidden;
|
||
box-shadow: 0 3.91rpx 15.63rpx rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
/* 关闭 X 30×30 → 11.72rpx 方形;相对弹窗 1230/20 → 弹窗右上 50/7.81rpx */
|
||
.modal-close {
|
||
position: absolute;
|
||
top: 7.81rpx;
|
||
right: 19.53rpx; /* 设计稿 (1280-1230-30)=20 → 7.81rpx,稍放大一点更易点 */
|
||
width: 11.72rpx;
|
||
height: 11.72rpx;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.modal-close-line1 {
|
||
position: absolute;
|
||
width: 11.72rpx;
|
||
height: 1rpx;
|
||
background-color: #FFFFFF;
|
||
transform: rotate(45deg);
|
||
}
|
||
|
||
.modal-close-line2 {
|
||
position: absolute;
|
||
width: 11.72rpx;
|
||
height: 1rpx;
|
||
background-color: #FFFFFF;
|
||
transform: rotate(-45deg);
|
||
}
|
||
|
||
/* 左侧插画容器:设计稿 Mask group 弹窗内 32/154 556×380 → 用比例换算 + 匹配图1效果
|
||
修正:
|
||
1. 加上蓝边(~2px 粗亮蓝描边,与 Figma 截图的蓝色一致)
|
||
2. 图片按 aspectFit 居中展示真实车身 PNG,不裁切
|
||
*/
|
||
.modal-banner-wrap {
|
||
position: absolute;
|
||
left: 12.5rpx;
|
||
top: 60.16rpx;
|
||
width: 217.19rpx;
|
||
height: 148.44rpx;
|
||
background-color: transparent;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.modal-banner {
|
||
width: 80%;
|
||
height: 80%;
|
||
border-radius: 0;
|
||
}
|
||
|
||
/* 右侧表单:起点 620/162 570×60 → 占弹窗右,用比例 */
|
||
.modal-form {
|
||
position: absolute;
|
||
left: 242.19rpx; /* 620/1280*500 ≈ 242.19 */
|
||
top: 63.28rpx; /* 162/720*281.25 = 63.28 */
|
||
width: 222.66rpx; /* 570/1280*500 ≈ 222.66 */
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 切换文字:「账号密码登录」 20 → 7.81rpx;位置 y=162,距离顶部 0 → 相对弹窗 form 起点 162 即 top=0 对应 */
|
||
.modal-switch {
|
||
font-size: 7.81rpx; /* 20 → 7.81rpx */
|
||
color: #FFFFFF;
|
||
line-height: 14.06rpx; /* 36px lineHeight → 14.06rpx */
|
||
margin-bottom: 7.03rpx; /* 210 - 162 - 36 = 12 → 4.69rpx 微调 → 7.03rpx 使下间距合理 */
|
||
}
|
||
|
||
/* 输入框 570×60 → 222.66×23.44rpx;背景 rgba(36,39,56,0.8);圆角 4 → 1.56rpx;与上一个间距 38(308-270=38 → 210到308 98 → 38.28rpx 作为 form 内间距) */
|
||
.field {
|
||
margin-top: 14.84rpx; /* 输入框间距 (308-210-60=38) → 14.84rpx */
|
||
width: 222.66rpx;
|
||
height: 23.44rpx; /* 60 → 23.44rpx */
|
||
background-color: rgba(36, 39, 56, 0.8);
|
||
border-radius: 1.56rpx; /* 4 → 1.56rpx */
|
||
flex-direction: row;
|
||
align-items: center;
|
||
padding-left: 6.25rpx; /* 图标起点 16px相对输入框 → 6.25rpx */
|
||
padding-right: 3.91rpx; /* 小内边距 */
|
||
position: relative;
|
||
border-width: 0.78rpx;
|
||
border-style: solid;
|
||
border-color: transparent;
|
||
}
|
||
|
||
/* 设计稿「注册或登录」按钮有边框 rgba(217,217,217,0.8) 2px → 输入框聚焦时按同样风格高亮 */
|
||
.fieldFocus {
|
||
border-color: rgba(217, 217, 217, 0.8);
|
||
border-width: 0.78rpx;
|
||
}
|
||
|
||
/* 图标 24×24 相对输入框 left 16/top 18(评论框图标)、top 228-210=18 for 手机号 → 都用字段垂直居中 */
|
||
.field-icon {
|
||
width: 9.38rpx; /* 24 → 9.38rpx */
|
||
height: 9.38rpx;
|
||
margin-right: 2.34rpx; /* 占位 672-636-24 = 12 → 4.69rpx 一半值,实际用 2.34 使视觉紧凑 */
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* 用户图标(Figma user备份2):大致由上半圆 + 下方梯形组成,用两个 view 拼出轮廓 */
|
||
.icon-user-1 {
|
||
position: absolute;
|
||
left: 1.56rpx;
|
||
top: 0;
|
||
width: 6.25rpx;
|
||
height: 6.25rpx;
|
||
border-width: 0.78rpx;
|
||
border-style: solid;
|
||
border-color: #D8D8D8;
|
||
border-radius: 3.13rpx; /* 50%效果 */
|
||
}
|
||
|
||
.icon-user-2 {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
width: 9.38rpx;
|
||
height: 4.69rpx;
|
||
border-top-left-radius: 4.69rpx;
|
||
border-top-right-radius: 4.69rpx;
|
||
border-width: 0.78rpx;
|
||
border-style: solid;
|
||
border-color: #D8D8D8;
|
||
border-bottom-width: 0;
|
||
}
|
||
|
||
/* 消息图标(Figma「评论」框 + 遮罩):信封轮廓 矩形 20×14 + 翻盖 17×5 */
|
||
.icon-sms-box {
|
||
position: absolute;
|
||
left: 0.78rpx;
|
||
top: 2.0rpx;
|
||
width: 7.81rpx; /* 20 → 7.81 */
|
||
height: 5.47rpx; /* 14 → 5.47 */
|
||
border-width: 0.78rpx;
|
||
border-style: solid;
|
||
border-color: #D8D8D8;
|
||
border-radius: 1.17rpx; /* 3 → 1.17 */
|
||
background-color: transparent;
|
||
}
|
||
|
||
.icon-sms-flap {
|
||
position: absolute;
|
||
left: 1.17rpx;
|
||
top: 2.81rpx;
|
||
width: 6.64rpx; /* 17 → 6.64 */
|
||
height: 1.95rpx; /* 5 → 1.95 */
|
||
border-top-width: 0.78rpx;
|
||
border-top-style: solid;
|
||
border-top-color: #D8D8D8;
|
||
}
|
||
|
||
.field-input {
|
||
flex: 1;
|
||
height: 23.44rpx;
|
||
color: #FFFFFF;
|
||
font-size: 9.38rpx; /* 24 → 9.38rpx */
|
||
line-height: 14.06rpx; /* 36 → 14.06rpx */
|
||
padding: 0;
|
||
margin: 0;
|
||
background-color: transparent;
|
||
}
|
||
|
||
.field-placeholder {
|
||
color: #999999;
|
||
font-size: 9.38rpx;
|
||
}
|
||
|
||
/* 获取验证码 右对齐 input;设计稿 454+100=554 (<570 框内),字号 20 白 */
|
||
.code-btn {
|
||
flex-shrink: 0;
|
||
font-size: 7.81rpx; /* 20 → 7.81rpx */
|
||
line-height: 14.06rpx; /* 36 → 14.06rpx */
|
||
color: #FFFFFF;
|
||
text-align: right;
|
||
padding-left: 3.91rpx;
|
||
}
|
||
|
||
.code-btn.disabled {
|
||
color: #999999;
|
||
}
|
||
|
||
/* 提交按钮 570×60 → 222.66×23.44rpx;同输入框背景 + 边框 2px rgba(217,217,217,0.8);圆角 4 → 1.56rpx;距上 (514-308-60=146) → 57.03rpx */
|
||
.submit-btn {
|
||
margin-top: 57.03rpx;
|
||
width: 222.66rpx;
|
||
height: 23.44rpx;
|
||
background-color: rgba(36, 39, 56, 0.8);
|
||
border-radius: 1.56rpx;
|
||
border-width: 0.78rpx; /* 2px → 0.78rpx */
|
||
border-style: solid;
|
||
border-color: rgba(217, 217, 217, 0.8);
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.submit-text {
|
||
color: #FFFFFF;
|
||
font-size: 9.38rpx; /* 24 → 9.38rpx */
|
||
line-height: 14.84rpx; /* 38 → 14.84rpx */
|
||
text-align: center;
|
||
}
|
||
</style>
|