首页接入真实数据

feasure
lld 2026-02-13 00:13:18 +08:00
parent 4457402aa4
commit a8d60b5829
4 changed files with 224 additions and 71 deletions

View File

@ -60,7 +60,6 @@ export default {
console.log('小程序切前台/首次显示') console.log('小程序切前台/首次显示')
const token = getToken() || this.globalData.mqtt.token const token = getToken() || this.globalData.mqtt.token
if (token) { if (token) {
this.$tab.reLaunch('/pages/index')
// globalData // globalData
if (this.globalData.mqtt.subscribeList.length === 0) { if (this.globalData.mqtt.subscribeList.length === 0) {
const savedSubscribeList = uni.getStorageSync('mqtt_subscribe_list') const savedSubscribeList = uni.getStorageSync('mqtt_subscribe_list')

View File

@ -16,6 +16,13 @@ export function getAgri(id) {
method: 'get' method: 'get'
}) })
} }
export function getAgriInfo(query) {
return request({
url: '/assets/agri/findAgriInfoByUser',
method: 'get',
params: query
})
}
// 新增大棚管理 // 新增大棚管理
export function addAgri(data) { export function addAgri(data) {

View File

@ -1,23 +1,25 @@
<template> <template>
<view class="page-container"> <view class="page-container">
<z-paging ref="paging" refresher-only bg-color="radial-gradient(circle at top left, #E8F4F8 40%, #F8FCFE 100%)" <z-paging ref="index" refresher-only bg-color="radial-gradient(circle at top left, #E8F4F8 40%, #F8FCFE 100%)"
:show-empty="false" :show-footer="false" @onRefresh="refresh"> :show-empty="false" :show-footer="false" @onRefresh="refresh">
<template #refresher="{refresherStatus}"> <template #refresher="{refresherStatus}">
<!-- 此处的custom-refresh为demo中自定义的组件非z-paging的内置组件请在实际项目中自行创建这里插入什么view下拉刷新就显示什么view --> <!-- 此处的custom-refresh为demo中自定义的组件非z-paging的内置组件请在实际项目中自行创建这里插入什么view下拉刷新就显示什么view -->
<custom-refresher :status="refresherStatus" /> <custom-refresher :status="refresherStatus" />
</template> </template>
<!-- confirm:confirm; input:change; cancel:点击取消
clear点击清除focus:获取焦点blur失去焦点 -->
<uni-row class="demo-uni-row" > <uni-row class="demo-uni-row" >
<uni-col :span="7"> <uni-col :span="7">
<uni-data-select align="left" :clear="false" v-model="value" :localdata="range" ></uni-data-select> <uni-data-select align="left" :clear="false" v-model="value" @change="change" :localdata="range" ></uni-data-select>
</uni-col> </uni-col>
<uni-col :span="17"> <uni-col :span="17">
<uni-search-bar @confirm="search" :focus="true" bgColor="#fbfdfe" <!-- confirm:confirm; input:change; cancel:点击取消
clear点击清除focus:获取焦点blur失去焦点 -->
<uni-search-bar :focus="true" bgColor="#fbfdfe"
v-model="searchValue" v-model="searchValue"
cancelButton="always" cancelButton="always"
placeholder="请输入搜索内容" @input="input"
@cancel="cancel" @clear="cancel"> @cancel="cancel"
@clear="cancel"
placeholder="请输入搜索内容">
</uni-search-bar> </uni-search-bar>
</uni-col> </uni-col>
</uni-row> </uni-row>
@ -36,13 +38,13 @@
@tap="item.online !== '离线' && onItemTap(item)" @tap="item.online !== '离线' && onItemTap(item)"
> >
<view class="item-title"> <view class="item-title">
<view class="title-text">{{ item.title }}</view> <view class="title-text">{{ item.agriName }}</view>
<text :class="['tag','tag-status',{'tag-manual':item.status==='手动模式'}]" v-if="item.status">{{ item.status }}</text> <text :class="['tag','tag-status',{'tag-manual':item.workMode==='手动模式'}]" v-if="item.workMode">{{ item.workMode }}</text>
<text :class="['tag','tag-online',{'tag-offline':item.online==='离线'}]" v-if="item.online">{{ item.online }}</text> <text :class="['tag','tag-online',{'tag-offline':item.online==='离线'}]" v-if="item.online">{{ item.online }}</text>
</view> </view>
<view class="item-subtitle"> <view class="item-subtitle">
{{ item.subtitle }} {{ item.imei }}
</view> </view>
<view class="item-tags"> <view class="item-tags">
@ -73,13 +75,17 @@
<script> <script>
import ZPaging from "../uni_modules/z-paging/components/z-paging/z-paging.vue"; import ZPaging from "../uni_modules/z-paging/components/z-paging/z-paging.vue";
import CustomRefresher from "../components/custom-refresher/custom-refresher.vue"; import CustomRefresher from "../components/custom-refresher/custom-refresher.vue";
import {getAgriInfo} from "../api/system/assets/agri";
import store from "../store";
import TimeUtil from "../utils/TimeUtil";
import {getNewSpecialData} from "../api/data/specialData";
export default { export default {
components: {CustomRefresher, ZPaging}, components: {CustomRefresher, ZPaging},
data() { data() {
return { return {
listData: [], listData: [],
page: 1, datas: [],
pageSize: 6, pageSize: 6,
isLoading: false, isLoading: false,
noMore: false, noMore: false,
@ -134,8 +140,8 @@ export default {
} }
return false*/ return false*/
}, },
onLoad() { onShow() {
this.getListData() this.refresh();
}, },
onReady() { onReady() {
@ -149,21 +155,15 @@ export default {
// //
// uni.navigateTo({ url: '/pages/add-agri/add-agri' }) // uni.navigateTo({ url: '/pages/add-agri/add-agri' })
}, },
search(res) { change(e) {
uni.showToast({ this.input(this.searchValue)
title: '搜索:' + res.value,
icon: 'none'
})
}, },
input(res) { input(res) {
this.listData = this.datas.filter(item =>
item[this.value === 0 ? 'agriName' : 'imei'].includes(res));
}, },
cancel(res) { cancel(res) {
uni.showToast({ this.listData = [...this.datas]
title: '点击取消,输入值为:' + res.value,
icon: 'none'
})
}, },
/*trigger(e) { /*trigger(e) {
console.log(e) console.log(e)
@ -186,68 +186,108 @@ export default {
icon: 'none' icon: 'none'
}) })
},*/ },*/
// //
getListData(isRefresh = false) { getListData() {
if (isRefresh) { this.noMore = false;
this.page = 1 this.listData = [];
this.noMore = false if (this.isLoading || this.noMore) return;
this.listData = [] this.isLoading = true;
getAgriInfo().then(response => {
if (response.code === 200) {
// 1. map forEach undefined
// 2. / listData
this.listData = response.data.map(item => {
//
return {
...item,
deviceStatus: TimeUtil.isLessThanSpecifiedSeconds(item.time, 90) ? '在线' : '离线',
online: TimeUtil.isLessThanSpecifiedSeconds(item.time, 90) ? '在线' : '离线', // online
agriName: item.agriName || '未知大棚',
imei: `设备编号:${item.imei || '未知'}`,
workMode: item.workMode === 0 ? '手动模式' : '自动模式',
temp1: item.temp1,
temp2: item.temp2,
temp3: item.temp3,
temp4: item.temp4
};
});
} }
}).catch(err => {
if (this.isLoading || this.noMore) return console.error("获取大棚信息失败:", err);
uni.showToast({ title: "数据加载失败", icon: "none" });
this.isLoading = true }).finally(() => {
// 4.
// this.isLoading = false;
setTimeout(() => { // 5.
const start = (this.page - 1) * this.pageSize this.noMore = this.listData.length >= this.total;
const end = this.page * this.pageSize if (store.getters && store.getters.name === 'admin') {
const newData = [] this.getNewSpecialData();
for (let i = start; i < end && i < this.total; i++) {
// idv-forkey
newData.push({
id: `item-${i}`,
title: `设备名称${i + 1}`,
subtitle: `设备编号SN-${10000 + i}`,
status: i % 2 === 0 ? "自动模式" : "手动模式",
online: i % 3 === 0 ? "在线" : "离线",
temp1: Math.floor(Math.random() * 51), // 0-50
temp2: Math.floor(Math.random() * 51),
temp3: Math.floor(Math.random() * 51),
temp4: Math.floor(Math.random() * 51)
})
} }
this.datas = [...this.listData]
this.listData = isRefresh ? newData : [...this.listData, ...newData] this.$refs.index.complete();
this.page++ });
this.isLoading = false
if (this.listData.length >= this.total) {
this.noMore = true
}
}, 0)
}, },
// //
loadMore() { loadMore() {
if (!this.isLoading && !this.noMore) { if (!this.isLoading && !this.noMore) {
//
setTimeout(() => {
this.getListData()
}, 100)
} }
}, },
refresh() { refresh() {
this.getListData();
this.$refs.paging.complete();
}, },
// //
onItemTap(item) { onItemTap(item) {
uni.showToast({ uni.showToast({
title: `点击了:${item.title}`, title: `点击了:${item.agriName}`,
icon: 'none' icon: 'none'
}) })
}, },
getNewSpecialData() {
getNewSpecialData().then(response => {
if (response.code === 200 && response.data) {
this.makeSpecialData(response.data);
}
this.datas = [...this.listData]
})
},
makeSpecialData: function (msgData){
const online = TimeUtil.isLessThanSpecifiedSeconds(msgData.ts,90)?'在线':'离线';
this.listData.push(
{
agriName: "八方南棚",
imei: "A",
temp1: msgData.temp1,
temp2: msgData.temp2,
temp3: msgData.temp3,
temp4: msgData.temp4,
online:online
},
{
agriName: "九方春棚",
imei: "B",
temp1: msgData.temp5,
temp2: msgData.temp6,
temp3: msgData.temp7,
temp4: msgData.temp8,
online:online
},
{
agriName: "十二方棚",
imei: "C",
temp1: msgData.temp9,
temp2: msgData.temp10,
temp3: msgData.temp11,
temp4: msgData.temp12,
online:online
},
)
},
} }
} }
</script> </script>
@ -289,6 +329,7 @@ page {
/* 新增:点击态样式,双端统一 */ /* 新增:点击态样式,双端统一 */
transition: all 0.2s ease; transition: all 0.2s ease;
box-shadow: 8rpx 5rpx 10rpx #999; box-shadow: 8rpx 5rpx 10rpx #999;
pointer-events: auto !important;
} }
.list-item:active { .list-item:active {
background-color: rgba(255, 255, 255, 0.95); background-color: rgba(255, 255, 255, 0.95);
@ -341,13 +382,13 @@ page {
.item-tags { .item-tags {
display: flex; display: flex;
gap: 16rpx; gap: 12rpx;
flex-wrap: wrap; /* 新增:标签过多时换行,避免溢出 */ flex-wrap: wrap; /* 新增:标签过多时换行,避免溢出 */
margin: 14rpx 0; margin: 14rpx 0;
} }
.tag { .tag {
font-size: 22rpx; font-size: 23rpx;
padding: 4rpx 12rpx; padding: 4rpx 12rpx;
border-radius: 4rpx; border-radius: 4rpx;
display: inline-block; /* 修复H5端padding不生效问题 */ display: inline-block; /* 修复H5端padding不生效问题 */
@ -422,6 +463,7 @@ page {
background-color: #fafafa; background-color: #fafafa;
/* 可选:添加透明度 */ /* 可选:添加透明度 */
opacity: 0.7; opacity: 0.7;
pointer-events: none !important; /* 禁止所有交互 */
} }
/* 禁用状态下的子元素也置灰 */ /* 禁用状态下的子元素也置灰 */

105
utils/TimeUtil.js Normal file
View File

@ -0,0 +1,105 @@
/**
* 时间差判断工具类
* 核心功能判断目标时间与当前时间的差值是否小于指定秒数
* 支持的目标时间格式毫秒级时间戳秒级时间戳Date对象合法时间字符串 "2026-02-12 10:00:00"
*/
class TimeUtil {
/**
* 判断目标时间距离当前时间是否小于指定秒数
* @param {String|Number|Date} targetTime 目标时间支持多格式
* @param {Number} seconds 指定秒数需为非负数字
* @returns {Boolean} true=时间差小于指定秒数false=时间差大于/等于指定秒数或参数异常
* @throws {Error} 当秒数参数不合法时抛出明确异常
*/
static isLessThanSpecifiedSeconds(targetTime, seconds) {
// 1. 严格校验秒数参数
if (typeof seconds !== 'number' || isNaN(seconds) || seconds < 0) {
throw new Error(`指定秒数不合法:${seconds},请传入非负数字(如 90、60`);
}
// 2. 转换目标时间为毫秒级时间戳(内部私有方法处理多格式兼容)
const targetTimestamp = this._parseToMillisecondTimestamp(targetTime);
if (targetTimestamp === null) return false; // 时间格式不合法时返回false
// 3. 计算时间差(绝对值:兼容目标时间在当前时间之前/之后的场景)
const nowTimestamp = Date.now();
const timeDiffMs = Math.abs(nowTimestamp - targetTimestamp);
// 4. 转换指定秒数为毫秒,判断是否小于(核心逻辑)
const specifiedMs = seconds * 1000;
return timeDiffMs < specifiedMs;
}
/**
* 私有方法统一转换任意时间格式为毫秒级时间戳
* @param {String|Number|Date} time 待转换的时间
* @returns {Number|null} 合法返回毫秒级时间戳不合法返回null
*/
static _parseToMillisecondTimestamp(time) {
let timestamp;
// 情况1传入的是数字秒级/毫秒级时间戳)
if (typeof time === 'number') {
// 区分秒级戳10位和毫秒级戳13位
timestamp = time.toString().length <= 10 ? time * 1000 : time;
// 校验时间戳有效性
if (isNaN(timestamp) || timestamp < 0) {
console.error(`时间戳不合法:${time},需为非负数字`);
return null;
}
}
// 情况2传入的是Date对象
else if (time instanceof Date) {
timestamp = time.getTime();
if (isNaN(timestamp)) {
console.error(`Date对象不合法${time}`);
return null;
}
}
// 情况3传入的是时间字符串如 "2026-02-12 10:00:00"、"2026/02/12"
else if (typeof time === 'string') {
const date = new Date(time);
timestamp = date.getTime();
if (isNaN(timestamp)) {
console.error(`时间字符串格式不合法:${time},请使用如 "2026-02-12 10:00:00" 的格式`);
return null;
}
}
// 情况4不支持的类型
else {
console.error(`不支持的时间类型:${typeof time}仅支持数字、Date对象、字符串`);
return null;
}
return timestamp;
}
}
export default TimeUtil;
// -------------------------- 测试用例 --------------------------
// // 测试1目标时间是90秒前判断是否小于100秒 → true
// const test1 = TimeUtil.isLessThanSpecifiedSeconds(Date.now() - 90 * 1000, 100);
// console.log('测试1', test1); // true
//
// // 测试2目标时间是100秒前判断是否小于90秒 → false
// const test2 = TimeUtil.isLessThanSpecifiedSeconds(Date.now() - 100 * 1000, 90);
// console.log('测试2', test2); // false
//
// // 测试3传入时间字符串判断是否小于60秒 → false
// const test3Time = "2026-02-12 09:00:00";
// const test3 = TimeUtil.isLessThanSpecifiedSeconds(test3Time, 60);
// console.log('测试3', test3); // false
//
// // 测试4传入秒级时间戳1740000000 → 转换为毫秒级判断是否小于30秒
// const test4 = TimeUtil.isLessThanSpecifiedSeconds(1740000000, 30);
// console.log('测试4', test4); // 取决于当前时间大概率false
//
// // 测试5非法秒数会抛出异常
// try {
// TimeUtil.isLessThanSpecifiedSeconds(Date.now(), -10);
// } catch (e) {
// console.log('测试5异常', e.message); // 指定秒数不合法:-10请传入非负数字
// }