forked from dyf/dyf-vue-ui
100j控制面包页面开发
This commit is contained in:
@ -6,8 +6,8 @@ VITE_APP_ENV = 'development'
|
|||||||
|
|
||||||
# 开发环境
|
# 开发环境
|
||||||
# VITE_APP_BASE_API = 'http://139.224.253.23:8000'
|
# VITE_APP_BASE_API = 'http://139.224.253.23:8000'
|
||||||
# VITE_APP_BASE_API = 'https://www.cnxhyc.com/jq'
|
VITE_APP_BASE_API = 'https://www.cnxhyc.com/jq'
|
||||||
VITE_APP_BASE_API = 'http://192.168.110.57:8000'
|
#VITE_APP_BASE_API = 'http://192.168.110.57:8000'
|
||||||
#代永飞接口
|
#代永飞接口
|
||||||
# VITE_APP_BASE_API = 'http://457102h2d6.qicp.vip:24689'
|
# VITE_APP_BASE_API = 'http://457102h2d6.qicp.vip:24689'
|
||||||
|
|
||||||
|
|||||||
51
src/api/controlCenter/controlPanel/100J.ts
Normal file
51
src/api/controlCenter/controlPanel/100J.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 详情信息
|
||||||
|
export const deviceDeatil = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/hby100j/device/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 灯光模式
|
||||||
|
function lightModeSettings (data: any) {
|
||||||
|
return request({
|
||||||
|
url: `/app/hby100j/device/lightAdjustment`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//频率调节
|
||||||
|
function staticPowerSetting (data: any) {
|
||||||
|
return request({
|
||||||
|
url: `/app/hby100j/device/strobeFrequency`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 修改音量
|
||||||
|
function settingUpdateVolume (data: any) {
|
||||||
|
return request({
|
||||||
|
url: `/app/hby100j/device/updateVolume`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 强制报警
|
||||||
|
function SosSetting (data: any) {
|
||||||
|
return request({
|
||||||
|
url: `/app/hby100j/device/forceAlarmActivation`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
deviceDeatil,
|
||||||
|
lightModeSettings:lightModeSettings,
|
||||||
|
SosSetting:SosSetting,
|
||||||
|
staticPowerSetting:staticPowerSetting,
|
||||||
|
settingUpdateVolume:settingUpdateVolume
|
||||||
|
};
|
||||||
@ -36,14 +36,10 @@ export interface DeviceDetail {
|
|||||||
currentLightMode?: string;// 当前选中的灯光模式(如"strong",对应强光)
|
currentLightMode?: string;// 当前选中的灯光模式(如"strong",对应强光)
|
||||||
sendMsg: string;
|
sendMsg: string;
|
||||||
lightBrightness: string;
|
lightBrightness: string;
|
||||||
personnelInfo: { // 人员信息(嵌套对象,根据接口调整)
|
strobeFrequency: string;
|
||||||
unitName: string; // 单位
|
volume: string;
|
||||||
position: string; // 职位
|
|
||||||
name: string; // 姓名
|
|
||||||
code: string; // ID(身份证/工号)
|
|
||||||
};
|
|
||||||
chargeState: string;
|
chargeState: string;
|
||||||
alarmStatus:number
|
alarmStatus: number
|
||||||
}
|
}
|
||||||
// 定义灯光模式的类型接口
|
// 定义灯光模式的类型接口
|
||||||
export interface LightMode {
|
export interface LightMode {
|
||||||
|
|||||||
@ -28,7 +28,6 @@ function copyTextToClipboard(input: string, { target = document.body } = {}) {
|
|||||||
element.value = input;
|
element.value = input;
|
||||||
// Prevent keyboard from showing on mobile
|
// Prevent keyboard from showing on mobile
|
||||||
element.setAttribute('readonly', '');
|
element.setAttribute('readonly', '');
|
||||||
|
|
||||||
element.style.contain = 'strict';
|
element.style.contain = 'strict';
|
||||||
element.style.position = 'absolute';
|
element.style.position = 'absolute';
|
||||||
element.style.left = '-9999px';
|
element.style.left = '-9999px';
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export default {
|
|||||||
ElMessageBox.alert(content, '系统提示', { type: 'warning' });
|
ElMessageBox.alert(content, '系统提示', { type: 'warning' });
|
||||||
},
|
},
|
||||||
// 通知提示
|
// 通知提示
|
||||||
notify(content: any) {
|
notify(content: any) {
|
||||||
ElNotification.info(content);
|
ElNotification.info(content);
|
||||||
},
|
},
|
||||||
// 错误通知
|
// 错误通知
|
||||||
@ -56,7 +56,7 @@ export default {
|
|||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 提交内容
|
// 提交内容
|
||||||
prompt(content: any) {
|
prompt(content: any) {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export const initWebSocket = (url: any) => {
|
|||||||
useWebSocket(url, {
|
useWebSocket(url, {
|
||||||
autoReconnect: {
|
autoReconnect: {
|
||||||
// 重连最大次数
|
// 重连最大次数
|
||||||
retries: 3,
|
retries: 3,
|
||||||
// 重连间隔
|
// 重连间隔
|
||||||
delay: 1000,
|
delay: 1000,
|
||||||
onFailed() {
|
onFailed() {
|
||||||
|
|||||||
886
src/views/controlCenter/100J/index.vue
Normal file
886
src/views/controlCenter/100J/index.vue
Normal file
@ -0,0 +1,886 @@
|
|||||||
|
<template>
|
||||||
|
<div class="device-page p-2">
|
||||||
|
<!-- 头部信息栏 -->
|
||||||
|
<div class="header-bar">
|
||||||
|
<div>设备名称:{{ deviceDetail.deviceName }}</div>
|
||||||
|
<div>设备型号:{{ deviceDetail.deviceImei }}</div>
|
||||||
|
<div class="device-status">设备状态:
|
||||||
|
<span :class="{ online: deviceDetail.onlineStatus === 1, offline: deviceDetail?.onlineStatus === 0 }">
|
||||||
|
{{ deviceDetail.onlineStatus === 1 ? '在线' : '离线' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>电量:{{ deviceDetail.batteryPercentage || 0 }}%</div>
|
||||||
|
<div>续航:{{ deviceDetail.batteryRemainingTime || "0" }} 分钟</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主体内容区域 -->
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<el-row :gutter="20" class="content-row" :class="deviceDetail.alarmStatus == 1 ? '' : 'displayNone'">
|
||||||
|
<el-col :lg="24" :xs="24">
|
||||||
|
<div class="staticRwo" :class="deviceDetail.alarmStatus == 1 ? '' : 'displayNone'"
|
||||||
|
@click="showClose()">
|
||||||
|
设备强制报警中!
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<!-- 第一行:灯光模式 + 灯光亮度、强制报警、位置信息 -->
|
||||||
|
<el-row :gutter="20" class="content-row">
|
||||||
|
<el-col :lg="16" :xs="24">
|
||||||
|
<div class="content-card">
|
||||||
|
<h4 class="section-title">报警模式</h4>
|
||||||
|
<div class="light-mode">
|
||||||
|
<!-- 使用v-for循环渲染灯光模式卡片 -->
|
||||||
|
<div class="mode-card" :class="{ 'active': mode.active }"
|
||||||
|
@click.stop="handleVoiceType(mode.id)" v-for="mode in sta_VoiceType" :key="mode.id">
|
||||||
|
<img :src="mode.active ? mode.activeIcon : mode.icon" :alt="mode.name"
|
||||||
|
class="mode-icon" />
|
||||||
|
<div class="mode-name">{{ mode.name }}</div>
|
||||||
|
<el-switch v-model="mode.switchStatusVioice" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :lg="8" :xs="24">
|
||||||
|
<div class="brightness-alarm">
|
||||||
|
<el-button type="danger" class="alarm-btn" @click="forceAlarm" :loading="forceAlarmLoading"
|
||||||
|
v-if="deviceDetail.alarmStatus === 0 || deviceDetail.alarmStatus === null"
|
||||||
|
:loading-text="forceAlarmLoading ? '报警中...' : '强制报警'"> {{
|
||||||
|
forceAlarmLoading ? '报警中' : '强制报警' }}</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="content-card_gps">
|
||||||
|
<h4 class="section-title">位置信息</h4>
|
||||||
|
<div class="location-info">
|
||||||
|
<div class="location-item">
|
||||||
|
<span class="location-icon"></span>
|
||||||
|
<span>经纬度 {{ deviceDetail && deviceDetail.longitude ?
|
||||||
|
Number(deviceDetail.longitude).toFixed(4) : '无' }}
|
||||||
|
{{ deviceDetail && deviceDetail.latitude ? Number(deviceDetail.latitude).toFixed(4)
|
||||||
|
: '无' }} </span>
|
||||||
|
</div>
|
||||||
|
<div class="location-item">
|
||||||
|
|
||||||
|
<div>地址 <span class="lacatin_gps">{{ deviceDetail.address || "未获取到地址" }}</span></div>
|
||||||
|
<el-button link type="primary" class="view-btn"
|
||||||
|
@click="lookMap(deviceDetail)">查看</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 第二行:人员信息登记 + 发送信息 -->
|
||||||
|
<el-row :gutter="20" class="content-row">
|
||||||
|
<el-col :lg="16" :xs="24">
|
||||||
|
<div class="content-card">
|
||||||
|
<h4 class="section-title">警示灯模式</h4>
|
||||||
|
<div class="light-mode">
|
||||||
|
<!-- 使用v-for循环渲染灯光模式卡片 -->
|
||||||
|
<div class="mode-card" :class="{ 'active': mode.active }"
|
||||||
|
@click.stop="handleModeClick(mode.id)" v-for="mode in lightModes" :key="mode.id">
|
||||||
|
<img :src="mode.active ? mode.activeIcon : mode.icon" :alt="mode.name"
|
||||||
|
class="mode-icon" />
|
||||||
|
<div class="mode-name">{{ mode.name }}</div>
|
||||||
|
<el-switch v-model="mode.switchStatus" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :lg="8" :xs="24">
|
||||||
|
<div class="content-card ">
|
||||||
|
<div class="brightness-alarm">
|
||||||
|
<div class="brightness-control">
|
||||||
|
<span class="brightness-label">亮度</span>
|
||||||
|
<el-input class="inputTFT" v-model="deviceDetail.lightBrightness" :min="10" :max="100"
|
||||||
|
:step="1" size="small" />
|
||||||
|
<span class="brightness-value">%</span>
|
||||||
|
<el-button type="primary" class="save-btn" v-loading="lightModesLoading"
|
||||||
|
@click="saveBtnlight">保存 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="brightness-alarm">
|
||||||
|
<div class="brightness-control">
|
||||||
|
<span class="brightness-label">频率</span>
|
||||||
|
<el-input class="inputTFT" v-model="deviceDetail.strobeFrequency" :min="0.5" :max="10"
|
||||||
|
:step="1" size="small" />
|
||||||
|
<span class="brightness-value">HZ</span>
|
||||||
|
<el-button type="primary" class="save-btn" @click="saveBtnstrobe">保存 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="brightness-alarm">
|
||||||
|
<div class="brightness-control">
|
||||||
|
<span class="brightness-label">音量</span>
|
||||||
|
<el-input class="inputTFT" v-model="deviceDetail.volume" :min="10" :max="100" :step="1"
|
||||||
|
size="small" />
|
||||||
|
<span class="brightness-value">%</span>
|
||||||
|
<el-button type="primary" class="save-btn" @click="saveBtnVolume">保存 </el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
<!-- ===========充电提示框====== -->
|
||||||
|
<el-dialog title="充电提示" v-model="centerDialogVisible" width="15%">
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<h3 style="color: rgba(224, 52, 52, 1)">设备电量低于20%</h3>
|
||||||
|
</div>
|
||||||
|
<div>请及时充电</div>
|
||||||
|
<span slot="footer" class="dialog-footer" style="text-align: right;display: block;">
|
||||||
|
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup name="DeviceControl" lang="ts">
|
||||||
|
const route = useRoute();
|
||||||
|
import { useMqtt } from '@/utils/mqtt';
|
||||||
|
import api from '@/api/controlCenter/controlPanel/100J'
|
||||||
|
import { DeviceDetail, LightMode } from '@/api/controlCenter/controlPanel/types';
|
||||||
|
import {getDeviceStatus } from '@/utils/function';
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const router = useRouter();
|
||||||
|
// 导入图片资源(确保路径正确)
|
||||||
|
import closeDefault from '@/assets/images/close.png';
|
||||||
|
import closeActive from '@/assets/images/close_HL.png';
|
||||||
|
import rb from '@/assets/images/rb.png';
|
||||||
|
import rbAc from '@/assets/images/rbAc.png';
|
||||||
|
import sg from '@/assets/images/sg.png';
|
||||||
|
import sgAc from '@/assets/images/sgAc.png';
|
||||||
|
const forceAlarmLoading = ref(false) //强制报警
|
||||||
|
const lightModesLoading = ref(false)
|
||||||
|
const centerDialogVisible = ref(false)
|
||||||
|
const {
|
||||||
|
connected,
|
||||||
|
connect,
|
||||||
|
subscribe,
|
||||||
|
onConnect,
|
||||||
|
onError,
|
||||||
|
onMessage,
|
||||||
|
disconnect
|
||||||
|
} = useMqtt();
|
||||||
|
// 报警模式
|
||||||
|
const sta_VoiceType = ref([
|
||||||
|
{
|
||||||
|
id: 'fire',
|
||||||
|
name: '消防',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
switchStatusVioice: true,
|
||||||
|
active: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '0',
|
||||||
|
name: '公安',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
active: false,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
name: '交警',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
name: '市政',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: '应急',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
name: '医疗',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
name: '铁道',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
name: 'app语音',
|
||||||
|
icon: sg, // 直接使用导入的变量
|
||||||
|
activeIcon: sgAc,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '-1',
|
||||||
|
name: '关闭',
|
||||||
|
icon: closeDefault, // 直接使用导入的变量
|
||||||
|
activeIcon: closeActive,
|
||||||
|
switchStatusVioice: false,
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
])
|
||||||
|
// 警示灯灯光模式数据(引用导入的图片)
|
||||||
|
const lightModes = ref<LightMode[]>([
|
||||||
|
{
|
||||||
|
id: 'redBlueAlternate', // 红蓝交替
|
||||||
|
name: '红蓝交替',
|
||||||
|
icon: rb,
|
||||||
|
activeIcon: rbAc,
|
||||||
|
switchStatus: true,
|
||||||
|
instructValue: '6',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'redFlash', // 红闪
|
||||||
|
name: '红闪',
|
||||||
|
icon: rb,
|
||||||
|
activeIcon: rbAc,
|
||||||
|
switchStatus: false,
|
||||||
|
instructValue: '0',
|
||||||
|
active: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'yellowFlash', // 黄闪
|
||||||
|
name: '黄闪',
|
||||||
|
icon: rb,
|
||||||
|
activeIcon: rbAc,
|
||||||
|
switchStatus: false,
|
||||||
|
instructValue: '2',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'blueFlash', // 蓝闪
|
||||||
|
name: '蓝闪',
|
||||||
|
icon: rb,
|
||||||
|
activeIcon: rbAc,
|
||||||
|
switchStatus: false,
|
||||||
|
instructValue: '1',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'redClockwise', // 红色顺时针
|
||||||
|
name: '红色顺时针',
|
||||||
|
icon: rb,
|
||||||
|
activeIcon: rbAc,
|
||||||
|
switchStatus: false,
|
||||||
|
instructValue: '3',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'yellowClockwise', // 黄色顺时针
|
||||||
|
name: '黄色顺时针',
|
||||||
|
icon: rb,
|
||||||
|
activeIcon: rbAc,
|
||||||
|
switchStatus: false,
|
||||||
|
instructValue: '4',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'redBlueClockwise', // 红蓝顺时针
|
||||||
|
name: '红蓝顺时针',
|
||||||
|
icon: rb,
|
||||||
|
activeIcon: rbAc,
|
||||||
|
switchStatus: false,
|
||||||
|
instructValue: '5',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'close', // 关闭
|
||||||
|
name: '关闭',
|
||||||
|
icon: closeDefault,
|
||||||
|
activeIcon: closeActive,
|
||||||
|
switchStatus: false,
|
||||||
|
instructValue: '-1',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const deviceDetail = ref<DeviceDetail & { typeName: string }>({
|
||||||
|
lightBrightness: '',
|
||||||
|
deviceName: '',
|
||||||
|
deviceImei: '',
|
||||||
|
onlineStatus: 0,
|
||||||
|
batteryPercentage: 0,
|
||||||
|
batteryRemainingTime: '',
|
||||||
|
longitude: '',
|
||||||
|
latitude: '',
|
||||||
|
address: '',
|
||||||
|
sendMsg: '',
|
||||||
|
chargeState: '0',
|
||||||
|
typeName: '',
|
||||||
|
alarmStatus: 0,
|
||||||
|
strobeFrequency: '0.5',
|
||||||
|
volume: '10'
|
||||||
|
});
|
||||||
|
const isUpdatingStatus = ref(false);
|
||||||
|
// 报警模式// 2. 点击卡片事件
|
||||||
|
const handleVoiceType = async (targetId: string) => {
|
||||||
|
const deviceId = route.params.deviceId as string;
|
||||||
|
if (!deviceId) return;
|
||||||
|
const targetMode = sta_VoiceType.value.find(mode => mode.id === targetId);
|
||||||
|
if (!targetMode) return;
|
||||||
|
if (targetMode.active) return;
|
||||||
|
sta_VoiceType.value.forEach(mode => {
|
||||||
|
mode.active = mode.id === targetId;
|
||||||
|
if (mode.active) {
|
||||||
|
mode.switchStatusVioice = true;
|
||||||
|
} else {
|
||||||
|
mode.switchStatusVioice = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 2. 调用强制报警接口
|
||||||
|
const params = {
|
||||||
|
deviceIds: [deviceId],
|
||||||
|
voiceStrobeAlarm: targetId === '-1' ? 0 : 1,
|
||||||
|
mode: targetId == '-1' ? 0 : targetId
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const res = await api.SosSetting(params);
|
||||||
|
if (res.code == 200) {
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
await getList()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 警示灯模式
|
||||||
|
const handleModeClick = async (modeId: string) => {
|
||||||
|
if (isUpdatingStatus.value || isSyncingStatus.value) return;
|
||||||
|
try {
|
||||||
|
const deviceId = route.params.deviceId as string;
|
||||||
|
if (!deviceId) return;
|
||||||
|
const targetMode = lightModes.value.find(m => m.id === modeId);
|
||||||
|
if (!targetMode || !targetMode.instructValue) return;
|
||||||
|
isUpdatingStatus.value = true;
|
||||||
|
const res = await api.lightModeSettings({
|
||||||
|
deviceId,
|
||||||
|
instructValue: targetMode.instructValue,
|
||||||
|
deviceImei: deviceDetail.value.deviceImei,
|
||||||
|
typeName: deviceDetail.value.typeName,
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.closeAll();
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
setActiveLightMode(modeId);
|
||||||
|
} else {
|
||||||
|
proxy?.$modal.msgError(res.msg);
|
||||||
|
const prevActiveMode = lightModes.value.find(m => m.active);
|
||||||
|
if (prevActiveMode) {
|
||||||
|
setActiveLightMode(prevActiveMode.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 异常时恢复状态
|
||||||
|
const prevActiveMode = lightModes.value.find(m => m.active);
|
||||||
|
if (prevActiveMode) {
|
||||||
|
setActiveLightMode(prevActiveMode.id);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
isUpdatingStatus.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const isSyncingStatus = ref(false);
|
||||||
|
// 警示灯接口
|
||||||
|
const setActiveLightMode = (targetModeId: string) => {
|
||||||
|
isSyncingStatus.value = true;
|
||||||
|
lightModes.value.forEach(mode => {
|
||||||
|
const isActive = mode.id === targetModeId;
|
||||||
|
mode.active = isActive;
|
||||||
|
mode.switchStatus = isActive;
|
||||||
|
});
|
||||||
|
isSyncingStatus.value = false;
|
||||||
|
};
|
||||||
|
const getList = async () => {
|
||||||
|
try {
|
||||||
|
const deviceId = route.params.deviceId;
|
||||||
|
if (!deviceId) return;
|
||||||
|
const res = await api.deviceDeatil(deviceId as string);
|
||||||
|
deviceDetail.value = res.data;
|
||||||
|
|
||||||
|
// ==========灯光模式逻辑==========
|
||||||
|
let targetModeId = "redBlueAlternate";
|
||||||
|
const mainLightMode = String(res.data.strobeMode);
|
||||||
|
const matchedMode = lightModes.value.find(
|
||||||
|
mode => mode.instructValue === mainLightMode
|
||||||
|
);
|
||||||
|
if (matchedMode) {
|
||||||
|
targetModeId = matchedMode.id;
|
||||||
|
}
|
||||||
|
setActiveLightMode(targetModeId);
|
||||||
|
// 报警模式
|
||||||
|
const alarmMode = String(res.data.alarmMode); // 报警模式ID
|
||||||
|
const voiceStrobeAlarm = String(res.data.voiceStrobeAlarm); // 报警开关状态:1开启,0关闭
|
||||||
|
// 先重置所有报警模式的状态
|
||||||
|
sta_VoiceType.value.forEach(mode => {
|
||||||
|
mode.active = false;
|
||||||
|
mode.switchStatusVioice = false;
|
||||||
|
});
|
||||||
|
if (voiceStrobeAlarm === '1') {
|
||||||
|
const matchedVoiceMode = sta_VoiceType.value.find(
|
||||||
|
mode => mode.id === alarmMode
|
||||||
|
);
|
||||||
|
if (matchedVoiceMode) {
|
||||||
|
matchedVoiceMode.active = true;
|
||||||
|
matchedVoiceMode.switchStatusVioice = true;
|
||||||
|
} else {
|
||||||
|
console.warn('未找到对应的报警模式:', alarmMode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const closeMode = sta_VoiceType.value.find(mode => mode.id === '-1');
|
||||||
|
if (closeMode) {
|
||||||
|
closeMode.active = true;
|
||||||
|
closeMode.switchStatusVioice = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设备详情失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 灯光亮度
|
||||||
|
const saveBtnlight = () => {
|
||||||
|
lightModesLoading.value = true
|
||||||
|
let data = {
|
||||||
|
deviceId: route.params.deviceId,
|
||||||
|
brightness: deviceDetail.value.lightBrightness,
|
||||||
|
}
|
||||||
|
api.lightModeSettings(data).then((res) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
lightModesLoading.value = false
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
lightModesLoading.value = false
|
||||||
|
proxy?.$modal.msgError(res.msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
lightModesLoading.value = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 爆闪频率
|
||||||
|
const saveBtnstrobe = () => {
|
||||||
|
let data = {
|
||||||
|
deviceId: route.params.deviceId,
|
||||||
|
frequency: deviceDetail.value.strobeFrequency,
|
||||||
|
}
|
||||||
|
api.staticPowerSetting(data).then((res) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 修改音量
|
||||||
|
const saveBtnVolume = () => {
|
||||||
|
let data = {
|
||||||
|
deviceId: route.params.deviceId,
|
||||||
|
volume: deviceDetail.value.volume,
|
||||||
|
}
|
||||||
|
api.settingUpdateVolume(data).then((res) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
proxy?.$modal.msgSuccess(res.msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解除报警
|
||||||
|
const showClose = async () => {
|
||||||
|
try {
|
||||||
|
await proxy?.$modal.confirm('确定要对该设备解除报警?', '提示');
|
||||||
|
// 2. 准备请求数据
|
||||||
|
let data = {
|
||||||
|
deviceIds: [route.params.deviceId],
|
||||||
|
typeName: deviceDetail.value.typeName,
|
||||||
|
deviceImeiList: [deviceDetail.value.deviceImei],
|
||||||
|
instructValue: '0', //强制报警1,解除报警0
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强制报警
|
||||||
|
const forceAlarm = async () => {
|
||||||
|
try {
|
||||||
|
await proxy?.$modal.confirm('确定要对该设备开启强制报警?', '提示');
|
||||||
|
forceAlarmLoading.value = true
|
||||||
|
// 2. 准备请求数据
|
||||||
|
let data = {
|
||||||
|
deviceIds: [route.params.deviceId],
|
||||||
|
typeName: deviceDetail.value.typeName,
|
||||||
|
deviceImeiList: [deviceDetail.value.deviceImei],
|
||||||
|
instructValue: '1', //强制报警1,解除报警0
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
// proxy?.$modal.msgWarning(error.msg)
|
||||||
|
forceAlarmLoading.value = false;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
forceAlarmLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const lookMap = (row: any) => {
|
||||||
|
console.log(row, 'rowrowrowrowrworowrowrowrowrowrow');
|
||||||
|
router.push({
|
||||||
|
path: '/controlCenter/controlPanel',
|
||||||
|
query: {
|
||||||
|
view: 'map',
|
||||||
|
deviceId: row.deviceId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getList();
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.p-2 {
|
||||||
|
background: rgba(247, 248, 252, 1);
|
||||||
|
min-height: 100vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device-page {
|
||||||
|
.header-bar {
|
||||||
|
border-radius: 8px;
|
||||||
|
background: linear-gradient(135deg, #3400e7, #009bff);
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
.device-status {
|
||||||
|
.online {
|
||||||
|
color: #00ff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline {
|
||||||
|
color: rgb(224, 52, 52);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
.content-row {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card {
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 34, 96, 0.1);
|
||||||
|
background: white;
|
||||||
|
padding: 0px 20px 50px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
height: 289px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card_gps {
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 34, 96, 0.1);
|
||||||
|
background: white;
|
||||||
|
padding: 0px 20px 50px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
height: 78%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light-mode {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lacatin_gps {
|
||||||
|
height: 70px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(247, 248, 252, 1);
|
||||||
|
display: inline-block;
|
||||||
|
width: 400px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 107px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-color: #409eff;
|
||||||
|
background-color: rgba(64, 158, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-icon {
|
||||||
|
width: 48px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
object-fit: scale-down;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-name {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-switch {
|
||||||
|
--el-switch-on-color: #409eff;
|
||||||
|
--el-switch-off-color: #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.brightness-alarm {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
.brightness-control {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
border-radius: 39px;
|
||||||
|
// box-shadow: 0px 0px 6px 0px rgba(0, 34, 96, 0.1);
|
||||||
|
background: rgba(255, 255, 255, 1);
|
||||||
|
width: 100%;
|
||||||
|
// height: 54px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.brightness-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
min-width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brightness-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
padding: 6px 20px;
|
||||||
|
border-radius: 29px;
|
||||||
|
background: rgba(2, 124, 251, 1);
|
||||||
|
border: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputTFT {
|
||||||
|
width: 130px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alarm-btn {
|
||||||
|
background-color: rgba(224, 52, 52, 1);
|
||||||
|
border-color: rgba(224, 52, 52, 1);
|
||||||
|
padding: 8px 20px;
|
||||||
|
border-radius: 27px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-info {
|
||||||
|
.location-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
|
||||||
|
.location-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-btn {
|
||||||
|
margin: 0 8px;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
min-width: 35px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-btn {
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
justify-self: start;
|
||||||
|
padding: 6px 20px;
|
||||||
|
position: absolute;
|
||||||
|
right: 19px;
|
||||||
|
bottom: 30px;
|
||||||
|
border-radius: 29px;
|
||||||
|
background: rgba(2, 124, 251, 1);
|
||||||
|
border: none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-content {
|
||||||
|
// display: flex;
|
||||||
|
// flex-direction: column;
|
||||||
|
// gap: 10px;
|
||||||
|
|
||||||
|
.el-textarea {
|
||||||
|
border: 1px solid rgba(29, 111, 255, 1);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(247, 248, 252, 1);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
background: rgba(247, 248, 252, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-btn {
|
||||||
|
align-self: flex-end;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 29px;
|
||||||
|
background: rgba(2, 124, 251, 1);
|
||||||
|
border: none;
|
||||||
|
margin: 20px 0px 30px 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100px;
|
||||||
|
border: 1px dashed #dcdfe6;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-input {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-video-btn {
|
||||||
|
padding: 6px 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式调整
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.header-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid .register-btn {
|
||||||
|
grid-column: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light-mode .mode-group {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light-mode .mode-item {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light-mode .mode-icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-img {
|
||||||
|
width: 52px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.staticRwo {
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 34, 96, 0.1);
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
height: auto;
|
||||||
|
line-height: 36px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-indent: 15px;
|
||||||
|
color: #ff0000;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 17px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayNone {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -6,3 +6,4 @@ export default () => {
|
|||||||
autoInstall: true
|
autoInstall: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user