Files
APP/pages/6170/callPolice/index.vue
2026-02-05 11:40:56 +08:00

497 lines
12 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 class="container">
<!-- 设备列表 -->
<view class="allSelect" @click="selectAll"> 全选</view>
<scroll-view class="device-list" scroll-y>
<view class="device-card" v-for="(item, index) in deviceList" :key="index"
@click="item.onlineStatus === 1 ? toggleSelect(index) : null">
<!-- 复选框 -->
<view class="checkbox" :class="{ checked: item.checked, disabled: item.onlineStatus !== 1 }">
<uni-icons v-if="item.checked" type="checkmarkempty" size="18" color="rgb(0, 0, 0)"></uni-icons>
</view>
<!-- 设备信息 -->
<view class="device-content">
<view class="device-header">
<view class="deviceIMG">
<image :src="item.devicePic" class="IMG" mode="aspectFit"></image>
</view>
<view class="device-name">
<view>设备:{{ item.deviceName }}</view>
<view class="ID">
<view class="ID">ID:{{ item.deviceImei }}</view>
<view class="onlines" v-if="item.onlineStatus == 1">在线</view>
<!-- 离线状态 -->
<view class="unlines" v-if="item.onlineStatus == 0">离线</view>
<view>电量{{ item.battery || '0' }}%</view>
</view>
</view>
</view>
</view>
</view>
<view class="editInfmation">
<button class="login-btn qz" @click="forceAlarm">强制报警</button>
<button class="login-btn jc" @click="cancelAlarm">解除报警</button>
</view>
</scroll-view>
<!-- 强制报警提示弹框 -->
<CustomPopup v-if="popupType === 'force'" :show="showPopupFlag" popupBorder="1rpx solid rgba(224, 52, 52, 0.3)"
:message="popupMessage" icon="/static/images/6170/bj.png" :confirm-text="popupConfirmText"
:show-cancel="false" @close="onclosePopup" @confirm="onPopupConfirm" confirmBtnBg="rgba(224, 52, 52, 1)"
confirmBtnColor="#fff" />
<!-- 解除报警 -->
<CustomPopup v-if="popupType === 'cancel'" :show="showPopupFlag" popupBorder="1rpx solid rgba(224, 52, 52, 0.3)"
:message="popupMessage" icon="/static/images/6170/svg.png" :confirm-text="popupConfirmText"
:show-cancel="false" @close="onclosePopup" @confirm="onPopupConfirm" confirmBtnBg="rgba(224, 52, 52, 1)"
confirmBtnColor="#fff" />
</view>
</template>
<script>
import CustomPopup from '@/components/CustomPopup/CustomPopup.vue'
import {
generateShortId,
getdeviceSTatus
} from '@/utils/function.js';
import {
deviceInfo,
} from '@/api/common/index.js'
// 1. 导入所有需要的报警接口
import {
deviceSendAlarmMessage, //6170对应类型接口
deviceDefaultAlarm
} from '@/api/6170/callPolice.js'
import {
deviceForceAlarmActivation
} from '@/api/100J/HBY100-J.js'
// BJQ100J 对应的接口
import {
deviceRealTimeStatus //设备状态
} from '@/api/6170/deviceControl.js'
export default {
components: {
CustomPopup
},
data() {
return {
deviceList: [],
showPopupFlag: false,
popupTitle: '',
popupMessage: '确认要对所选设备开启强制报警?',
popupConfirmText: '确认',
popupType: 'force', // 'force' or 'cancel'
pendingAlarmAction: '',
sendInfo: '',
// 2. 核心typeName 与接口的映射表
alarmApiMapping: {
'HBY100-J': { //100J类型
sendApi: deviceForceAlarmActivation,
statusTypeName: 'FunctionAccessBatchStatusRule_BJQ100J'
},
'BJQ6170': { //6170类型
sendApi: deviceSendAlarmMessage,
statusTypeName: 'FunctionAccessBatchStatusRule_BJQ200J'
}
},
loading: false,
total: 0
}
},
computed: {
selectedDeviceIds() {
return this.deviceList.filter(item => item.checked).map(item => item.id);
},
// 自动匹配当前typeName对应的接口配置
currentApiConfig() {
const currentTypeName = this.sendInfo.typeName || '';
// 匹配到则用对应配置,匹配不到用默认配置
return this.alarmApiMapping[currentTypeName] || {
sendApi: deviceDefaultAlarm,
statusTypeName: 'FunctionAccessBatchStatusRule_Default'
};
}
},
methods: {
onclosePopup() {
this.showPopupFlag = false
},
toggleSelect(index) {
this.deviceList[index].checked = !this.deviceList[index].checked
this.$forceUpdate()
},
// 全选/取消全选
selectAll() {
console.log('123');
// 仅对在线设备进行全选/取消
const allSelected = this.deviceList.every(item => item.onlineStatus === 1 && item.checked);
this.deviceList.forEach(item => {
// 离线设备不修改checked状态
if (item.onlineStatus === 1) {
item.checked = !allSelected;
}
});
this.$forceUpdate();
},
// 获取设备列表
getData(deviceType) {
console.log(deviceType, 'deviceTypedeviceType');
this.loading = true;
let data = {
pageNum: 1,
pageSize: 50,
deviceType: deviceType
}
deviceInfo(data).then((res) => {
if (res.code == 200) {
const newDevices = res.rows.map(device => ({
...device,
showConfirm: false,
checked: false
}));
this.total = res.total;
this.deviceList = newDevices
}
}).finally(() => {
this.loading = false;
});
},
// 强制报警
forceAlarm() {
const selectedDevices = this.deviceList.filter(item => item.checked)
if (selectedDevices.length === 0) {
uni.showToast({
title: '请选择一个在线设备',
icon: 'none'
});
return;
}
this.popupType = 'force';
this.popupMessage = '确认要对所选设备开启强制报警?';
this.showPopupFlag = true;
this.pendingAlarmAction = 1
},
// 解除报警
cancelAlarm() {
const selectedDevices = this.deviceList.filter(item => item.checked);
if (selectedDevices.length === 0) {
uni.showToast({
title: '请选择一个在线设备',
icon: 'none'
});
return;
}
this.popupType = 'cancel';
this.popupMessage = '确认要解除所选设备的报警状态?';
this.showPopupFlag = true;
this.pendingAlarmAction = 0
},
//动态调用对应接口
async sendAlarmCommand() {
const selectedDevices = this.deviceList.filter(item => item.checked);
const deviceIds = selectedDevices.map(item => item.id);
const deviceImeiList = selectedDevices.map(item => item.deviceImei);
const isAlarming = this.pendingAlarmAction == 1;
if (selectedDevices.length === 0) {
uni.showToast({
title: '请选择在线设备',
icon: 'none'
});
return;
}
try {
uni.showLoading({
title: isAlarming ? '设备报警中...' : '解除报警中...',
mask: true
});
// 获取当前typeName对应的接口和参数配置
const {
sendApi,
statusTypeName
} = this.currentApiConfig;
// 准备请求数据
// const batchId = generateShortId();
const requestData = {
deviceIds: deviceIds,
typeName: this.sendInfo.typeName,
deviceImeiList: deviceImeiList,
// batchId: batchId,
voiceStrobeAlarm: this.pendingAlarmAction == 1 ? '1' : '0'
};
// 动态调用匹配的接口
const registerRes = await sendApi(requestData);
if (registerRes.code == 200) {
uni.showToast({
title: isAlarming ? '强制报警开启成功' : '报警已解除',
icon: 'success'
});
this.showPopupFlag = false
uni.$emit('deviceStatusUpdate', {});
setTimeout(() => {
uni.navigateBack()
}, 500)
} else {
uni.showToast({
title: registerRes.msg || '状态查询失败',
icon: 'none'
});
}
} catch (error) {
console.error('报警操作异常:', error);
uni.showToast({
title: '网络异常,请重试',
icon: 'none'
});
} finally {
uni.hideLoading();
}
},
// 点击确认状态
onPopupConfirm() {
this.sendAlarmCommand(this.popupType);
},
},
onLoad(options) {
const eventChannel = this.getOpenerEventChannel();
// 监听 'deviceSend' 事件,获取传过来的数据
eventChannel.on('devicePolice', (data) => {
this.getData(data.data.id)
this.sendInfo = data.data
});
eventChannel.emit('ack', {})
},
}
</script>
<style scoped>
.container {
min-height: 100vh;
background-color: rgb(18, 18, 18);
box-sizing: border-box;
overflow-x: hidden;
}
.allSelect {
color: rgba(255, 255, 255, 0.87);
float: right;
padding: 25rpx;
cursor: pointer;
}
.device-list {
flex: 1;
padding: 0rpx 20rpx;
clear: both;
}
.device-card {
position: relative;
display: flex;
align-items: center;
width: 95%;
margin-bottom: 20rpx;
}
.checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid rgba(255, 255, 255, 0.5);
margin-right: 20rpx;
border-radius: 4rpx;
display: flex;
align-items: center;
justify-content: center;
}
.checkbox.checked {
background: rgba(224, 52, 52, 1);
border-color: rgba(224, 52, 52, 1);
}
.device-content {
background-color: rgb(26, 26, 26);
border-radius: 16rpx;
position: relative;
/* display: flex; */
align-items: center;
padding: 20rpx;
width: 95%;
}
.device-header {
display: flex;
align-items: center;
margin-bottom: 15rpx;
}
.device-name {
font-size: 32rpx;
color: rgba(255, 255, 255, 0.87);
margin-left: 12rpx;
line-height: 50rpx;
width: 83%;
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;
}
.online {
color: rgb(187, 230, 0);
}
.unline {
color: rgba(255, 255, 255, 0.4);
}
.device-info {
display: flex;
justify-content: space-evenly;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.87);
padding-top: 10rpx;
position: relative;
}
.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%;
}
.onlines {
position: relative;
}
.onlines::before {
content: '';
position: absolute;
width: 15rpx;
height: 15rpx;
background: rgb(0, 171, 103);
border-radius: 50%;
top: 20rpx;
left: -20rpx
}
.unlines {
position: relative;
}
.unlines::before {
content: '';
position: absolute;
width: 15rpx;
height: 15rpx;
background: rgba(255, 255, 255, 0.4);
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;
}
.ql-editor {
color: rgba(255, 255, 255, 0.6);
font-size: 30rpx;
}
.ql-input {
width: 95.9%;
height: 200rpx;
margin-top: 30rpx;
box-sizing: border-box;
padding: 30rpx;
border-radius: 16rpx;
background: rgb(26, 26, 26);
}
.textarea {
color: rgba(255, 255, 255, 0.8);
background: rgba(42, 42, 42, 1);
border-radius: 16rpx;
padding: 10rpx;
height: 150rpx;
}
.editInfmation {
display: flex;
padding: 20rpx;
border-radius: 40rpx 40rpx 0px 0px;
width: 96%;
position: fixed;
bottom: 50rpx;
box-sizing: border-box;
}
.login-btn {
margin-top: 30rpx;
color: rgb(35, 35, 35);
border-radius: 50rpx;
width: 40%;
color: #fff;
height: 88rpx;
font-size: 30rpx;
line-height: 88rpx;
}
.qz {
background: rgba(224, 52, 52, 1);
}
.jc {
border: 1px solid rgba(255, 255, 255, 0.87);
background: rgba(18, 18, 18, 1);
}
.checkbox.disabled {
opacity: 0.5;
background-color: rgba(255, 255, 255, 0.1) !important;
border-color: rgba(255, 255, 255, 0.2) !important;
pointer-events: none;
/* 阻止点击事件 */
}
/* 可选:离线设备的卡片整体置灰 */
.device-card[data-offline="true"] {
opacity: 0.6;
}
</style>