first commit

This commit is contained in:
cg
2026-09-03 22:21:38 +08:00
commit 63ce526195
34 changed files with 2139 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
+3
View File
@@ -0,0 +1,3 @@
unpackage/
.DS_Store
.hbuilderx/
+51
View File
@@ -0,0 +1,51 @@
<script setup lang="uts">
// #ifdef APP-ANDROID || APP-HARMONY
let firstBackTime = 0
// #endif
onLaunch(() => {
console.log('App Launch')
})
onAppShow(() => {
console.log('App Show')
})
onAppHide(() => {
console.log('App Hide')
})
// #ifdef APP-ANDROID || APP-HARMONY
onLastPageBackPress(() => {
console.log('App LastPageBackPress')
if (firstBackTime == 0) {
uni.showToast({
title: '再按一次退出应用',
position: 'bottom',
})
firstBackTime = Date.now()
setTimeout(() => {
firstBackTime = 0
}, 2000)
} else if (Date.now() - firstBackTime < 2000) {
firstBackTime = Date.now()
uni.exit()
}
})
onExit(() => {
console.log('App Exit')
})
// #endif
</script>
<style>
/*每个页面公共css */
.uni-row {
flex-direction: row;
}
.uni-column {
flex-direction: column;
}
</style>
+20
View File
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main"></script>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
import App from './App.uvue'
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
+68
View File
@@ -0,0 +1,68 @@
{
"name" : "yaokongqi",
"appid" : "__UNI__DD44C1A",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"uni-app-x" : {
"styleIsolationVersion" : "2"
},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3",
"app" : {
"distribute" : {
"icons" : {
"android" : {
"hdpi" : "",
"xhdpi" : "",
"xxhdpi" : "",
"xxxhdpi" : ""
}
}
}
},
"app-android" : {
"distribute" : {
"modules" : {},
"screenOrientation" : [ "landscape-primary", "landscape-secondary" ],
"icons" : {
"hdpi" : "",
"xhdpi" : "",
"xxhdpi" : "",
"xxxhdpi" : ""
},
"splashScreens" : {
"default" : {}
}
}
},
"app-ios" : {
"screenOrientation" : [ "landscape-primary", "landscape-secondary" ],
"distribute" : {
"modules" : {},
"icons" : {},
"splashScreens" : {}
}
}
}
+39
View File
@@ -0,0 +1,39 @@
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://doc.dcloud.net.cn/uni-app-x/collocation/pagesjson.html
{
"path": "pages/login-guide/login-guide",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "登录引导",
"pageOrientation": "landscape",
"hideStatusBar": true
}
},
{
"path": "pages/activate-device/activate-device",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "添加设备",
"pageOrientation": "landscape",
"hideStatusBar": true
}
},
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "首页",
"pageOrientation": "landscape",
"hideStatusBar": true
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app x",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"pageOrientation": "landscape"
},
"uniIdRouter": {}
}
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
<template>
<view>
<image class="logo" src="/static/logo.png"></image>
<text class="title">{{title}}</text>
</view>
</template>
<script setup lang="uts">
const title = ref('Hello')
</script>
<style>
.logo {
height: 100px;
width: 100px;
margin: 100px auto 25px auto;
}
.title {
font-size: 18px;
color: #8f8f94;
text-align: center;
}
</style>
+715
View File
@@ -0,0 +1,715 @@
<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>
+6
View File
@@ -0,0 +1,6 @@
// 参考链接 https://doc.dcloud.net.cn/uni-app-x/tutorial/ls-plugin.html#setting
{
"targets": [
"APP-ANDROID"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+76
View File
@@ -0,0 +1,76 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16px;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;