SEC_Warehouse/pages/index/index.vue

321 lines
7.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<!-- 首页:切换为 uview-plus 组件化结构,保留原有设备添加与配置入口 -->
<template>
<view class="page page-base">
<up-navbar title="智慧养老" :fixed="false" :safe-area-inset-top="true" :border="false" left-icon="" />
<view class="banner">
<view class="banner-left">
<text class="banner-title">智慧养老云助手</text>
<text class="banner-sub">一键开启智慧好生活</text>
</view>
<view class="banner-illus">
<up-icon name="home" color="#ffffff" size="52" />
</view>
</view>
<up-notice-bar
mode="link"
:text="noticeText"
color="#2f5a3a"
bg-color="#e9fff3"
@click="goConfig"
/>
<view class="site-row" @click="goSceneSelect">
<view class="site-left">
<up-icon name="list" size="18" color="#26c996" />
<text class="site-text">{{ sceneName || '请选择场所' }}</text>
</view>
<up-icon name="arrow-right" size="14" color="#26c996" />
</view>
<!-- 设备列表:loading / 错误 / 空态 / 双列卡片网格 -->
<view v-if="loading" class="state-wrap">
<up-loading-icon mode="circle" size="48" text="加载中..." />
</view>
<view v-else-if="loadError" class="state-wrap">
<up-empty mode="wifi" text="加载失败,请检查网络" />
<up-button type="success" shape="circle" text="重试" class="retry-btn" @click="loadDevices" />
</view>
<view v-else-if="deviceList.length === 0" class="state-wrap">
<up-empty mode="list" text="暂无设备" />
<up-button type="success" shape="circle" text="添加设备" class="retry-btn" @click="goAdd" />
</view>
<view v-else class="device-grid">
<view
v-for="device in deviceList"
:key="device.id"
class="device-card"
@click="goDetail(device)"
>
<view class="device-icon" :class="{ 'device-icon--offline': !device.online }">
<up-icon :name="iconOf(device)" :color="device.online ? '#ffffff' : '#b5b9c0'" size="30" />
</view>
<text class="device-name">{{ device.name }}</text>
<view class="device-status">
<view class="status-dot" :class="device.online ? 'status-dot--on' : 'status-dot--off'" />
<text class="status-text" :class="{ 'status-text--off': !device.online }">
{{ device.online ? '在线' : '离线' }}
</text>
</view>
</view>
</view>
<view class="fab-wrap" @click="goAdd">
<up-icon name="plus" color="#ffffff" size="28" />
</view>
</view>
</template>
<script>
import { getDeviceList } from '@/api/device'
import { ROUTES } from '@/constants/routes'
import { navigateTo } from '@/utils/navigation'
import { getCurrentScene } from '@/store/scene'
// 设备型号 -> 图标映射,未命中走兜底图标。
const DEVICE_ICON_MAP = {
ED713: 'home',
ED719: 'bell'
}
const FALLBACK_ICON = 'setting'
export default {
data() {
return {
noticeText: '点击选择场所后可进入设备配置流程',
sceneName: '',
loading: true,
loadError: false,
deviceList: []
}
},
onShow() {
this.refreshScene()
this.loadDevices()
},
methods: {
// 从全局场景状态刷新回显文案。
refreshScene() {
const scene = getCurrentScene()
this.sceneName = scene ? scene.name : ''
},
// 拉取当前场所的设备列表;在线状态需新鲜,每次 onShow 重拉。
async loadDevices() {
this.loading = true
this.loadError = false
try {
const scene = getCurrentScene()
const data = await getDeviceList(scene ? scene.id : null)
this.deviceList = Array.isArray(data) ? data : []
} catch (error) {
this.loadError = true
} finally {
this.loading = false
}
},
// 设备型号对应图标。
iconOf(device) {
return DEVICE_ICON_MAP[device.model] || FALLBACK_ICON
},
// 进入场景选择页。
goSceneSelect() {
navigateTo(ROUTES.SCENE_SELECT)
},
// 进入设备添加页(后续会承接蓝牙配网流程入口)。
goAdd() {
navigateTo(ROUTES.DEVICE_ADD)
},
// 进入设备配置页。
goConfig() {
navigateTo(ROUTES.DEVICE_CONFIG)
},
// 进入设备详情页:携带基础信息,后续接详情接口后改为仅传 id。
goDetail(device) {
const name = encodeURIComponent(device.name || '')
navigateTo(`${ROUTES.DEVICE_DETAIL}?id=${device.id}&name=${name}&model=${device.model || ''}&online=${device.online ? 1 : 0}`)
}
}
}
</script>
<style lang="scss" scoped>
@import '@/styles/common.css';
.page {
position: relative;
}
.banner {
margin: 0;
min-height: 360rpx;
background: linear-gradient(135deg, #1fca97 0%, #2dbf9c 100%);
padding: 48rpx 44rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.banner-left {
display: flex;
flex-direction: column;
}
.banner-title {
font-size: 52rpx;
color: #ffffff;
font-weight: 700;
margin-bottom: 20rpx;
}
.banner-sub {
font-size: 34rpx;
color: #e9fff8;
font-weight: 600;
}
.banner-illus {
width: 180rpx;
height: 180rpx;
border-radius: 24rpx;
background: rgba(255, 255, 255, 0.18);
display: flex;
align-items: center;
justify-content: center;
}
.site-row {
height: 108rpx;
padding: 0 32rpx;
background: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
}
.site-left {
display: flex;
align-items: center;
}
.site-text {
margin-left: 14rpx;
font-size: 34rpx;
color: #222;
font-weight: 600;
}
/* 列表三态容器 */
.state-wrap {
margin-top: 80rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.retry-btn {
margin-top: 40rpx;
width: 240rpx;
}
/* 设备双列网格 */
.device-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 24rpx 24rpx 0;
}
.device-card {
width: 48.5%;
margin-bottom: 24rpx;
padding: 36rpx 20rpx 28rpx;
box-sizing: border-box;
background: #ffffff;
border-radius: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
&:active {
background: #f7f8fa;
}
}
.device-icon {
width: 108rpx;
height: 108rpx;
border-radius: 50%;
background: linear-gradient(135deg, #1fca97 0%, #2dbf9c 100%);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
&--offline {
background: #eef0f4;
}
}
.device-name {
max-width: 100%;
font-size: 28rpx;
font-weight: 600;
color: #2a2d33;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.device-status {
margin-top: 12rpx;
display: flex;
align-items: center;
}
.status-dot {
width: 14rpx;
height: 14rpx;
border-radius: 50%;
margin-right: 10rpx;
&--on {
background: #2ccb98;
}
&--off {
background: #c0c4cc;
}
}
.status-text {
font-size: 24rpx;
color: #12a37a;
&--off {
color: #9ea1a6;
}
}
.fab-wrap {
position: fixed;
right: 40rpx;
bottom: 60rpx;
width: 112rpx;
height: 112rpx;
border-radius: 50%;
background: linear-gradient(135deg, #1fca97 0%, #2dbf9c 100%);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(31, 202, 151, 0.4);
/* 点击态缩放反馈 */
&:active {
transform: scale(0.92);
}
}
</style>