1120 lines
31 KiB
Plaintext
1120 lines
31 KiB
Plaintext
<template>
|
||
<view class="page">
|
||
<!-- ============ 顶部栏(Figma #172:3451,1920×104) ============ -->
|
||
<view class="header">
|
||
<!-- 左侧:头像 + 登录状态 -->
|
||
<view class="header-user" @click="onHeaderUserClick">
|
||
<image class="header-avatar" src="/static/activate/avatar.png" mode="aspectFill"></image>
|
||
<text class="header-name">{{ isLoggedIn ? '已登录' : '未登录' }}</text>
|
||
</view>
|
||
<view class="header-spacer"></view>
|
||
<!-- 右侧:蓝牙 / WiFi / 信号 + 时间(设计稿内绘制的状态栏元素) -->
|
||
<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">
|
||
<!-- ============ 左列:2×2 功能卡 + 预览大图 ============ -->
|
||
<view class="left-col">
|
||
<view class="card-grid">
|
||
<!-- 文件(Figma #11:227) -->
|
||
<view class="func-card" @click="onCardClick('文件')">
|
||
<text class="card-title">文件</text>
|
||
<text class="card-sub">点击查看文件</text>
|
||
<view class="card-ring">
|
||
<image class="ring-icon" src="/static/activate/icon-file.png" mode="aspectFit"></image>
|
||
</view>
|
||
</view>
|
||
<!-- 空间(Figma #0:826,电量环) -->
|
||
<view class="func-card" @click="onCardClick('空间')">
|
||
<text class="card-title">空间</text>
|
||
<text class="card-sub">点击查看空间</text>
|
||
<image class="battery-ring" src="/static/activate/battery-ring.png" mode="aspectFit"></image>
|
||
</view>
|
||
<!-- 航线(Figma #0:830) -->
|
||
<view class="func-card" @click="onCardClick('航线')">
|
||
<text class="card-title">航线</text>
|
||
<text class="card-sub">点击查看航线</text>
|
||
<image class="route-icon" src="/static/activate/icon-route.png" mode="aspectFit"></image>
|
||
</view>
|
||
<!-- 文件-菜单(Figma #11:226) -->
|
||
<view class="func-card" @click="onCardClick('文件')">
|
||
<text class="card-title">文件</text>
|
||
<text class="card-sub">点击查看文件</text>
|
||
<view class="card-ring">
|
||
<image class="ring-icon" src="/static/activate/icon-menu.png" mode="aspectFit"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 预览大图(Figma #9:100,946×532,5 张轮巡:自动轮播 + 左右滑动浏览) -->
|
||
<view class="preview-card">
|
||
<swiper
|
||
class="preview-swiper"
|
||
:autoplay="true"
|
||
:circular="true"
|
||
:interval="4000"
|
||
:duration="400"
|
||
:indicator-dots="false"
|
||
:current="currentPreview"
|
||
:disable-touch="false"
|
||
@change="onPreviewChange"
|
||
>
|
||
<swiper-item v-for="(item, index) in previewImages" :key="index" @click="onPreviewClick(index)">
|
||
<image class="preview-img" :src="item" mode="aspectFill"></image>
|
||
</swiper-item>
|
||
</swiper>
|
||
<!-- 指示点(Figma #9:91,200×24,透明度 0.7,距右下 23.44rpx) -->
|
||
<image class="preview-dots" src="/static/activate/progress-bar.png" mode="aspectFit"></image>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ============ 右列:设备信息 + 激活按钮 ============ -->
|
||
<view class="right-col">
|
||
<!-- 设备展示区(Figma #12:239,660×380 灰底) -->
|
||
<view class="device-area">
|
||
<image class="device-img" src="/static/activate/device-view.png" mode="aspectFit"></image>
|
||
</view>
|
||
<!-- 设备名(Figma #0:812) -->
|
||
<text class="device-name">{{ deviceNameDisplay }}</text>
|
||
<!-- 统计三项(Figma #12:241 / #12:242 / #12:240) -->
|
||
<view class="stats-row">
|
||
<view class="stat-item">
|
||
<text class="stat-value">720 h</text>
|
||
<text class="stat-label">行驶时长</text>
|
||
</view>
|
||
<view class="stat-item stat-item-mid">
|
||
<text class="stat-value">720 km</text>
|
||
<text class="stat-label">行驶里程</text>
|
||
</view>
|
||
<view class="stat-item">
|
||
<text class="stat-value">720 次</text>
|
||
<text class="stat-label">行驶次数</text>
|
||
</view>
|
||
</view>
|
||
<!-- 激活状态(Figma #0:821):正在激活中时显示 -->
|
||
<text class="activating" v-if="activating">正在激活</text>
|
||
<view class="right-spacer"></view>
|
||
<!-- 按钮(Figma #9:90,800×96):三态切换 — 添加设备 / 激活设备(含激活中) / 开始使用 -->
|
||
<view
|
||
class="activate-btn"
|
||
:class="{ 'activate-btn-activating': activating, 'activate-btn-done': activateBtnState === 'start' }"
|
||
@click="onActivateBtnClick"
|
||
>
|
||
<!-- 激活中:显示 loading spinner + 文案 -->
|
||
<view class="activate-loading" v-if="activating">
|
||
<view class="spinner"></view>
|
||
<text class="activate-text activate-text-inline">正在激活中...</text>
|
||
</view>
|
||
<text class="activate-text" v-else>
|
||
{{ activateBtnState === 'add' ? '添加设备' : (activateBtnState === 'activate' ? '激活设备' : '开始使用') }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ============ 添加设备弹窗(Figma node 18:617,画布 1280×720,1px=0.390625rpx) ============ -->
|
||
<view class="modal-mask" v-if="showAddModal" @click="onModalMaskClick">
|
||
<view class="add-modal" @click.stop="noop">
|
||
<!-- 顶栏 1280×80 -->
|
||
<view class="modal-header">
|
||
<text class="modal-title">添加设备</text>
|
||
<text class="modal-close" @click="onCloseModal">✕</text>
|
||
</view>
|
||
|
||
<!-- 设备类型选择:无人车(636,160) 150×60 / 无人机(810,160) 150×60 -->
|
||
<view class="type-tabs">
|
||
<view
|
||
class="type-tab"
|
||
:class="deviceType === 'car' ? 'type-tab-active' : ''"
|
||
@click="onTypeTabChange('car')"
|
||
>
|
||
<text
|
||
class="type-tab-text"
|
||
:class="deviceType === 'car' ? 'type-tab-text-active' : ''"
|
||
>无人车</text>
|
||
</view>
|
||
<view
|
||
class="type-tab"
|
||
:class="deviceType === 'uav' ? 'type-tab-active' : ''"
|
||
@click="onTypeTabChange('uav')"
|
||
>
|
||
<text
|
||
class="type-tab-text"
|
||
:class="deviceType === 'uav' ? 'type-tab-text-active' : ''"
|
||
>无人机</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 左侧预览图 Mask (36,128) 542×380,内部图 (84,23) 373×334;按设备类型切换展示 -->
|
||
<view class="preview-wrap">
|
||
<image
|
||
class="preview-dev-img"
|
||
:src="deviceType === 'car' ? '/static/activate/add_device_car.png' : '/static/activate/add_device_uav.png'"
|
||
mode="aspectFill"
|
||
></image>
|
||
</view>
|
||
|
||
<!-- 右侧输入区:设备名 (636,244) 570×60;SN码 (636,334) 570×60 -->
|
||
<view class="input-group">
|
||
<view class="input-box" @click="onInputFocus('name')">
|
||
<input
|
||
class="input-field"
|
||
v-model="deviceName"
|
||
placeholder="请填写设备名称"
|
||
placeholder-class="input-placeholder"
|
||
:focus="inputFocusTarget === 'name'"
|
||
@focus="onInputFocus('name')"
|
||
/>
|
||
</view>
|
||
<view class="input-box input-box-sn" @click="onInputFocus('sn')">
|
||
<input
|
||
class="input-field"
|
||
v-model="deviceSn"
|
||
placeholder="请填写设备SN码"
|
||
placeholder-class="input-placeholder"
|
||
:focus="inputFocusTarget === 'sn'"
|
||
@focus="onInputFocus('sn')"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部按钮:取消(474,544) 150×60;确定(656,544) 150×60(相对弹窗) -->
|
||
<view class="modal-btns">
|
||
<view class="modal-btn modal-btn-cancel" @click="onModalCancel">
|
||
<text class="modal-btn-text">取消</text>
|
||
</view>
|
||
<view class="modal-btn modal-btn-ok" @click="onModalOk">
|
||
<text class="modal-btn-text">确定</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ========== 模拟拼音键盘弹窗(点击输入框打开,覆盖弹窗底部区域) ========== -->
|
||
<view class="kbd-mask" v-if="showKeyboard" @click="closeKeyboard">
|
||
<view class="kbd-panel" @click.stop="noop">
|
||
<view class="kbd-title">
|
||
<text class="kbd-title-text">拼音键盘</text>
|
||
<text class="kbd-close" @click="closeKeyboard">✕</text>
|
||
</view>
|
||
<!-- 3 行字母 -->
|
||
<view class="kbd-row">
|
||
<view class="kbd-key" v-for="(k,i) in kbdRow1" :key="'r1-'+i" @click="onKbdKey(k)"><text class="kbd-key-text">{{ k }}</text></view>
|
||
</view>
|
||
<view class="kbd-row">
|
||
<view class="kbd-key" v-for="(k,i) in kbdRow2" :key="'r2-'+i" @click="onKbdKey(k)"><text class="kbd-key-text">{{ k }}</text></view>
|
||
</view>
|
||
<view class="kbd-row">
|
||
<view class="kbd-key" v-for="(k,i) in kbdRow3" :key="'r3-'+i" @click="onKbdKey(k)"><text class="kbd-key-text">{{ k }}</text></view>
|
||
</view>
|
||
<!-- 数字行 + 空格 + 删除 + 确认 -->
|
||
<view class="kbd-row">
|
||
<view class="kbd-key kbd-key-num" v-for="(k,i) in kbdNums" :key="'n-'+i" @click="onKbdKey(k)"><text class="kbd-key-text">{{ k }}</text></view>
|
||
<view class="kbd-key kbd-key-space" @click="onKbdKey(' ')"><text class="kbd-key-text">空格</text></view>
|
||
<view class="kbd-key kbd-key-del" @click="onKbdBackspace"><text class="kbd-key-text">⌫</text></view>
|
||
<view class="kbd-key kbd-key-ok" @click="closeKeyboard"><text class="kbd-key-text kbd-key-ok-text">确认</text></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
// ====== 添加设备弹窗 ======
|
||
const showAddModal = ref<boolean>(false)
|
||
const deviceType = ref<string>('car') // 'car' | 'uav' 必选单选,默认无人车
|
||
const deviceName = ref<string>('')
|
||
const deviceSn = ref<string>('')
|
||
|
||
// ====== 模拟拼音键盘 ======
|
||
const showKeyboard = ref<boolean>(false)
|
||
// 当前激活的目标字段:'name' 设备名称 | 'sn' 设备SN码
|
||
const inputFocusTarget = ref<string>('')
|
||
|
||
const kbdRow1 = ref<string[]>(['Q','W','E','R','T','Y','U','I','O','P'])
|
||
const kbdRow2 = ref<string[]>(['A','S','D','F','G','H','J','K','L'])
|
||
const kbdRow3 = ref<string[]>(['Z','X','C','V','B','N','M'])
|
||
const kbdNums = ref<string[]>(['1','2','3','4','5','6','7','8','9','0'])
|
||
|
||
function onInputFocus(target : string) : void {
|
||
// 点击【设备名称】或【设备SN码】打开拼音键盘弹窗
|
||
inputFocusTarget.value = target
|
||
showKeyboard.value = true
|
||
}
|
||
|
||
function closeKeyboard() : void {
|
||
showKeyboard.value = false
|
||
}
|
||
|
||
function onKbdKey(ch : string) : void {
|
||
const target = inputFocusTarget.value
|
||
if (target !== 'name' && target !== 'sn') return
|
||
if (target === 'name') {
|
||
deviceName.value = deviceName.value + ch
|
||
} else {
|
||
deviceSn.value = deviceSn.value + ch
|
||
}
|
||
}
|
||
|
||
function onKbdBackspace() : void {
|
||
const target = inputFocusTarget.value
|
||
if (target !== 'name' && target !== 'sn') return
|
||
if (target === 'name') {
|
||
const s = deviceName.value
|
||
if (s.length > 0) deviceName.value = s.substring(0, s.length - 1)
|
||
} else {
|
||
const s = deviceSn.value
|
||
if (s.length > 0) deviceSn.value = s.substring(0, s.length - 1)
|
||
}
|
||
}
|
||
|
||
function noop() : void {}
|
||
|
||
function onModalMaskClick() : void {
|
||
// 点击遮罩关闭(按需求可改为不关闭)
|
||
showAddModal.value = false
|
||
showKeyboard.value = false
|
||
}
|
||
|
||
function onCloseModal() : void {
|
||
showAddModal.value = false
|
||
showKeyboard.value = false
|
||
}
|
||
|
||
function onTypeTabChange(type : string) : void {
|
||
// 类型单选互斥:切换后预览图同步切换(car→无人车图,uav→无人机图)
|
||
deviceType.value = type
|
||
}
|
||
|
||
function onModalCancel() : void {
|
||
// 取消添加:关闭弹窗并清空所有编辑信息(名称/SN码/类型恢复默认),不保留
|
||
showAddModal.value = false
|
||
showKeyboard.value = false
|
||
deviceName.value = ''
|
||
deviceSn.value = ''
|
||
deviceType.value = 'car'
|
||
}
|
||
|
||
function onModalOk() : void {
|
||
const name = deviceName.value.trim()
|
||
const sn = deviceSn.value.trim()
|
||
if (name.length == 0) {
|
||
// 未填写设备名称
|
||
uni.showToast({ title: '请填写设备名称', icon: 'none' })
|
||
return
|
||
}
|
||
if (sn.length == 0) {
|
||
// 未填写设备SN码
|
||
uni.showToast({ title: '请填写设备SN码', icon: 'none' })
|
||
return
|
||
}
|
||
// 验证成功:绑定所属设备 → 同步到设备位展示;关闭弹窗;toast 提示「添加成功」;按钮切换为「激活设备」
|
||
deviceNameDisplay.value = name
|
||
activateBtnState.value = 'activate'
|
||
uni.showToast({ title: '添加成功', icon: 'none' })
|
||
showAddModal.value = false
|
||
showKeyboard.value = false
|
||
deviceName.value = ''
|
||
deviceSn.value = ''
|
||
}
|
||
|
||
// 预览轮播:限定 5 张宣传图片,接入真实素材后替换路径
|
||
const previewImages = ref<string[]>([
|
||
'/static/activate/preview-main.png',
|
||
'/static/activate/preview-main.png',
|
||
'/static/activate/preview-main.png',
|
||
'/static/activate/preview-main.png',
|
||
'/static/activate/preview-main.png'
|
||
])
|
||
// 轮播当前页(与 swiper current 双向同步,支持左右滑动浏览)
|
||
const currentPreview = ref<number>(0)
|
||
|
||
const isLoggedIn = ref<boolean>(false)
|
||
|
||
// 设备位显示的设备名:默认「赛德001」,添加后同步为新设备名
|
||
const deviceNameDisplay = ref<string>('赛德001')
|
||
|
||
// ====== 激活按钮状态机:'add' 添加设备 → 'activate' 激活设备 → 'start' 开始使用 ======
|
||
// 激活中中间态:activating = true 时按钮显示"正在激活中..."并禁用点击,上方显示"正在激活"文字
|
||
const activateBtnState = ref<string>('add')
|
||
const activating = ref<boolean>(false)
|
||
let _activateTimer : number = -1
|
||
|
||
// 按钮点击:按状态分发行为
|
||
function onActivateBtnClick() : void {
|
||
// 激活中禁止重复点击
|
||
if (activating.value) return
|
||
const state = activateBtnState.value
|
||
if (state === 'add') {
|
||
// 「添加设备」→ 打开添加设备弹窗
|
||
showAddModal.value = true
|
||
} else if (state === 'activate') {
|
||
// 「激活设备」→ 进入激活流程
|
||
startActivating()
|
||
} else if (state === 'start') {
|
||
// 「开始使用」→ 进入使用阶段(预留:跳转页面/下发控制命令等)
|
||
uni.showToast({ title: '开始使用', icon: 'none' })
|
||
}
|
||
}
|
||
|
||
// 模拟激活流程:2.5s 后激活完成,切换为「开始使用」
|
||
function startActivating() : void {
|
||
if (activating.value) return
|
||
activating.value = true
|
||
// 清理旧计时器,避免连续点击
|
||
if (_activateTimer != -1) {
|
||
clearTimeout(_activateTimer)
|
||
_activateTimer = -1
|
||
}
|
||
_activateTimer = setTimeout(() : void => {
|
||
activating.value = false
|
||
activateBtnState.value = 'start'
|
||
_activateTimer = -1
|
||
}, 2500)
|
||
}
|
||
|
||
// ====== 顶部时间(Figma 19:41,HH:mm 实时刷新) ======
|
||
const clockText = ref<string>('19:41')
|
||
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 (_clockTimer != -1) {
|
||
clearInterval(_clockTimer)
|
||
_clockTimer = -1
|
||
}
|
||
if (_activateTimer != -1) {
|
||
clearTimeout(_activateTimer)
|
||
_activateTimer = -1
|
||
}
|
||
})
|
||
|
||
// 顶部头像入口(预留:接入账号页)
|
||
function onHeaderUserClick() : void {
|
||
uni.showToast({ title: isLoggedIn.value ? '已登录' : '未登录', icon: 'none' })
|
||
}
|
||
|
||
// 功能卡片点击(预留:接入文件/空间/航线模块)
|
||
function onCardClick(name : string) : void {
|
||
uni.showToast({ title: name, icon: 'none' })
|
||
}
|
||
|
||
// 预览轮播滑动切换:同步 current
|
||
function onPreviewChange(e : any) : void {
|
||
currentPreview.value = e.detail.current as number
|
||
}
|
||
|
||
// 预览图点击:查看投放内容(打开图片预览,可查看5张宣传图片)
|
||
function onPreviewClick(index : number) : void {
|
||
currentPreview.value = index
|
||
const urls : string[] = []
|
||
for (let i = 0; i < previewImages.value.length; i++) {
|
||
urls.push(previewImages.value[i])
|
||
}
|
||
// #ifdef APP-ANDROID
|
||
uni.previewImage({
|
||
urls: urls,
|
||
current: urls[index]
|
||
})
|
||
// #endif
|
||
// #ifndef APP-ANDROID
|
||
// H5 / 其他平台兜底:简单 toast 提示
|
||
uni.showToast({ title: '查看投放内容 ' + (index + 1).toString(), icon: 'none' })
|
||
// #endif
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
/* ==================== 激活设备页(设计稿 1920×1200,1px = 0.390625rpx) ==================== */
|
||
.page {
|
||
width: 750rpx;
|
||
height: 100%;
|
||
background-color: #040912;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* ---------- 顶部栏:1920×104 → 750×40.63rpx ---------- */
|
||
.header {
|
||
width: 100%;
|
||
height: 40.63rpx;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
padding-left: 23.44rpx; /* 头像 x=60 */
|
||
padding-right: 23.44rpx; /* 时间右边缘 x=1860 */
|
||
}
|
||
|
||
.header-user {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 头像 60×60 → 23.44rpx 圆形 */
|
||
.header-avatar {
|
||
width: 23.44rpx;
|
||
height: 23.44rpx;
|
||
border-radius: 11.72rpx;
|
||
}
|
||
|
||
/* 「未登录」36px Regular 白,与头像间距 24 → 9.38rpx */
|
||
.header-name {
|
||
margin-left: 9.38rpx;
|
||
font-size: 14.06rpx;
|
||
line-height: 18.75rpx;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.header-spacer {
|
||
flex: 1;
|
||
}
|
||
|
||
.header-status {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 状态图标 60×60 → 23.44rpx;图标间距 84-60=24 → 9.38rpx */
|
||
.status-icon {
|
||
width: 23.44rpx;
|
||
height: 23.44rpx;
|
||
}
|
||
|
||
.status-icon-gap {
|
||
margin-left: 9.38rpx;
|
||
}
|
||
|
||
/* 「19:41」36px Regular 白,与信号图标间距 24 → 9.38rpx */
|
||
.header-time {
|
||
margin-left: 9.38rpx;
|
||
font-size: 14.06rpx;
|
||
line-height: 14.06rpx;
|
||
color: #FFFFFF;
|
||
text-align: right;
|
||
}
|
||
|
||
/* ---------- 内容区:卡片顶边 y=112(header 104 → 间距 8 → 3.13rpx);底边距 90 → 35.16rpx ---------- */
|
||
.content {
|
||
flex: 1;
|
||
flex-direction: row;
|
||
padding-left: 23.44rpx; /* x=60 */
|
||
padding-right: 23.44rpx; /* 右列右边缘 x=1860 */
|
||
padding-top: 3.13rpx;
|
||
padding-bottom: 35.16rpx;
|
||
}
|
||
|
||
/* ---------- 左列:宽 946 → 369.53rpx ---------- */
|
||
.left-col {
|
||
width: 369.53rpx;
|
||
flex-shrink: 0;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 2×2 卡片网格:卡 464×208 → 181.25×81.25rpx;水平/垂直间距 18 → 7.03rpx */
|
||
.card-grid {
|
||
width: 100%;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.func-card {
|
||
width: 181.25rpx;
|
||
height: 81.25rpx;
|
||
margin-bottom: 7.03rpx;
|
||
background-color: #242738;
|
||
border-radius: 7.81rpx; /* 20 → 7.81rpx */
|
||
position: relative;
|
||
}
|
||
|
||
/* 标题 36px Bold,相对卡片 (28,46) → (10.94,17.97)rpx */
|
||
.card-title {
|
||
position: absolute;
|
||
left: 10.94rpx;
|
||
top: 17.97rpx;
|
||
font-size: 14.06rpx;
|
||
line-height: 18.75rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
/* 副标题 24px Medium,相对卡片 (30,106) → (11.72,41.41)rpx */
|
||
.card-sub {
|
||
position: absolute;
|
||
left: 11.72rpx;
|
||
top: 41.41rpx;
|
||
font-size: 9.38rpx;
|
||
line-height: 18.75rpx;
|
||
font-weight: 500;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
/* 图标圆环 96×96 → 37.5rpx,相对卡片 (338,56) → (132.03,21.88)rpx;描边 2px 白 */
|
||
.card-ring {
|
||
position: absolute;
|
||
left: 132.03rpx;
|
||
top: 21.88rpx;
|
||
width: 37.5rpx;
|
||
height: 37.5rpx;
|
||
border-radius: 18.75rpx;
|
||
border-width: 0.78rpx;
|
||
border-style: solid;
|
||
border-color: #FFFFFF;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 圆环内图标 60×60 → 23.44rpx */
|
||
.ring-icon {
|
||
width: 23.44rpx;
|
||
height: 23.44rpx;
|
||
}
|
||
|
||
/* 电量环(含 80% 文字)96×96 → 37.5rpx */
|
||
.battery-ring {
|
||
position: absolute;
|
||
left: 132.03rpx;
|
||
top: 21.88rpx;
|
||
width: 37.5rpx;
|
||
height: 37.5rpx;
|
||
}
|
||
|
||
/* 航线图标(含圆环)96×96 → 37.5rpx */
|
||
.route-icon {
|
||
position: absolute;
|
||
left: 132.03rpx;
|
||
top: 21.88rpx;
|
||
width: 37.5rpx;
|
||
height: 37.5rpx;
|
||
}
|
||
|
||
/* 预览大图:设计稿 946×532 → 369.53×207.81rpx;与网格底部间距 32 → 12.5rpx;
|
||
高度弹性填充(1200 高屏幕下恰为 207.81rpx,矮屏自动收缩) */
|
||
.preview-card {
|
||
width: 369.53rpx;
|
||
flex: 1;
|
||
margin-top: 5.47rpx; /* 设计稿间距 32 → 12.5rpx,扣除第二行卡片 margin-bottom 7.03 */
|
||
border-radius: 7.81rpx;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
.preview-swiper {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.preview-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
/* 指示点:200×24 → 78.13×9.38rpx,距卡片右下 60px → 23.44rpx */
|
||
.preview-dots {
|
||
position: absolute;
|
||
right: 23.44rpx;
|
||
bottom: 23.44rpx;
|
||
width: 78.13rpx;
|
||
height: 9.38rpx;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
/* ---------- 右列:宽 800 → 312.5rpx,与左列间距 54 → 21.09rpx ---------- */
|
||
.right-col {
|
||
flex: 1;
|
||
margin-left: 21.09rpx;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 设备展示区:660×380 → 257.81×148.44rpx顶边 y=130 → 距内容顶 7.03rpx */
|
||
.device-area {
|
||
width: 257.81rpx;
|
||
height: 148.44rpx;
|
||
margin-top: 7.03rpx;
|
||
position: relative;
|
||
}
|
||
|
||
/* 设备图:373×334 → 145.70×130.47rpx,相对展示区 (145,23) → (56.64,8.98)rpx */
|
||
.device-img {
|
||
position: absolute;
|
||
left: 56.64rpx;
|
||
top: 8.98rpx;
|
||
width: 145.70rpx;
|
||
height: 130.47rpx;
|
||
}
|
||
|
||
/* 设备名「赛德001」36px Bold 居中;与展示区间距 30 → 11.72rpx */
|
||
.device-name {
|
||
margin-top: 11.72rpx;
|
||
font-size: 14.06rpx;
|
||
line-height: 19.69rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 统计行:与设备名底部间距 66 → 25.78rpx;三项居中,间隙 38 → 14.84rpx */
|
||
.stats-row {
|
||
margin-top: 25.78rpx;
|
||
flex-direction: row;
|
||
justify-content: center;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.stat-item {
|
||
width: 39.06rpx; /* 100px */
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.stat-item-mid {
|
||
width: 52.34rpx; /* 134px */
|
||
margin-left: 38.28rpx; /* 组间隙 98 → 38.28rpx */
|
||
margin-right: 38.28rpx;
|
||
}
|
||
|
||
/* 数值 32px Bold,行高 48 → 18.75rpx */
|
||
.stat-value {
|
||
font-size: 12.5rpx;
|
||
line-height: 18.75rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 标签 24px Medium,行高 33.6 → 13.13rpx;与数值间距 22 → 8.59rpx;阴影 0 4 5 rgba(0,0,0,0.3) */
|
||
.stat-label {
|
||
margin-top: 8.59rpx;
|
||
font-size: 9.38rpx;
|
||
line-height: 13.13rpx;
|
||
font-weight: 500;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
text-shadow: 0 1.56rpx 1.95rpx rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
/* 「正在激活」24px #0093F9;与统计行底部间距 66 → 25.78rpx */
|
||
.activating {
|
||
margin-top: 25.78rpx;
|
||
font-size: 9.38rpx;
|
||
line-height: 13.13rpx;
|
||
font-weight: 500;
|
||
color: #0093F9;
|
||
text-align: center;
|
||
text-shadow: 0 1.56rpx 1.95rpx rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
/* 弹性占位:设计稿中「正在激活」与按钮间距 148 → 57.81rpx,
|
||
1200 高屏幕下自动分配约 57.81rpx,矮屏收缩、不溢出 */
|
||
.right-spacer {
|
||
flex: 1;
|
||
}
|
||
|
||
/* 激活设备按钮:800×96 → 312.5×37.5rpx */
|
||
.activate-btn {
|
||
width: 312.5rpx;
|
||
height: 37.5rpx;
|
||
background-color: rgba(36, 39, 56, 0.8);
|
||
border-radius: 1.56rpx; /* 4 → 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;
|
||
}
|
||
|
||
/* 按钮文字 32px Bold,行高 38 → 14.84rpx */
|
||
.activate-text {
|
||
font-size: 12.5rpx;
|
||
line-height: 14.84rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 激活中态:按钮半透明 + 蓝边高亮,禁用点击视觉 */
|
||
.activate-btn-activating {
|
||
background-color: rgba(0, 147, 249, 0.15);
|
||
border-color: #0093F9;
|
||
/* 禁用态点击感:降低不透明度 */
|
||
opacity: 0.9;
|
||
}
|
||
|
||
/* 完成态(开始使用):蓝底白字,提示可操作 */
|
||
.activate-btn-done {
|
||
background-color: #0093F9;
|
||
border-color: #0093F9;
|
||
}
|
||
|
||
/* 激活中 loading 容器:横向排列 spinner + 文案 */
|
||
.activate-loading {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.activate-text-inline {
|
||
margin-left: 3.91rpx;
|
||
font-size: 12.5rpx;
|
||
line-height: 14.84rpx;
|
||
color: #0093F9;
|
||
}
|
||
|
||
/* spinner:16×16rpx 左右圆环旋转,两色圆弧(蓝+半透明白) */
|
||
.spinner {
|
||
width: 10.94rpx;
|
||
height: 10.94rpx;
|
||
border-radius: 5.47rpx;
|
||
border-width: 1.56rpx;
|
||
border-style: solid;
|
||
border-color: rgba(0, 147, 249, 0.2);
|
||
border-top-color: #0093F9;
|
||
border-right-color: #0093F9;
|
||
}
|
||
|
||
/* ==================== 添加设备弹窗(Figma 1280×720 画布,1px = 0.390625rpx) ==================== */
|
||
.modal-mask {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.6);
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 999;
|
||
}
|
||
|
||
/* 弹窗容器:1280×720 → 500×281.25rpx,背景 #030A16,圆角 20 → 7.81rpx */
|
||
.add-modal {
|
||
width: 500rpx;
|
||
height: 281.25rpx;
|
||
background-color: #030A16;
|
||
border-radius: 7.81rpx;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 顶栏:1280×80 → 500×31.25rpx */
|
||
.modal-header {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 500rpx;
|
||
height: 31.25rpx;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 标题:30×720 居中,30px Bold 白,行高 38 */
|
||
.modal-title {
|
||
font-size: 11.72rpx;
|
||
line-height: 14.84rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 关闭按钮:✕ 文本,位置 (1230,25),容器 30×30 → 11.72rpx,文字大小约 21px → 8.2rpx,颜色 #636E80 */
|
||
.modal-close {
|
||
position: absolute;
|
||
right: 19.53rpx;
|
||
top: 9.77rpx;
|
||
width: 11.72rpx;
|
||
height: 11.72rpx;
|
||
font-size: 8.2rpx;
|
||
line-height: 11.72rpx;
|
||
color: #636E80;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 类型 Tab 区:容器相对弹窗 x=636→248.44rpx, y=160→62.5rpx,宽 (150*2+24)=324→126.56rpx,高 60→23.44rpx,两个tab间距 24→9.38rpx */
|
||
.type-tabs {
|
||
position: absolute;
|
||
left: 248.44rpx;
|
||
top: 62.5rpx;
|
||
width: 126.56rpx;
|
||
height: 23.44rpx;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 单个 Tab:150×60 → 58.59×23.44rpx,圆角 6→2.34rpx,背景 #242738 */
|
||
.type-tab {
|
||
width: 58.59rpx;
|
||
height: 23.44rpx;
|
||
background-color: #242738;
|
||
border-radius: 2.34rpx;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 第二个 tab 与第一个间距 24 → 9.38rpx */
|
||
.type-tabs > .type-tab + .type-tab {
|
||
margin-left: 9.38rpx;
|
||
}
|
||
|
||
/* 选中状态:1px(#0093F9)描边,文字蓝 */
|
||
.type-tab-active {
|
||
border-width: 0.39rpx;
|
||
border-style: solid;
|
||
border-color: #0093F9;
|
||
}
|
||
|
||
/* Tab 文字:24px Regular(无人车为 150×60 中 72×38 居中 → 宽 28.13 高 14.84rpx) */
|
||
.type-tab-text {
|
||
font-size: 9.38rpx;
|
||
line-height: 14.84rpx;
|
||
font-weight: 350;
|
||
color: #999999;
|
||
text-align: center;
|
||
}
|
||
|
||
.type-tab-text-active {
|
||
color: #0093F9;
|
||
}
|
||
|
||
/* 左侧预览图容器 Mask (36,128) → (14.06,50)rpx,542×380 → 211.72×148.44rpx, */
|
||
.preview-wrap {
|
||
position: absolute;
|
||
left: 14.06rpx;
|
||
top: 50rpx;
|
||
width: 211.72rpx;
|
||
height: 148.44rpx;
|
||
overflow: hidden;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 内部图 373×334 → 相对 Mask (84,23) → (32.81,8.98)rpx,145.70×130.47rpx */
|
||
.preview-dev-img {
|
||
position: absolute;
|
||
left: 32.81rpx;
|
||
top: 8.98rpx;
|
||
width: 145.70rpx;
|
||
height: 130.47rpx;
|
||
}
|
||
|
||
/* 右侧输入组:位置 (636,244) → (248.44,95.31)rpx,570×(60+30+60)=570×150 → 222.66×58.59rpx,输入框间距 30→11.72rpx */
|
||
.input-group {
|
||
position: absolute;
|
||
left: 248.44rpx;
|
||
top: 95.31rpx;
|
||
width: 222.66rpx;
|
||
height: 58.59rpx;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 单个输入框:570×60 → 222.66×23.44rpx,背景 #242738,圆角 4→1.56rpx */
|
||
.input-box {
|
||
width: 222.66rpx;
|
||
height: 23.44rpx;
|
||
background-color: #242738;
|
||
border-radius: 1.56rpx;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
padding-left: 7.03rpx; /* 18 → 7.03rpx */
|
||
}
|
||
|
||
/* 第二个输入框与第一个间距 30 → 11.72rpx */
|
||
.input-box-sn {
|
||
margin-top: 11.72rpx;
|
||
}
|
||
|
||
/* 输入框字段 */
|
||
.input-field {
|
||
width: 208.59rpx; /* 222.66 - 7.03*2 ≈ 208.6rpx */
|
||
height: 23.44rpx;
|
||
font-size: 9.38rpx; /* 24px */
|
||
line-height: 14.06rpx; /* 36/38px → 约 14-14.84 */
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.input-placeholder {
|
||
color: #999999;
|
||
}
|
||
|
||
/* 底部按钮:容器中心定位,相对弹窗 y=544→212.5rpx(top 544/720*281.25=212.5),
|
||
取消 (474,544) → left 474/1280*500=185.16rpx,确定 656/1280*500=256.25rpx,
|
||
每个按钮 150×60 → 58.59×23.44rpx,圆角 6→2.34rpx */
|
||
.modal-btns {
|
||
position: absolute;
|
||
left: 185.16rpx;
|
||
top: 212.5rpx;
|
||
width: 129.69rpx; /* 58.59 + 12.5 + 58.59 = 129.68 */
|
||
height: 23.44rpx;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
.modal-btn {
|
||
width: 58.59rpx;
|
||
height: 23.44rpx;
|
||
background-color: #242738;
|
||
border-radius: 2.34rpx;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 取消按钮:白边 1px 白字 (#FFFFFF) */
|
||
.modal-btn-cancel {
|
||
border-width: 0.39rpx;
|
||
border-style: solid;
|
||
border-color: #FFFFFF;
|
||
}
|
||
|
||
/* 确定按钮:白边 1px 白字(设计稿确认) */
|
||
.modal-btn-ok {
|
||
border-width: 0.39rpx;
|
||
border-style: solid;
|
||
border-color: #FFFFFF;
|
||
margin-left: 12.5rpx; /* 182-150-474 得:按钮1 474宽150,按钮2 656宽150 → 656-(474+150)=32 → 12.5rpx */
|
||
}
|
||
|
||
/* 按钮文字:24px Regular 白,48×38 → 18.75×14.84rpx 居中 */
|
||
.modal-btn-text {
|
||
font-size: 9.38rpx;
|
||
line-height: 14.84rpx;
|
||
font-weight: 350;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
}
|
||
|
||
/* ==================== 模拟拼音键盘(内嵌于添加设备弹窗内,遮罩+键盘面板) ==================== */
|
||
.kbd-mask {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.4);
|
||
align-items: flex-end;
|
||
justify-content: center;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* 键盘面板:宽与弹窗一致(500rpx),高约 150rpx,深色系 #141825 与设计稿统一 */
|
||
.kbd-panel {
|
||
width: 500rpx;
|
||
padding-top: 6.25rpx;
|
||
padding-bottom: 6.25rpx;
|
||
padding-left: 3.91rpx;
|
||
padding-right: 3.91rpx;
|
||
background-color: #141825;
|
||
border-top-width: 0.78rpx;
|
||
border-top-style: solid;
|
||
border-top-color: #242738;
|
||
}
|
||
|
||
.kbd-title {
|
||
width: 100%;
|
||
height: 15.63rpx;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
padding-left: 7.81rpx;
|
||
padding-right: 7.81rpx;
|
||
margin-bottom: 3.91rpx;
|
||
}
|
||
|
||
.kbd-title-text {
|
||
flex: 1;
|
||
font-size: 9.38rpx;
|
||
line-height: 15.63rpx;
|
||
font-weight: 500;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.kbd-close {
|
||
width: 11.72rpx;
|
||
height: 11.72rpx;
|
||
font-size: 8.2rpx;
|
||
line-height: 11.72rpx;
|
||
color: #636E80;
|
||
text-align: center;
|
||
}
|
||
|
||
.kbd-row {
|
||
width: 100%;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 2.34rpx;
|
||
}
|
||
|
||
/* 单键:统一 31.25×15.63rpx(约 80×40 Figma px),圆角 2.34rpx,#242738 背景,白字 */
|
||
.kbd-key {
|
||
width: 31.25rpx;
|
||
height: 15.63rpx;
|
||
margin-left: 0.78rpx;
|
||
margin-right: 0.78rpx;
|
||
background-color: #242738;
|
||
border-radius: 2.34rpx;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.kbd-key-text {
|
||
font-size: 8.59rpx;
|
||
line-height: 14.06rpx;
|
||
font-weight: 500;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 数字小键(更紧凑) */
|
||
.kbd-key-num {
|
||
width: 23.44rpx;
|
||
height: 15.63rpx;
|
||
}
|
||
|
||
/* 空格键 */
|
||
.kbd-key-space {
|
||
width: 78.13rpx;
|
||
height: 15.63rpx;
|
||
}
|
||
|
||
/* 删除键 */
|
||
.kbd-key-del {
|
||
width: 39.06rpx;
|
||
height: 15.63rpx;
|
||
}
|
||
|
||
/* 确认键:蓝色底,白字 */
|
||
.kbd-key-ok {
|
||
width: 46.88rpx;
|
||
height: 15.63rpx;
|
||
background-color: #0093F9;
|
||
}
|
||
|
||
.kbd-key-ok-text {
|
||
color: #FFFFFF;
|
||
}
|
||
</style>
|