Files
APP/pages/common/index/index.vue
2025-07-19 10:22:48 +08:00

796 lines
17 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.

<template>
<view>
<!-- 使用自定义导航栏 -->
<custom-navbar :title="navTitle" :showBack="false" backgroundColor="#202020" color="#FFFFFF"
rightIcon="/static/images/add.png" @right-click="scan"></custom-navbar>
<view class="device-page" :style="{ paddingTop: navBarHeight + 'px' }">
<!-- handleSend 发送信息 -->
<scroll-view class="tab-bar" scroll-x="true" scroll-with-animation>
<view class="tab-container">
<view v-for="(tab, index) in tabs" :key="index"
:class="['tab-item', activeTab === index ? 'active' : '']" @click="switchTab(tab,index)">
{{tab.typeName}}
</view>
</view>
</scroll-view>
<view class="sendFlex" v-if="activeTab && activeTab.id !== ''">
<view class="callpolice">报警</view>
<view class="Sendmessage" @click="location">位置</view>
<view class="Sendmessage" @click="handleSend">发送信息</view>
</view>
<scroll-view class="device-list" scroll-y @scrolltolower="onScrollToLower" :lower-threshold="100"
style="height:80vh;">
<view v-if="deviceList.length>0">
<uni-swipe-action ref="swipeAction">
<block v-for="(item, index) in deviceList" :key="index" :ref="'swipeItem_' + index">
<uni-swipe-action-item :right-options="Options"
@click="handleSwipeClick($event, item, index)" class="device-card">
<view @click.stop="handleFile(item)">
<view class="device-header">
<view class="deviceIMG">
<image :src="item.devicePic" class="IMG"></image>
</view>
<view class="device-name">
<view>设备:{{item.deviceName}}</view>
<view class="ID">
<view class="ID" v-if="item.communicationMode==0">ID:{{item.deviceImei}}
</view>
<view class="ID" v-else>ID:{{item.deviceMac}}</view>
<view class="onlines" v-if="item.communicationMode==0">在线</view>
<view>电量90%</view>
</view>
</view>
</view>
<view class="" v-if="item.communicationMode==1">
<view class="device-status online">已连接</view>
<view class="device-status unline">未连接</view>
</view>
</view>
<image src="/static/images/cires.png" class="circle"></image>
</uni-swipe-action-item>
</block>
</uni-swipe-action>
<!-- 加载状态提示 -->
<view class="loading-status">
<text v-if="loading">加载中...</text>
<text v-if="finished">没有更多数据了</text>
</view>
</view>
<view v-else class="noDATA">
<view> <uni-icons type="image-filled" size="120" color="rgba(255, 255, 255, 0.9)"></uni-icons>
</view>
暂无数据
</view>
</scroll-view>
</view>
<!-- 删除弹框 -->
<view class="agreement-mask" v-if="deleteShow" @click="closePopup('delete')">
<view class="agreement-popupC" @click.stop>
<view class="popup-content">
<image src="/static/images/dell.png" mode="" class="svg"></image>
<uni-icon class="trash"></uni-icon>
<view>
<view class="popup-Title">确定删除所选设备</view>
</view>
</view>
<!-- 按钮组 -->
<view class="popup-buttons">
<button class="btn agreeBtn" @click="handleBtn">确定</button>
</view>
</view>
</view>
<!-- =========重命名============== -->
<view class="agreement-mask" v-if="RenameModel" @click="closePopup('rename')">
<view class="agreement-popupD" @click.stop>
<view class="popup-content">
<view>
<view class="popup-flex">
<text>设备名称</text>
<input type="text" v-model="deviceName" placeholder="请输入设备名称" class="popup-input"
@click.stop />
</view>
</view>
</view>
<!-- 按钮组 -->
<view class="popup-buttons" style="margin-top:50rpx;">
<button class="btn agreeBtn4" @click="handleBtnName">确定</button>
</view>
</view>
</view>
<!-- 小提示框 -->
<view class="tooltip-box" v-if="showTooltip">
<view class="tooltip-arrow"></view>
<view class="tooltip-content">
<view class="tooltip-item" v-for="(item, index) in menuItems" :key="index"
@click="handleMenuClick(item)">
<image :src="item.icon" class="item-icon" />
<text>{{ item.text }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import {
deviceTypeList,
deviceInfo,
deviceUnbind, //删除设备
deviceReName
} from '@/api/common/index.js'
export default {
data() {
return {
navBarHeight: 70 + uni.getSystemInfoSync().statusBarHeight,
deviceList: [],
tabs: [],
activeTab: 0,
showTooltip: false,
Options: [{
text: '重命名',
style: {
backgroundColor: '#E09319',
borderRadius: '16px',
width: '240rpx', // 初始宽度
},
},
{
text: '删除',
style: {
backgroundColor: 'rgb(240, 60, 60)',
borderRadius: '16px',
width: '240rpx', // 初始宽度
},
},
],
navTitle: "我的设备",
deleteShow: false,
RenameModel: false,
menuItems: [{
text: '扫一扫添加',
icon: '/static/images/scane.png',
action: 'scan'
},
{
text: '蓝牙添加',
icon: '/static/images/bluetooth.png',
action: 'bluetooth'
}
],
page: 1, // 当前页码
size: 10, // 每页条数
total: 0, // 总数据量
loading: false,
finished: false,
deviceId: '',
deviceName: "" //重命名
}
},
methods: {
// 点击弹框外的区域关闭
closePopup(type) {
if (type === 'delete') {
this.deleteShow = false;
uni.showTabBar(); // 显示TabBar
} else if (type === 'rename') {
this.RenameModel = false;
uni.showTabBar(); // 显示TabBar
}
},
// tab导航切换栏
getTab() {
deviceTypeList({}).then((res) => {
if (res.code == 200) {
//console.log("deviceTypeList=" + JSON.stringify(res.data));
this.tabs = [{
id: '',
name: '全部设备',
typeName: '全部设备'
},
...res.data.map(item => ({
id: item.id,
name: item.typeName,
typeName: item.typeName,
communicationMode: item.communicationMode
}))
];
}
})
},
// tab切换页
switchTab(tab, index) {
this.deviceList = [];
this.activeTab = index;
this.page = 1; // 重置页码
this.finished = false; // 重
// 明确传递参数空字符串改为null或undefined
const deviceType = tab.id === '' ? undefined : tab.id;
this.getData(deviceType);
},
// 获取设备列表
getData(deviceType = '') {
if (this.loading || this.finished) return;
this.loading = true;
let data = {
pageNum: this.page,
pageSize: this.size,
deviceType: deviceType // 使用传入的设备类型
}
deviceInfo(data).then((res) => {
if (res.code == 200) {
const newDevices = res.rows.map(device => ({
...device,
showConfirm: false
}));
// 如果是第一页或切换分类,替换数据
this.deviceList = this.page === 1 ? newDevices : [...this.deviceList, ...newDevices];
this.total = res.total;
// 判断是否加载完成
if (res.rows.length < this.size || this.deviceList.length >= this.total) {
this.finished = true;
} else {
this.page++;
}
}
}).finally(() => {
this.loading = false;
});
},
// 滚动触底事件处理
onScrollToLower() {
this.getData();
},
scan() {
this.showTooltip = !this.showTooltip;
},
handleMenuClick(item) {
this.showTooltip = false; // 关闭弹窗
switch (item.action) {
case 'scan':
uni.navigateTo({
url: '/pages/common/scan/scan'
});
break;
case 'bluetooth':
// uni.navigateTo({
// url: 'pages/common/addBLE/AddDevice',
// success:(res)=>{
// res.eventChannel.emit('key', { data: 'data from starter page' })
// },fail: (ex) => {
// console.log("跳转失败了",JSON.stringify(ex));
// }
// });
uni.navigateTo({
url: "/pages/common/addBLE/addEquip"
})
break;
}
},
// 右滑点击事件处理
handleSwipeClick(e, item, index) {
const {
content
} = e
console.log(item, 'eeeee');
switch (e.content.text) {
case '删除':
this.handleDeleteDevice(item, index)
break
case '重命名':
this.handleRenameDevice(item, index)
break
};
},
// 删除设备
handleDeleteDevice(item, index) {
this.deviceId = item
this.deleteShow = true
uni.hideTabBar()
},
// 确认删除
handleBtn() {
uni.showTabBar()
let data = {
id: this.deviceId.id
}
deviceUnbind(this.deviceId.id).then((res) => {
if (res.code == 200) {
uni.showToast({
title: '删除成功',
icon: 'none',
duration: 1000
});
setTimeout(() => {
this.onIntall();
}, 500);
this.deleteShow = false
// 关闭所有滑动项
this.$refs.swipeAction.closeAll();
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 1000
});
}
})
},
// 重命名设备
handleRenameDevice(item, index) {
this.RenameModel = true
uni.hideTabBar()
this.deviceId = item
},
handleBtnName() {
uni.showTabBar()
let data = {
id: this.deviceId.id,
deviceName: this.deviceName
}
deviceReName(data).then((res) => {
if (res.code == 200) {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 1000
});
setTimeout(() => {
this.onIntall();
}, 500);
this.RenameModel = false
this.deviceName = ''
// 关闭所有滑动项
this.$refs.swipeAction.closeAll();
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 1000
});
}
})
},
// 发生短信
handleSend() {
const currentTab = this.tabs[this.activeTab];
const deviceType = currentTab.id || 'all';
console.log(`跳转到发送信息页面\n当前设备类型: ${deviceType}\n设备类型名称: ${currentTab.typeName}`);
uni.navigateTo({
url: '/pages/common/send/index',
events: {
ack: function(data) {}
},
success: (res) => {
res.eventChannel.emit('deviceSend', {
data: deviceType
});
}
})
},
// 位置
location() {
uni.navigateTo({
url: '/pages/common/map/index'
})
},
handleFile(item) {
//console.log('item' + JSON.stringify(item));
// communicationMode 0是4G 1是蓝牙
if (item.communicationMode == 0) {
uni.navigateTo({
url: "/pages/6170/deviceControl/index",
events: {
ack: function(data) {}
},
success: (res) => {
// 页面跳转成功后的回调函数
res.eventChannel.emit('deviceControl', {
data: item
});
}
})
}
if (item.typeName == '6155') {
uni.navigateTo({
url: "/pages/6155/deviceDetail",
events: {
ack: function(data) {
}
},
success: (res) => {
res.eventChannel.emit('detailData', {
data: item
});
}
})
}
},
onIntall() {
this.page = 1;
this.finished = false;
this.getData(this.deviceType); // 重新加载第一页数据
},
},
onLoad() {
this.getTab()
this.onIntall()
// 绑定页面做了监听,新增成功,刷新页面
uni.$on('refreshDeviceList', () => {
this.getTab() // 刷新数据
this.onIntall()
});
},
beforeDestroy() {
// 组件销毁前移除监听器
uni.$off('refreshDeviceList');
},
}
</script>
<style>
/* 页面整体样式 */
.device-page {
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: rgb(18, 18, 18);
padding: 30rpx;
}
.tab-bar {
width: 100%;
color: rgb(255, 255, 255);
white-space: nowrap;
/* 禁止换行 */
overflow: hidden;
}
.tab-container {
display: flex;
/* justify-content: space-around; */
cursor: pointer;
margin-bottom: 40rpx;
/* min-width: 100%; */
/* 最小宽度 */
}
.tab-item {
font-size: 28rpx;
/* min-width: 120rpx; */
padding: 0 30rpx;
/* 左右内边距 */
text-align: center;
/* 文字居中 */
/* 设置最小宽度 */
}
.active {
color: rgba(187, 230, 0, 1);
border-bottom: 6rpx solid rgba(187, 230, 0, 1);
height: 60rpx;
}
.sendFlex {
display: flex;
color: rgba(255, 255, 255, 0.87);
justify-content: flex-end;
cursor: pointer;
margin-bottom: 30rpx;
font-size: 28rpx;
}
.gprs {
width: 28rpx;
height: 35rpx;
position: absolute;
left: 50rpx
}
.Sendmessage {
margin-left: 50rpx;
color: rgba(255, 255, 255, 0.87);
}
.callpolice {
color: rgba(224, 52, 52, 1);
}
/* 设备卡片 */
.device-card {
background-color: rgb(26, 26, 26);
border-radius: 16rpx;
margin-bottom: 20rpx;
box-sizing: border-box;
position: relative;
}
.device-header {
display: flex;
align-items: center;
margin-bottom: 15rpx;
padding: 30rpx 0 10rpx 30rpx;
}
.unline {
color: rgba(255, 255, 255, 0.4);
}
.device-name {
font-size: 32rpx;
color: rgba(255, 255, 255, 0.87);
margin-left: 24rpx;
line-height: 50rpx;
width: 75%;
white-space: nowrap;
}
.ID {
color: rgba(255, 255, 255, 0.6);
font-size: 26rpx;
display: flex;
justify-content: space-between;
position: relative;
}
.device-status {
width: 122rpx;
height: 52rpx;
font-size: 26rpx;
border-radius: 0px 8px 0px 8px;
background-color: rgb(42, 42, 42);
position: absolute;
top: 0rpx;
right: 0rpx;
text-align: center;
line-height: 52rpx;
}
.circle {
width: 8rpx;
height: 40rpx;
position: absolute;
right: 25rpx;
top: 60rpx;
}
.online {
color: rgb(187, 230, 0);
}
.device-id {
font-size: 26rpx;
color: #999;
margin-bottom: 20rpx;
display: block;
}
.device-info {
display: flex;
justify-content: space-evenly;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.87);
position: relative;
padding: 0rpx 0rpx 30rpx 30rpx;
}
.deviceIMG {
width: 100rpx;
height: 100rpx;
border-radius: 16rpx;
position: relative;
background-color: rgba(42, 42, 42, 0.6);
display: flex;
align-items: center;
}
.IMG {
width: 68rpx;
height: 50rpx;
margin-left: 17%;
object-fit: contain;
}
.onlines {
position: relative;
}
.onlines::before {
content: '';
position: absolute;
width: 15rpx;
height: 15rpx;
background: rgb(0, 171, 103);
border-radius: 50%;
top: 20rpx;
left: -20rpx
}
.line {
width: 2rpx;
height: 24rpx;
background: linear-gradient(90deg,
rgba(0, 0, 0, 0) 0%,
rgb(255, 255, 255) 50%,
rgba(255, 255, 255, 0) 100%);
margin-top: 12rpx;
}
.loading-status {
text-align: center;
color: rgba(255, 255, 255, 0.6);
padding: 20rpx;
font-size: 22rpx;
}
.noDATA{
text-align: center;
color: rgba(255, 255, 255, 0.87);
transform: translate(-0%,100%);
}
/* 遮罩层 */
.agreement-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.popup-Title {
color: rgba(255, 255, 255, 0.86);
text-align: center;
padding: 30rpx 0rpx;
}
.popup-buttons {
display: flex;
text-align: center;
}
/* 弹窗主体 */
.agreement-popup {
width: 100%;
height: 50%;
background-color: rgb(42, 42, 42);
border-radius: 60rpx 60rpx 0rpx 0rpx;
padding: 40rpx;
box-sizing: border-box;
position: absolute;
bottom: 0rpx;
}
.agreement-popupC {
width: 60%;
background-color: rgb(42, 42, 42);
border-radius: 40rpx;
padding: 30rpx;
text-align: center;
border: 1px solid rgba(255, 200, 78, 0.3);
}
.agreement-popupD {
width: 70%;
background-color: rgb(42, 42, 42);
border-radius: 40rpx;
padding: 40rpx;
text-align: center;
border: 1px solid rgba(187, 230, 0, 0.3);
}
.popup-flex {
display: flex;
white-space: nowrap;
color: rgba(255, 255, 255, 0.87);
height: 50rpx;
padding: 30rpx;
align-items: center;
}
.popup-input {
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 12rpx;
margin-left: 15rpx;
padding: 10rpx 0rpx;
font-size: 28rpx;
}
.svg {
width: 58rpx;
height: 62rpx;
}
/* 通用按钮样式 */
.btn {
height: 60rpx;
line-height: 60rpx;
border-radius: 40rpx;
font-size: 24rpx;
margin: 10rpx auto;
text-align: center;
}
/* 同意按钮 */
.agreeBtn {
background: #FFC84E;
color: #232323;
border: none;
width: 170rpx !important;
}
.agreeBtn4 {
background: rgba(187, 230, 0, 1);
color: #232323;
border: none;
width: 170rpx !important;
}
.closeBtn {
border: 1px solid rgba(255, 255, 255, 0.2);
background-color: rgba(35, 35, 35, 0.87);
color: rgba(255, 255, 255, 1);
}
/* 提示框样式 */
.tooltip-box {
position: fixed;
right: 18rpx;
top: 140rpx;
/* 根据导航栏高度调整 */
z-index: 9999;
}
.tooltip-arrow {
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-bottom: 8px solid #333;
position: absolute;
right: 12px;
top: -8px;
}
.tooltip-content {
border-radius: 8rpx;
backdrop-filter: blur(14px);
background: rgba(58, 58, 58, 1);
padding: 10px 0;
min-width: 120px;
}
.tooltip-item {
padding: 8px 16px;
display: flex;
align-items: center;
color: #fff;
}
.tooltip-item text {
margin-left: 8px;
font-size: 14px;
}
.item-icon {
width: 16px;
height: 16px;
}
</style>