first commit
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
unpackage/
|
||||
.DS_Store
|
||||
.hbuilderx/
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,9 @@
|
||||
import App from './App.uvue'
|
||||
|
||||
import { createSSRApp } from 'vue'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
@@ -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" : {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,6 @@
|
||||
// 参考链接 https://doc.dcloud.net.cn/uni-app-x/tutorial/ls-plugin.html#setting
|
||||
{
|
||||
"targets": [
|
||||
"APP-ANDROID"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 385 KiB |
|
After Width: | Height: | Size: 384 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 384 KiB |
|
After Width: | Height: | Size: 760 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 853 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 207 KiB |
|
After Width: | Height: | Size: 385 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
@@ -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;
|
||||