560 lines
14 KiB
Vue
560 lines
14 KiB
Vue
|
<template>
|
|||
|
<view class="device-group-wrap">
|
|||
|
<view class="search-wrap">
|
|||
|
<div class="left-wrap">
|
|||
|
<u-search v-model="queryParams.groupName" shape="square" @search="handleSearch" @custom="handleSearch"
|
|||
|
:inputStyle="{ height: '64rpx' }" :placeholder="$tt('group.inputContent')"
|
|||
|
:actionText="$tt('timing.search')"
|
|||
|
:actionStyle="{ backgroundColor: '#398ade', color: '#fff', padding: '0 12rpx', borderRadius: '6rpx', height: '64rpx', lineHeight: '64rpx' }"></u-search>
|
|||
|
</div>
|
|||
|
<div class="right-wrap">
|
|||
|
<u-button @click="handleAddGrup()" type="success" :text="$tt('common.add')" icon="plus"
|
|||
|
:customStyle="{ width: '120rpx', height: '64rpx' }" size="small"></u-button>
|
|||
|
</div>
|
|||
|
</view>
|
|||
|
<view class="card-wrap" v-for="(item, index) in dataList" :key="index" @click="handleEdit(item)">
|
|||
|
<u-row gutter="10" customStyle="margin:0;">
|
|||
|
<u-col :span="6"
|
|||
|
customStyle="background-color:#3fd1ad; padding:40rpx; border-top-left-radius:10rpx; border-bottom-left-radius:10rpx;">
|
|||
|
<u--text prefixIcon="grid" iconStyle="color:#fff; font-size:36rpx; margin-right:8rpx;" bold
|
|||
|
lines="1" :text="item.groupName" customStyle="color:#fff; font-size: 32rpx;"></u--text>
|
|||
|
</u-col>
|
|||
|
<u-col :span="6">
|
|||
|
<view class="button-group" @click.stop>
|
|||
|
<u-button type="success" @click="handleAddDevice(item)" size="small"
|
|||
|
customStyle="width:160rpx; height: 70rpx;">{{ $tt('group.add') }}</u-button>
|
|||
|
<u-button type="info" @click="showDeviceSelector(item.groupId)" size="small"
|
|||
|
customStyle="width:160rpx; height: 70rpx;">区域控制</u-button>
|
|||
|
</view>
|
|||
|
</u-col>
|
|||
|
</u-row>
|
|||
|
</view>
|
|||
|
|
|||
|
<!-- 区域控制弹窗 -->
|
|||
|
<u-popup :show="showDevicePopup" mode="center" @close="closeDevicePopup" round="10">
|
|||
|
<view class="area-control-popup">
|
|||
|
<view class="popup-header">
|
|||
|
<text class="popup-title">区域控制</text>
|
|||
|
<u-icon name="close" size="20" @click="closeDevicePopup"></u-icon>
|
|||
|
</view>
|
|||
|
|
|||
|
<view class="popup-content">
|
|||
|
<!-- 设备类型选择 -->
|
|||
|
<u-tabs :list="tabsList" :current="Number(activeMenu)" @click="handleMenuSelect"></u-tabs>
|
|||
|
|
|||
|
<!-- 安全王配置 -->
|
|||
|
<view v-if="activeMenu === 0" class="security-king">
|
|||
|
<u-form :model="formData" labelPosition="left">
|
|||
|
<u-form-item label="参数上传时间间隔">
|
|||
|
<u-input v-model="paramUploadInterval" placeholder="请输入参数上传时间间隔" />
|
|||
|
</u-form-item>
|
|||
|
<!-- <u-form-item label="接地电阻测试周期">
|
|||
|
<u-input v-model="groundResistanceTestInterval" placeholder="请输入接地电阻测试周期" />
|
|||
|
</u-form-item> -->
|
|||
|
</u-form>
|
|||
|
<view class="button-area">
|
|||
|
<u-button type="success" @click="submitFormreglin(Security_King)">发送</u-button>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
|
|||
|
<!-- 单灯控配置 -->
|
|||
|
<view v-if="activeMenu === 1" class="light-control">
|
|||
|
<view class="time-select">
|
|||
|
<text class="time-label">时间:</text>
|
|||
|
<u-button @click="showTimePicker = true" type="info" size="small">
|
|||
|
{{ startTime || '请选择开始时间' }}
|
|||
|
</u-button>
|
|||
|
</view>
|
|||
|
|
|||
|
<u-datetime-picker :show="showTimePicker" v-model="startTime" mode="time" @confirm="timeConfirm"
|
|||
|
@cancel="timeCancel" :minuteStep="1" format="HH:mm"></u-datetime-picker>
|
|||
|
|
|||
|
<view class="light-table">
|
|||
|
<view class="table-header">
|
|||
|
<text style="width: 25%;">阶段</text>
|
|||
|
<text style="width: 37.5%;">时长(分钟)</text>
|
|||
|
<text style="width: 37.5%;">亮度(%)</text>
|
|||
|
</view>
|
|||
|
<view class="table-body">
|
|||
|
<view class="table-row" v-for="(row, index) in tableData" :key="index">
|
|||
|
<text style="width: 25%;">{{ row.segment }}</text>
|
|||
|
<view style="width: 37.5%;">
|
|||
|
<u-input v-model="row.duration" placeholder="输入时长" type="number" />
|
|||
|
</view>
|
|||
|
<view style="width: 37.5%;">
|
|||
|
<u-input v-model="row.brightness" placeholder="输入亮度" type="number" />
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
|
|||
|
<view class="button-area">
|
|||
|
<u-button type="success" @click="submitlightcontrol(Single_lightcontrol)">发送配置</u-button>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</u-popup>
|
|||
|
|
|||
|
<u-empty mode="list" :show="total === 0" marginTop="30"></u-empty>
|
|||
|
<u-loadmore :status="status" v-if="total > queryParams.pageSize" marginTop="20"
|
|||
|
:nomoreText="$tt('group.nomore')" />
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
import {
|
|||
|
getGroupList
|
|||
|
} from '@/apis/modules/group';
|
|||
|
import {
|
|||
|
listDeviceShort
|
|||
|
} from '@/apis/modules/device.js';
|
|||
|
|
|||
|
export default {
|
|||
|
data() {
|
|||
|
return {
|
|||
|
status: 'nomore', // 加载更多
|
|||
|
dataList: [], // 列表数据
|
|||
|
total: 0, // 总条数
|
|||
|
queryParams: {
|
|||
|
pageNum: 1,
|
|||
|
pageSize: 10,
|
|||
|
userId: 0,
|
|||
|
groupName: null,
|
|||
|
},
|
|||
|
showDevicePopup: false,
|
|||
|
selectedDevices: [],
|
|||
|
currentGroup: null,
|
|||
|
deviceOptions: [
|
|||
|
{ deviceName: '安全王' },
|
|||
|
{ deviceName: '双灯控' }
|
|||
|
],
|
|||
|
tabsList: [
|
|||
|
{ name: '安全王' },
|
|||
|
{ name: '单灯控' }
|
|||
|
],
|
|||
|
activeMenu: 0,
|
|||
|
showTimePicker: false,
|
|||
|
startTime: '',
|
|||
|
paramUploadInterval: '',
|
|||
|
groundResistanceTestInterval: '',
|
|||
|
tableData: [
|
|||
|
{ segment: '阶段1', duration: '', brightness: '' },
|
|||
|
{ segment: '阶段2', duration: '', brightness: '' },
|
|||
|
{ segment: '阶段3', duration: '', brightness: '' }
|
|||
|
],
|
|||
|
Security_King: [],
|
|||
|
Single_lightcontrol: [],
|
|||
|
formData: {}, // 添加表单数据对象
|
|||
|
timeParams: {
|
|||
|
hour: true,
|
|||
|
minute: true,
|
|||
|
second: false
|
|||
|
}
|
|||
|
};
|
|||
|
},
|
|||
|
onLoad() {
|
|||
|
this.getToken();
|
|||
|
if (this.token != '' && this.token != null) {
|
|||
|
this.connectMqtt();
|
|||
|
}
|
|||
|
this.queryParams.userId = this.profile.userId;
|
|||
|
this.getList();
|
|||
|
},
|
|||
|
onShow() {
|
|||
|
let operate = getApp().globalData.operate;
|
|||
|
if (operate && operate == 'operate') {
|
|||
|
this.getList();
|
|||
|
// 置空 operate
|
|||
|
getApp().globalData.operate = "";
|
|||
|
}
|
|||
|
|
|||
|
},
|
|||
|
methods: {
|
|||
|
getToken() {
|
|||
|
// 本地缓存获取token
|
|||
|
this.token = uni.getStorageSync('token');
|
|||
|
// vuex存储token
|
|||
|
uni.$u.vuex('vuex_token', this.token);
|
|||
|
},
|
|||
|
// 连接Mqtt消息服务器
|
|||
|
async connectMqtt() {
|
|||
|
if (this.$mqttTool.client == null) {
|
|||
|
await this.$mqttTool.connect(this.vuex_token);
|
|||
|
}
|
|||
|
this.mqttCallback();
|
|||
|
this.getDatas();
|
|||
|
},
|
|||
|
// 获取列表数据
|
|||
|
getList() {
|
|||
|
getGroupList(this.queryParams).then(response => {
|
|||
|
if (this.queryParams.pageNum == 1) {
|
|||
|
this.dataList = response.rows;
|
|||
|
} else {
|
|||
|
this.dataList = this.dataList.concat(response.rows);
|
|||
|
}
|
|||
|
this.total = response.total;
|
|||
|
uni.stopPullDownRefresh();
|
|||
|
});
|
|||
|
},
|
|||
|
// 搜索
|
|||
|
handleSearch(value) {
|
|||
|
this.dataList = [];
|
|||
|
this.queryParams.pageNum = 1;
|
|||
|
this.getList(true);
|
|||
|
},
|
|||
|
// 新增
|
|||
|
handleAddGrup() {
|
|||
|
uni.navigateTo({
|
|||
|
url: '/pagesB/user/deviceGroup/detail'
|
|||
|
});
|
|||
|
},
|
|||
|
// 编辑
|
|||
|
handleEdit(item) {
|
|||
|
uni.navigateTo({
|
|||
|
url: '/pagesB/user/deviceGroup/detail?groupId=' + item.groupId
|
|||
|
});
|
|||
|
},
|
|||
|
// 选择分组设备
|
|||
|
handleAddDevice(item) {
|
|||
|
uni.navigateTo({
|
|||
|
url: '/pagesB/user/deviceGroup/devices?groupId=' + item.groupId + '&groupUserId=' +
|
|||
|
item.userId
|
|||
|
});
|
|||
|
},
|
|||
|
// 下拉刷新
|
|||
|
onPullDownRefresh() {
|
|||
|
this.dataList = [];
|
|||
|
this.queryParams.pageNum = 1;
|
|||
|
this.getList(); // Http获取列表
|
|||
|
},
|
|||
|
// 上拉加载
|
|||
|
onReachBottom() {
|
|||
|
this.status = 'loading';
|
|||
|
this.queryParams.pageNum = this.queryParams.pageNum + 1;
|
|||
|
if ((this.queryParams.pageNum - 1) * this.queryParams.pageSize > this.total) {
|
|||
|
this.status = 'nomore';
|
|||
|
} else {
|
|||
|
this.getList();
|
|||
|
this.status = 'loading';
|
|||
|
}
|
|||
|
},
|
|||
|
// 显示设备选择弹窗
|
|||
|
showDeviceSelector(group) {
|
|||
|
this.currentGroup = group;
|
|||
|
console.log('当前分组:', JSON.stringify(this.currentGroup));
|
|||
|
this.showDevicePopup = true;
|
|||
|
// 这里可以添加获取可选设备列表的接口调用
|
|||
|
this.getAvailableDevices();
|
|||
|
},
|
|||
|
|
|||
|
// 获取可选设备列表
|
|||
|
getAvailableDevices() {
|
|||
|
const GroupListqueryParams = {
|
|||
|
pageNum: 1,
|
|||
|
pageSize: 12,
|
|||
|
showChild: true,
|
|||
|
groupId: this.currentGroup,
|
|||
|
};
|
|||
|
listDeviceShort(GroupListqueryParams).then((response) => {
|
|||
|
this.deviceList = response.rows;
|
|||
|
this.total = response.total;
|
|||
|
|
|||
|
// 按 productId 分成两个数组
|
|||
|
const lightcontrol = this.deviceList.filter(device => device.productId === 138);
|
|||
|
const Security = this.deviceList.filter(device => device.productId === 136);
|
|||
|
this.Security_King = Security;
|
|||
|
this.Single_lightcontrol = lightcontrol;
|
|||
|
console.log("安全王设备:", JSON.stringify(this.Security_King));
|
|||
|
console.log("单灯控设备:", JSON.stringify(this.Single_lightcontrol));
|
|||
|
});
|
|||
|
},
|
|||
|
|
|||
|
// 关闭设备选择弹窗
|
|||
|
closeDevicePopup() {
|
|||
|
this.showDevicePopup = false;
|
|||
|
this.selectedDevices = [];
|
|||
|
this.currentGroup = null;
|
|||
|
},
|
|||
|
|
|||
|
// 确认设备选择
|
|||
|
confirmDeviceSelection() {
|
|||
|
if (this.selectedDevices.length === 0) {
|
|||
|
uni.showToast({
|
|||
|
title: '请选择设备',
|
|||
|
icon: 'none'
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 这里添加关联设备的逻辑
|
|||
|
console.log('选中的设备:', this.selectedDevices);
|
|||
|
console.log('当前分组:', this.currentGroup);
|
|||
|
|
|||
|
// 示例:调用关联设备的API
|
|||
|
// linkDevicesToGroup({
|
|||
|
// groupId: this.currentGroup.groupId,
|
|||
|
// deviceIds: this.selectedDevices
|
|||
|
// }).then(res => {
|
|||
|
// if (res.code === 200) {
|
|||
|
// uni.showToast({
|
|||
|
// title: '关联成功',
|
|||
|
// icon: 'success'
|
|||
|
// });
|
|||
|
// this.closeDevicePopup();
|
|||
|
// this.getList(); // 刷新列表
|
|||
|
// }
|
|||
|
// });
|
|||
|
|
|||
|
// 临时显示成功提示
|
|||
|
uni.showToast({
|
|||
|
title: '关联成功',
|
|||
|
icon: 'success'
|
|||
|
});
|
|||
|
this.closeDevicePopup();
|
|||
|
},
|
|||
|
|
|||
|
|
|||
|
// 连接Mqtt消息服务器
|
|||
|
async connectMqtt() {
|
|||
|
if (this.$mqttTool.client == null) {
|
|||
|
await this.$mqttTool.connect(this.vuex_token);
|
|||
|
}
|
|||
|
},
|
|||
|
// 订阅消息
|
|||
|
mqttSubscribe(list) {
|
|||
|
// 订阅当前页面设备状态和实时监测
|
|||
|
let topics = [];
|
|||
|
for (let i = 0; i < list.length; i++) {
|
|||
|
let topicStatus = '/' + list[i].productId + '/' + list[i].serialNumber + '/status/post';
|
|||
|
topics.push(topicStatus);
|
|||
|
}
|
|||
|
this.$mqttTool.subscribe(topics);
|
|||
|
},
|
|||
|
// 提交安全王配置
|
|||
|
submitFormreglin(devicelist) {
|
|||
|
let message = [{
|
|||
|
"id": "report_time_min",
|
|||
|
"remark": "",
|
|||
|
"value": this.paramUploadInterval || "0"
|
|||
|
}];
|
|||
|
|
|||
|
console.log("安全王设置下发数据:", JSON.stringify(message));
|
|||
|
this.AreamqttSubscribe(devicelist, JSON.stringify(message));
|
|||
|
},
|
|||
|
|
|||
|
// 提交单灯控配置
|
|||
|
submitlightcontrol(devicelist) {
|
|||
|
console.log('当前时间值:', this.startTime);
|
|||
|
|
|||
|
// 默认值
|
|||
|
let startHour = '00';
|
|||
|
let startMinute = '00';
|
|||
|
|
|||
|
// 解析时间字符串
|
|||
|
if (this.startTime && typeof this.startTime === 'string') {
|
|||
|
const timeParts = this.startTime.split(':');
|
|||
|
if (timeParts.length === 2) {
|
|||
|
startHour = String(timeParts[0]).padStart(2, '0');
|
|||
|
startMinute = String(timeParts[1]).padStart(2, '0');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
let message = [
|
|||
|
{
|
|||
|
"id": "S1_startH",
|
|||
|
"remark": "",
|
|||
|
"value": startHour
|
|||
|
},
|
|||
|
{
|
|||
|
"id": "S1_startM",
|
|||
|
"remark": "",
|
|||
|
"value": startMinute
|
|||
|
},
|
|||
|
{
|
|||
|
"id": "S1_seg1M",
|
|||
|
"remark": "",
|
|||
|
"value": this.tableData[0].duration || "0"
|
|||
|
},
|
|||
|
{
|
|||
|
"id": "S1_seg1B",
|
|||
|
"remark": "",
|
|||
|
"value": this.tableData[0].brightness || "0"
|
|||
|
},
|
|||
|
{
|
|||
|
"id": "S1_seg2M",
|
|||
|
"remark": "",
|
|||
|
"value": this.tableData[1].duration || "0"
|
|||
|
},
|
|||
|
{
|
|||
|
"id": "S1_seg2B",
|
|||
|
"remark": "",
|
|||
|
"value": this.tableData[1].brightness || "0"
|
|||
|
},
|
|||
|
{
|
|||
|
"id": "S1_seg3M",
|
|||
|
"remark": "",
|
|||
|
"value": this.tableData[2].duration || "0"
|
|||
|
},
|
|||
|
{
|
|||
|
"id": "S1_seg3B",
|
|||
|
"remark": "",
|
|||
|
"value": this.tableData[2].brightness || "0"
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
console.log("单灯控设置下发数据:", JSON.stringify(message));
|
|||
|
this.AreamqttSubscribe(devicelist, JSON.stringify(message));
|
|||
|
},
|
|||
|
|
|||
|
// MQTT订阅和发布
|
|||
|
AreamqttSubscribe(list, message) {
|
|||
|
let topics = [];
|
|||
|
for (let i = 0; i < list.length; i++) {
|
|||
|
let topicService = '/' + list[i].productId + '/' + list[i].serialNumber + '/function/get';
|
|||
|
topics.push(topicService);
|
|||
|
|
|||
|
this.$mqttTool.subscribe([topicService]);
|
|||
|
this.$mqttTool.publish(topicService, message, list[i].serialNumber)
|
|||
|
.then((res) => {
|
|||
|
console.log(res);
|
|||
|
})
|
|||
|
.catch((err) => {
|
|||
|
console.log(err);
|
|||
|
});
|
|||
|
}
|
|||
|
console.log("Subscribe Topics:", JSON.stringify(topics));
|
|||
|
uni.showToast({
|
|||
|
title: '指令下发成功',
|
|||
|
icon: 'success'
|
|||
|
});
|
|||
|
},
|
|||
|
|
|||
|
timeConfirm(e) {
|
|||
|
console.log('选择的时间:', e);
|
|||
|
// 直接保存时分
|
|||
|
this.startTime = {
|
|||
|
hour: e, // 直接保存选择的时间值
|
|||
|
minute: e
|
|||
|
};
|
|||
|
this.showTimePicker = false;
|
|||
|
},
|
|||
|
|
|||
|
timeCancel() {
|
|||
|
this.showTimePicker = false;
|
|||
|
},
|
|||
|
|
|||
|
handleMenuSelect(item) {
|
|||
|
this.activeMenu = Number(item.index);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss">
|
|||
|
page {
|
|||
|
background: #eef3f7;
|
|||
|
}
|
|||
|
|
|||
|
.device-group-wrap {
|
|||
|
.search-wrap {
|
|||
|
padding: 20rpx;
|
|||
|
background: #ffffff;
|
|||
|
display: flex;
|
|||
|
flex-direction: row;
|
|||
|
align-items: center;
|
|||
|
|
|||
|
.left-wrap {
|
|||
|
flex: 1;
|
|||
|
}
|
|||
|
|
|||
|
.right-wrap {
|
|||
|
margin-left: 20rpx;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.card-wrap {
|
|||
|
box-shadow: 0 2rpx 0 0 rgba(0, 0, 0, 0.1);
|
|||
|
border-radius: 10rpx;
|
|||
|
margin: 20rpx;
|
|||
|
background-color: #ffffff;
|
|||
|
min-height: 120rpx;
|
|||
|
cursor: pointer;
|
|||
|
transition: all 0.3s;
|
|||
|
|
|||
|
&:active {
|
|||
|
opacity: 0.8;
|
|||
|
}
|
|||
|
|
|||
|
.button-group {
|
|||
|
display: flex;
|
|||
|
gap: 10rpx;
|
|||
|
padding: 10rpx;
|
|||
|
justify-content: center;
|
|||
|
align-items: center;
|
|||
|
height: 100%;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.area-control-popup {
|
|||
|
width: 90vw;
|
|||
|
max-height: 80vh;
|
|||
|
background-color: #fff;
|
|||
|
border-radius: 20rpx;
|
|||
|
|
|||
|
.popup-header {
|
|||
|
display: flex;
|
|||
|
justify-content: space-between;
|
|||
|
align-items: center;
|
|||
|
padding: 30rpx;
|
|||
|
border-bottom: 1rpx solid #eee;
|
|||
|
|
|||
|
.popup-title {
|
|||
|
font-size: 32rpx;
|
|||
|
font-weight: bold;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.popup-content {
|
|||
|
padding: 20rpx;
|
|||
|
|
|||
|
.time-select {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
margin: 20rpx 0;
|
|||
|
|
|||
|
.time-label {
|
|||
|
margin-right: 10rpx;
|
|||
|
font-size: 28rpx;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.light-table {
|
|||
|
border: 1rpx solid #eee;
|
|||
|
border-radius: 10rpx;
|
|||
|
margin: 20rpx 0;
|
|||
|
|
|||
|
.table-header {
|
|||
|
display: flex;
|
|||
|
background-color: #f5f7fa;
|
|||
|
padding: 20rpx;
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
|
|||
|
.table-row {
|
|||
|
display: flex;
|
|||
|
padding: 20rpx;
|
|||
|
border-top: 1rpx solid #eee;
|
|||
|
align-items: center;
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.button-area {
|
|||
|
margin-top: 30rpx;
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|