| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869 |
- <template>
- <view class="container">
- <!-- 搜索区域 -->
- <view class="search-section">
- <view class="search-box" :class="{ 'search-focus': isSearchFocused }">
- <view class="search-icon">
- <text class="iconfont icon-search"></text>
- </view>
- <input
- class="search-input"
- type="text"
- v-model="searchKeyword"
- placeholder="搜索设备名称 / 编号"
- confirm-type="search"
- @confirm="handleSearch"
- @focus="isSearchFocused = true"
- @blur="isSearchFocused = false"
- />
- <view class="clear-icon" v-if="searchKeyword" @click="handleClearSearch">
- <text class="iconfont icon-close"></text>
- </view>
- </view>
- </view>
-
- <!-- 状态筛选区域 -->
- <view class="filter-section">
- <view
- class="filter-item"
- :class="{ active: statusFilter === 'all' }"
- @click="setStatusFilter('all')"
- >
- 全部
- </view>
- <view
- class="filter-item"
- :class="{ active: statusFilter === 'online' }"
- @click="setStatusFilter('online')"
- >
- <view class="filter-dot online-dot"></view>
- 在线 ({{ onlineCount }})
- </view>
- <view
- class="filter-item"
- :class="{ active: statusFilter === 'offline' }"
- @click="setStatusFilter('offline')"
- >
- <view class="filter-dot offline-dot"></view>
- 离线 ({{ offlineCount }})
- </view>
- </view>
-
- <!-- 设备列表区域 -->
- <scroll-view
- scroll-y
- class="device-list"
- @scrolltolower="loadMore"
- :scroll-with-animation="true"
- :enable-back-to-top="true"
- :refresher-enabled="true"
- :refresher-threshold="80"
- :refresher-triggered="isRefreshing"
- @refresherrefresh="handleRefresh"
- @refresherrestore="isRefreshing = false"
- >
- <!-- 无数据提示 -->
- <view v-if="filteredDeviceList.length === 0 && !isLoading" class="empty-tips">
- <view class="empty-icon">
- <text class="iconfont icon-empty"></text>
- </view>
- <text class="empty-text">{{ searchKeyword ? '未找到匹配的设备' : '暂无设备' }}</text>
- <view v-if="searchKeyword" class="empty-action" @click="handleClearSearch">
- <text>清除搜索条件</text>
- </view>
- </view>
-
- <!-- 首次加载中状态 -->
- <view v-if="isLoading && deviceList.length === 0" class="loading-container">
- <view class="loading-spinner"></view>
- <text class="loading-text">加载中...</text>
- </view>
-
- <!-- 设备列表 -->
- <view
- v-for="(item, index) in filteredDeviceList"
- :key="index"
- class="device-card"
- :class="{
- 'has-alert': item.alarmCount > 0,
- 'is-offline': item.status === 'offline'
- }"
- hover-class="device-card-hover"
- hover-stay-time="70"
- @click="navigateToDetail(item)"
- >
- <!-- 设备基本信息 -->
- <view class="device-info">
- <view class="device-icon-wrapper">
- <!-- 告警角标 -->
- <view v-if="item.alarmCount > 0" class="alarm-badge">
- {{ item.alarmCount }}
- </view>
-
- <view class="device-icon-container" :class="{'offline-icon': item.status === 'offline'}">
- <image :src="getDeviceIcon(item.type)" mode="aspectFit" class="device-icon"></image>
- </view>
- </view>
-
- <view class="device-meta">
- <view class="device-name-row">
- <text class="device-name" :class="{'offline-text': item.status === 'offline'}">{{ item.name }}</text>
- <view
- class="status-tag"
- :class="item.status === 'online' ? 'status-online' : 'status-offline'"
- >
- <text class="status-dot" :class="{'offline-dot': item.status === 'offline'}"></text>
- {{ item.status === 'online' ? '在线' : '离线' }}
- </view>
- </view>
-
- <view class="device-id">
- <text class="id-label">设备编号:</text>
- <text class="id-value">{{ item.code }}</text>
- </view>
-
- <view class="device-location">
- <text class="location-label">安装位置:</text>
- <text class="location-value">{{ item.location }}</text>
- </view>
- </view>
- </view>
-
- <!-- 底部信息栏 -->
- <view class="device-footer">
- <text class="update-time">{{ item.updateTime }}</text>
- <view class="device-actions">
- <text class="iconfont icon-right"></text>
- </view>
- </view>
- </view>
-
- <!-- 加载更多提示 -->
- <view v-if="filteredDeviceList.length > 0" class="load-more">
- <view class="load-more-content" v-if="loadMoreStatus === 'loading'">
- <view class="loading-icon"></view>
- <text>正在加载...</text>
- </view>
- <view class="load-more-content" v-if="loadMoreStatus === 'nomore'">
- <text>没有更多了</text>
- </view>
- <view class="load-more-content" v-if="loadMoreStatus === 'loadmore'" @click="loadMore">
- <text>点击加载更多</text>
- </view>
- </view>
- </scroll-view>
- </view>
- </template>
- <script>
- export default {
- data() {
- return {
- deviceType: '',
- searchKeyword: '',
- isSearchFocused: false,
- statusFilter: 'all', // 'all', 'online', 'offline'
- deviceList: [],
- page: 1,
- limit: 10,
- loadMoreStatus: 'loading', // 'loadmore', 'loading', 'nomore'
- isLoading: true,
- isRefreshing: false
- }
- },
-
- computed: {
- // 过滤后的设备列表
- filteredDeviceList() {
- let result = this.deviceList;
-
- // 按状态筛选
- if (this.statusFilter !== 'all') {
- result = result.filter(device => device.status === this.statusFilter);
- }
-
- // 按关键词搜索
- if (this.searchKeyword) {
- const keyword = this.searchKeyword.toLowerCase();
- result = result.filter(device =>
- device.name.toLowerCase().includes(keyword) ||
- device.code.toLowerCase().includes(keyword)
- );
- }
-
- return result;
- },
-
- // 在线设备数量
- onlineCount() {
- return this.deviceList.filter(device => device.status === 'online').length;
- },
-
- // 离线设备数量
- offlineCount() {
- return this.deviceList.filter(device => device.status === 'offline').length;
- }
- },
-
- onLoad(options) {
- // 获取路由参数
- if (options.type) {
- this.deviceType = options.type;
- this.setPageTitle();
- }
-
- // 加载设备数据
- this.loadDeviceData();
- },
-
- methods: {
- // 设置页面标题
- setPageTitle() {
- const titleMap = {
- 'monitor': '监控设备列表',
- 'sensor': '采集设备列表',
- 'control': '控制设备列表',
- 'irrigation': '灌溉设备列表',
- 'tractor': '农机设备列表'
- };
-
- const title = titleMap[this.deviceType] || '设备列表';
- uni.setNavigationBarTitle({
- title: title
- });
- },
-
- // 获取设备图标
- getDeviceIcon(type) {
- const iconMap = {
- 'monitor': '/static/icons/camera.png',
- 'sensor': '/static/icons/sensor.png',
- 'control': '/static/icons/control.png',
- 'irrigation': '/static/icons/water.png',
- 'tractor': '/static/icons/tractor.png'
- };
-
- return iconMap[type] || '/static/icons/device-default.png';
- },
-
- // 设置状态筛选
- setStatusFilter(status) {
- this.statusFilter = status;
- },
-
- // 加载设备数据
- loadDeviceData() {
- this.isLoading = true;
-
- // 模拟API请求数据
- setTimeout(() => {
- // 这里应该是真实的API请求
- // 模拟一些设备数据用于展示
- const newDevices = this.generateMockDevices();
- this.deviceList = [...this.deviceList, ...newDevices];
-
- if (this.deviceList.length >= 30) {
- this.loadMoreStatus = 'nomore';
- } else {
- this.loadMoreStatus = 'loadmore';
- }
-
- this.isLoading = false;
- this.isRefreshing = false;
- }, 1000);
- },
-
- // 生成模拟设备数据
- generateMockDevices() {
- const devices = [];
- const locations = ['东区A1地块', '西区B2地块', '南区C3地块', '北区D4地块'];
- const updateTimes = ['刚刚更新', '1分钟前更新', '5分钟前更新', '10分钟前更新', '1小时前更新'];
-
- // 根据当前页码和限制数量生成对应数量的模拟数据
- const startIndex = (this.page - 1) * this.limit;
- for (let i = 0; i < this.limit; i++) {
- const index = startIndex + i;
-
- // 如果已经生成了30条数据,则停止
- if (index >= 30) break;
-
- // 对于采集设备类型,生成随机的气象或土壤设备
- let deviceType = this.deviceType;
- let deviceCode = `DEV${String(index + 1001).padStart(4, '0')}`;
-
- // 如果是采集设备,随机生成气象站或土壤墒情设备
- if (this.deviceType === 'sensor') {
- // 随机分配采集设备子类型:气象站或土壤墒情
- const sensorSubType = Math.random() > 0.5 ? 'weather' : 'soil';
- deviceCode = sensorSubType === 'weather' ? `W${deviceCode}` : `S${deviceCode}`;
- }
-
- devices.push({
- id: `device-${index + 1}`,
- name: `${this.getDeviceTypeName(this.deviceType)}-${index + 1}`,
- code: deviceCode,
- type: deviceType,
- status: Math.random() > 0.3 ? 'online' : 'offline', // 70% 概率在线
- location: locations[Math.floor(Math.random() * locations.length)],
- updateTime: updateTimes[Math.floor(Math.random() * updateTimes.length)],
- alarmCount: Math.random() > 0.7 ? Math.floor(Math.random() * 3) + 1 : 0 // 30% 概率有告警
- });
- }
-
- return devices;
- },
-
- // 获取设备类型名称
- getDeviceTypeName(type) {
- const nameMap = {
- 'monitor': '监控设备',
- 'sensor': '采集设备',
- 'control': '控制设备',
- 'irrigation': '灌溉设备',
- 'tractor': '农机设备'
- };
-
- return nameMap[type] || '未知设备';
- },
-
- // 处理搜索
- handleSearch() {
- // 执行搜索逻辑
- console.log('搜索关键词:', this.searchKeyword);
- },
-
- // 处理清空搜索
- handleClearSearch() {
- this.searchKeyword = '';
- },
-
- // 加载更多数据
- loadMore() {
- if (this.loadMoreStatus !== 'nomore') {
- this.loadMoreStatus = 'loading';
- this.page += 1;
- this.loadDeviceData();
- }
- },
-
- // 跳转到设备详情页
- navigateToDetail(device) {
- // 根据设备类型跳转到不同的详情页
- let url = '';
-
- if (device.type === 'monitor') {
- url = `/pages/device-list/detail-camera?id=${device.id}`;
- } else if (device.type === 'sensor') {
- // 采集设备跳转到采集设备详情页,同时传递设备编码,便于判断设备子类型
- url = `/pages/device-list/detail-collector?id=${device.id}&code=${device.code}`;
- } else {
- // 其他类型设备暂时使用通用详情页
- url = `/pages/device-detail/index?id=${device.id}&type=${device.type}`;
- }
-
- uni.navigateTo({
- url: url
- });
- },
-
- // 处理刷新
- handleRefresh() {
- this.isRefreshing = true;
- this.page = 1;
- this.deviceList = [];
- this.loadDeviceData();
- }
- }
- }
- </script>
- <style scoped>
- /* 图标字体 */
- @font-face {
- font-family: "iconfont";
- src: url('data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAAOMAAsAAAAACFAAAAM+AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACDMgqDGIJmATYCJAMUCwwABCAFhGcHRhvqBsgOJaDgwABgBNFYPPy3H/3OSB4kWdI1Pb2QBw8gSpZIsxBFsTCNTIm//9dv/7FzF1E1S9ysIZWDPNdPJdSYbfLy/+fpTTMwKn5ZZ3OImpRUTZ8FHAcYFrLCBqyAHZD3CP9I09oXUgNcDSEAS8oGR507tO6KhRQTNQGQyeNGD8PCkVATUkFYsMgGcuqQ5YiFWruCPAVYnn9f/KGFBQxrghRq0KjzAXS5TP3SHp3ZmXUyEIfTAYDvDEiQARSQiaJjIjKaZiDJ+hpQYnY1i8tK1ZfWl83/fxYLm8TS//EADBBU6C9ghIBwJXxprxqwhC8d6x9AvAB4BcARgGWgRlWY71Cn5I5XvJ5Ot5sXy91Ud9Oj1nXnfbK9vK09bVsrGq2rrB1sxMcbxZmXntbdI8u6cRGhGy9r92Hj7hCjx1G6Dd9G9N6sbSvwVZiw+/hC0D7WFi5tbcltVyPOdqm41HkQr9T0bKFa2zrLLVeKJufZy7vn7aXtY+3XMvl65fJ7wnHT7ZJWozcvrHC5XNnTGy5/0NvX1xdSu8W9Ml0ePXEqZ3Jm0r6SLSdPbJnc27Mm05YsrLjfI8Ypvb5dL5pAj9m5c3Tzw+UvtK/SzO/Vv+Dt/9Lfq3+Xr30Hf9pz0JsnGgsPDBWHv+v12l5zGsE7Pz9A2d0W9WJ2dUZ/a/PkxQW58o/asvHDfyvJEw39G/5zf2p9OmZFYYGKoioVKPzPpwQA0+d2xv7C/aL/Dx/m7QfkjDLZL8AH4F3p+8PBrGIuqFLmM3uqfI6+YxAFCRZWAQ9LM8Q3JuRm2/bCgWEDCgzzIFgrEYk0AxgciQCDtQxgSRr76yYgfkIiHoB0FxGEEKfAEOQMJCHukYj0CQyjPsMQ0oJgyQD6hI6DL3FILJJLiqDqQs9kbYnLnTRuoA+5j7HsWmUJG2QdvdPrY51xR0WpwQZZIJvsGJ8OWYgVpomO28rIDCGTHHGJpqFe7xSPlUXs04FBiQV1FxSCqhboGVlrEldXpOGP94G4Hwydnaj6DjJBj1dvVtZizE8WlMYD9rHWaVsLsmF6QhZEmMDsIk1wOZWLgSHSSTkEJzGNQvvLc3HLFVXz9euBBWkm+YbLZKGH3uISrbIXRuNaAA==');
- }
- .iconfont {
- font-family: "iconfont" !important;
- font-size: 24rpx;
- font-style: normal;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- }
- .icon-search:before {
- content: "\e6e1";
- font-size: 32rpx;
- }
- .icon-close:before {
- content: "\e6a7";
- font-size: 28rpx;
- }
- .icon-right:before {
- content: "\e6a3";
- font-size: 28rpx;
- }
- .icon-empty:before {
- content: "\e6a9";
- font-size: 80rpx;
- }
- /* 容器样式 */
- .container {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- background-color: #F9FCFA;
- padding-bottom: 20rpx;
- }
- /* 搜索区域 */
- .search-section {
- padding: 20rpx 30rpx;
- background-color: #FFFFFF;
- margin-bottom: 2rpx;
- width: 100%;
- box-sizing: border-box;
- position: relative;
- z-index: 5;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03);
- }
- .search-box {
- display: flex;
- align-items: center;
- background-color: #F7F7F7;
- height: 80rpx;
- border-radius: 40rpx;
- padding: 0 24rpx;
- width: 100%;
- box-sizing: border-box;
- border: 2rpx solid transparent;
- transition: all 0.3s ease;
- }
- .search-box.search-focus {
- border-color: #4CAF50;
- background-color: #FFFFFF;
- box-shadow: 0 0 10rpx rgba(76, 175, 80, 0.1);
- }
- .search-icon {
- color: #4CAF50;
- width: 60rpx;
- display: flex;
- justify-content: center;
- }
- .search-input {
- flex: 1;
- height: 80rpx;
- font-size: 28rpx;
- color: #333333;
- }
- .clear-icon {
- width: 60rpx;
- display: flex;
- justify-content: center;
- color: #999;
- }
- /* 状态筛选区域 */
- .filter-section {
- display: flex;
- padding: 24rpx 30rpx;
- background-color: #FFFFFF;
- margin-bottom: 20rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
- position: relative;
- z-index: 4;
- }
- .filter-item {
- display: flex;
- align-items: center;
- font-size: 28rpx;
- color: #666666;
- margin-right: 30rpx;
- padding: 12rpx 20rpx;
- border-radius: 30rpx;
- transition: all 0.2s ease;
- position: relative;
- }
- .filter-item.active {
- background-color: #F0F9F0;
- color: #4CAF50;
- font-weight: 500;
- }
- .filter-dot {
- width: 14rpx;
- height: 14rpx;
- border-radius: 50%;
- margin-right: 10rpx;
- }
- .online-dot {
- background-color: #4CAF50;
- box-shadow: 0 0 6rpx rgba(76, 175, 80, 0.5);
- }
- .offline-dot {
- background-color: #F56C6C;
- box-shadow: 0 0 6rpx rgba(245, 108, 108, 0.5);
- }
- /* 设备列表区域 */
- .device-list {
- flex: 1;
- padding: 0 30rpx;
- box-sizing: border-box;
- width: 100%;
- position: relative;
- z-index: 3;
- }
- /* 空数据提示 */
- .empty-tips {
- padding: 120rpx 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
- .empty-icon {
- color: #DDDDDD;
- margin-bottom: 20rpx;
- }
- .empty-text {
- font-size: 28rpx;
- color: #999999;
- margin-bottom: 20rpx;
- }
- .empty-action {
- font-size: 26rpx;
- color: #4CAF50;
- padding: 12rpx 30rpx;
- border-radius: 30rpx;
- background-color: rgba(76, 175, 80, 0.1);
- }
- /* 首次加载中状态 */
- .loading-container {
- padding: 80rpx 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
- .loading-spinner {
- width: 60rpx;
- height: 60rpx;
- border: 4rpx solid #E0E0E0;
- border-top: 4rpx solid #4CAF50;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- margin-bottom: 20rpx;
- }
- .loading-text {
- font-size: 28rpx;
- color: #999999;
- }
- /* 设备卡片 */
- .device-card {
- position: relative;
- background-color: #FFFFFF;
- border-radius: 24rpx;
- padding: 28rpx;
- margin-bottom: 24rpx;
- box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.05);
- transition: all 0.25s ease;
- width: 100%;
- box-sizing: border-box;
- border: 1rpx solid rgba(0, 0, 0, 0.05);
- overflow: hidden;
- }
- .device-card::before {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 6rpx;
- height: 100%;
- background: linear-gradient(to bottom, #66CC6A, #3BB44A);
- opacity: 0;
- transition: opacity 0.3s ease;
- }
- .device-card:active::before {
- opacity: 1;
- }
- .device-card-hover {
- background-color: #f2fef6;
- box-shadow: 0 10rpx 25rpx rgba(59, 180, 74, 0.1);
- transform: translateY(-3rpx);
- }
- .device-card.has-alert {
- box-shadow: 0 6rpx 20rpx rgba(245, 108, 108, 0.08);
- border: 1rpx solid rgba(245, 108, 108, 0.08);
- }
- .device-card.has-alert::before {
- background: linear-gradient(to bottom, #FF8F8F, #F56C6C);
- }
- .device-card.is-offline {
- opacity: 0.9;
- }
- .device-card.is-offline.device-card-hover {
- background-color: #f5f5f5;
- box-shadow: 0 10rpx 25rpx rgba(0, 0, 0, 0.05);
- }
- /* 告警角标 */
- .alarm-badge {
- position: absolute;
- top: -8rpx;
- right: -8rpx;
- min-width: 36rpx;
- height: 36rpx;
- border-radius: 18rpx;
- background-color: #F56C6C;
- color: #FFFFFF;
- font-size: 22rpx;
- font-weight: 600;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 0 8rpx;
- z-index: 3;
- box-shadow: 0 3rpx 8rpx rgba(245, 108, 108, 0.3);
- animation: pulse 1.5s infinite;
- }
- @keyframes pulse {
- 0% {
- transform: scale(1);
- }
- 50% {
- transform: scale(1.1);
- }
- 100% {
- transform: scale(1);
- }
- }
- /* 设备基本信息 */
- .device-info {
- display: flex;
- margin-bottom: 24rpx;
- width: 100%;
- }
- .device-icon-wrapper {
- position: relative;
- margin-right: 24rpx;
- flex-shrink: 0;
- }
- .device-icon-container {
- width: 96rpx;
- height: 96rpx;
- border-radius: 50%;
- background: linear-gradient(135deg, #66CC6A 0%, #3BB44A 100%);
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- box-shadow: 0 6rpx 16rpx rgba(59, 180, 74, 0.2);
- transition: all 0.3s ease;
- }
- .device-icon-container.offline-icon {
- background: linear-gradient(135deg, #AAB2BD 0%, #656D78 100%);
- box-shadow: 0 6rpx 16rpx rgba(101, 109, 120, 0.2);
- }
- .device-icon {
- width: 52rpx;
- height: 52rpx;
- filter: brightness(0) invert(1);
- }
- .device-meta {
- flex: 1;
- width: calc(100% - 120rpx);
- overflow: hidden;
- }
- .device-name-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 14rpx;
- width: 100%;
- }
- .device-name {
- font-size: 34rpx;
- font-weight: 600;
- color: #333333;
- max-width: 65%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- transition: color 0.3s ease;
- }
- .device-name.offline-text {
- color: #656D78;
- }
- .status-tag {
- padding: 6rpx 16rpx 6rpx 32rpx;
- border-radius: 8rpx;
- font-size: 24rpx;
- font-weight: 500;
- flex-shrink: 0;
- border: 1rpx solid;
- position: relative;
- overflow: hidden;
- }
- .status-online {
- background-color: rgba(76, 175, 80, 0.1);
- color: #4CAF50;
- border-color: rgba(76, 175, 80, 0.3);
- }
- .status-dot {
- position: absolute;
- width: 8rpx;
- height: 8rpx;
- background-color: #4CAF50;
- border-radius: 50%;
- top: 50%;
- left: 16rpx;
- transform: translateY(-50%);
- box-shadow: 0 0 4rpx rgba(76, 175, 80, 0.8);
- animation: blink 1.5s infinite;
- display: inline-block;
- }
- .status-dot.offline-dot {
- background-color: #F56C6C;
- box-shadow: 0 0 4rpx rgba(245, 108, 108, 0.8);
- }
- .status-offline {
- background-color: rgba(245, 108, 108, 0.1);
- color: #F56C6C;
- border-color: rgba(245, 108, 108, 0.3);
- padding-left: 32rpx;
- }
- @keyframes blink {
- 0% {
- opacity: 0.4;
- }
- 50% {
- opacity: 1;
- }
- 100% {
- opacity: 0.4;
- }
- }
- .device-id, .device-location {
- display: flex;
- font-size: 26rpx;
- margin-top: 10rpx;
- color: #666666;
- width: 100%;
- overflow: hidden;
- }
- .id-label, .location-label {
- color: #999999;
- margin-right: 8rpx;
- flex-shrink: 0;
- }
- .id-value, .location-value {
- color: #666666;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- /* 底部信息栏 */
- .device-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding-top: 18rpx;
- border-top: 1rpx solid #F2F2F2;
- }
- .update-time {
- font-size: 24rpx;
- color: #999999;
- }
- .device-actions {
- display: flex;
- align-items: center;
- color: #CCCCCC;
- }
- /* 加载更多区域 */
- .load-more {
- padding: 20rpx 0 40rpx;
- }
- .load-more-content {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 60rpx;
- font-size: 24rpx;
- color: #999999;
- }
- .loading-icon {
- width: 30rpx;
- height: 30rpx;
- margin-right: 10rpx;
- border: 2rpx solid #E0E0E0;
- border-top: 2rpx solid #4CAF50;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- }
- @keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
- }
- </style>
|