2025年05月09日11:39:05

This commit is contained in:
luojiayi 2025-05-09 11:39:26 +08:00
parent 3c1cb3ec88
commit 5e52002178
11 changed files with 168 additions and 92 deletions

View File

@ -71,9 +71,9 @@ const getLocateRecord = () => {
if (list.length < 50) {
let marker: any = "";
if (index == 0) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
} else if (index == list.length - 1) {
marker = newMap.marker({ icon: startIcon, position: [item.lng, item.lat], zIndex: 13 });
} else if (index == list.length - 1) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
} else {
marker = newMap.marker({ icon: ViaIcon, position: [item.lng, item.lat], zIndex: 12 });
}
@ -119,6 +119,7 @@ onMounted(() => {
height: 400px;
flex-shrink: 0;
position: relative;
.toolbox {
width: 32px;
height: 32px;

View File

@ -2,7 +2,7 @@
<div class="device">
<div class="device-head">
<div class="title">设备列表</div>
<el-select class="select" v-model="mode" @change="handelMode">
<el-select class="select" v-model="mode" @change="handleMode">
<el-option label="全部" value="" />
<el-option label="常规模式" value="0" />
<el-option label="审讯模式" value="1" />
@ -10,10 +10,10 @@
</el-select>
</div>
<template v-if="deviceData.length">
<div v-infinite-scroll="handelLoad" :infinite-scroll-immediate="false" class="device-list noScrollbar infinite-list" style="overflow: auto">
<el-popover :width="350" class="box-item" placement="right" v-for="item in deviceData" :key="item.id">
<div v-infinite-scroll="handleLoad" :infinite-scroll-immediate="false" class="device-list noScrollbar infinite-list" style="overflow: auto">
<el-popover :width="400" class="box-item" placement="right" v-for="item in deviceData" :key="item.id">
<template #reference>
<div class="item" :class="{ active: deviceId === item.deviceId }" @click="handelItem(item)">
<div class="item" :class="{ active: deviceId === item.deviceId }" @click="handleItem(item)">
<div class="item-img">
<img src="@/assets/img/handcuffs.png" alt="" srcset="" />
</div>
@ -50,17 +50,27 @@
<span class="lable">联系电话</span>
{{ item.adminPhone }}
</div>
<div>
<span class="lable">佩戴者</span>
{{ item.userNumber || "--" }}
</div>
<div>
<span class="lable">状态</span>
<el-tag :type="statusColor[item.status]">{{ statusEnum[item.status] }}</el-tag>
</div>
<div>
<span class="lable">模式</span>
<el-tag :type="modeColor[item.mode]">{{ modeEnum[item.mode] }}</el-tag>
</div>
<div>
<span class="lable">佩戴者</span>
{{ item.userNumber || "--" }}
<span class="lable">模式选择</span>
<el-select
:teleported="false"
v-model="item.mode"
placeholder="请选择模式"
style="width: 200px"
@change="(e) => handleSelect(e, item.deviceId)"
>
<el-option label="常规模式" :value="0" />
<el-option label="审讯模式" :value="1" />
<el-option label="户外押送模式" :value="2" />
</el-select>
</div>
</div>
</template>
@ -75,22 +85,26 @@
<script setup lang="ts">
import { TDevice } from "@/api/index.d";
import { ref, watch, reactive, onMounted } from "vue";
import { deviceList } from "@/api/index";
import { deviceList, setMode } from "@/api/index";
import battery1 from "@/assets/img/battery1.png";
import battery from "@/assets/img/battery.png";
import { ElMessage } from "element-plus";
const statusColor = ["danger", "success", "warning"];
const modeColor = ["primary", "danger", "warning"];
enum statusEnum {
"离线" = 0,
"在线",
"充电中",
}
enum modeEnum {
"常规",
"审讯模式",
"户外押送",
}
const emit = defineEmits(["click"]);
const mode = ref("");
@ -116,19 +130,25 @@ const getdeviceList = async () => {
emit("click", res.records[0]);
}
};
//
const handleSelect = (mode: number, deviceId: number) => {
setMode({ deviceId, mode }).then(() => {
ElMessage.success("操作成功");
});
};
const handelLoad = () => {
const handleLoad = () => {
if (loadFlag.value) return;
devicePaging.page += 1;
getdeviceList();
};
const handelMode = (e) => {
const handleMode = (e) => {
devicePaging.mode = e;
devicePaging.page = 1;
deviceData.value = [];
getdeviceList();
};
const handelItem = (item) => {
const handleItem = (item) => {
deviceId.value = item.deviceId;
emit("click", item);
};
@ -152,9 +172,11 @@ onMounted(() => {
justify-content: space-between;
box-sizing: border-box;
margin: 14px 0;
.title {
color: #061451;
font-size: 18px;
&::before {
display: inline-block;
margin-right: 10px;
@ -165,15 +187,18 @@ onMounted(() => {
background: #061451;
}
}
.select {
width: 120px;
margin-right: 20px;
}
}
.device-list {
flex: 1;
overflow: auto;
list-style: none;
.item {
height: 89px;
background: #ffffff;
@ -182,53 +207,66 @@ onMounted(() => {
box-sizing: border-box;
border-bottom: 1px solid #dedede;
cursor: pointer;
&.active {
background: #f5f5f5;
}
&:hover {
background: #f5f5f5;
}
.item-img {
width: 50px;
height: 50px;
margin-left: 20px;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
}
}
.item-content {
flex: 1;
margin: 0 15px;
.item-content-name {
color: #061451;
font-size: 18px;
}
.item-content-num {
color: #787878;
font-size: 16px;
}
}
.item-right {
margin-right: 20px;
.battery {
display: flex;
align-items: center;
.battery-icon {
width: 24px;
height: 24px;
margin-right: 5px;
img {
width: 100%;
height: 100%;
}
}
.battery-num {
color: #787878;
font-size: 16px;
}
}
.user {
color: #787878;
font-size: 16px;
@ -242,6 +280,7 @@ onMounted(() => {
}
}
}
.demo-rich-conent {
display: flex;
flex-direction: column;

View File

@ -3,14 +3,16 @@
<div class="card-head">
<div class="title">当前设备告警记录</div>
<div class="search">
<el-select class="select" placeholder="请选择事件类型" v-model="paging.warnType" style="width: 150px; margin-right: 20px" @change="handelChange">
<el-option label="全部" value="" />
<el-option v-for="(item, index) in warnTypeList" :key="index" :label="item" :value="index" />
<el-select class="select" placeholder="请选择事件类型" v-model="paging.warnType"
style="width: 150px; margin-right: 20px" @change="handleChange">
<el-option label="全部" value=""/>
<el-option v-for="(item, index) in warnTypeList" :key="index" :label="item" :value="index"/>
</el-select>
<el-select class="select" placeholder="请选择处理状态" v-model="paging.status" style="width: 150px" @change="handelChange">
<el-option label="全部" value="" />
<el-option label="待处理" value="0" />
<el-option label="已处理" value="1" />
<el-select class="select" placeholder="请选择处理状态" v-model="paging.status" style="width: 150px"
@change="handleChange">
<el-option label="全部" value=""/>
<el-option label="待处理" value="0"/>
<el-option label="已处理" value="1"/>
</el-select>
</div>
</div>
@ -23,23 +25,25 @@
{{ warnTypeEnum[rows.warnType] }}
</template>
<template #operator="{ rows }">
<el-button type="primary" size="small" link @click="toIncidentDispose(rows.id)"> 处理事件 </el-button>
<el-button type="primary" size="small" link @click="toIncidentDispose(rows.id)"> 处理事件</el-button>
</template>
</TableCustom>
</div>
</template>
<script setup lang="ts">
import TableCustom from "@/components/table-custom.vue";
import { warningRecord } from "@/api/index";
import { ref, reactive, watch } from "vue";
import { TDevice } from "@/api/index.d";
import { useRouter } from "vue-router";
import {warningRecord} from "@/api/index";
import {ref, reactive, watch} from "vue";
import {TDevice} from "@/api/index.d";
import {useRouter} from "vue-router";
const statusColor = ["danger", "success"];
enum warningStatusEnum {
"待处理",
"已处理",
}
enum warnTypeEnum {
"SOS告警",
"围栏告警",
@ -49,6 +53,7 @@ enum warnTypeEnum {
"血氧告警",
"体温告警",
}
const router = useRouter();
const warnTypeList = ["SOS告警", "围栏告警", "破坏告警", "低电告警", "心率告警", "血氧告警", "体温告警"];
const paging = reactive({
@ -70,11 +75,11 @@ const props = defineProps({
//
let columns = [
{ type: "index", label: "序号", width: 55, align: "center" },
{ prop: "warnType", label: "事件类型" },
{ prop: "status", label: "处理状态" },
{ prop: "createTime", label: "触发时间" },
{ prop: "operator", label: "操作" },
{type: "index", label: "序号", width: 55, align: "center"},
{prop: "warnType", label: "事件类型"},
{prop: "status", label: "处理状态"},
{prop: "createTime", label: "触发时间"},
{prop: "operator", label: "操作"},
];
const getData = async () => {
const res = await warningRecord(paging);
@ -82,7 +87,7 @@ const getData = async () => {
paging.total = res.total;
};
const handelChange = () => {
const handleChange = () => {
paging.page = 1;
getData();
};
@ -92,19 +97,19 @@ const changePage = (val: number) => {
};
watch(
() => props.deviceInfo,
(newVal) => {
if (newVal) {
paging.deviceId = newVal.deviceId;
getData && getData();
}
},
{ immediate: true } //
() => props.deviceInfo,
(newVal) => {
if (newVal) {
paging.deviceId = newVal.deviceId;
getData && getData();
}
},
{immediate: true} //
);
const toIncidentDispose = (id: string) => {
router.push({
path: "/incidentDispose",
query: { id },
query: {id},
});
};
</script>
@ -116,6 +121,7 @@ const toIncidentDispose = (id: string) => {
box-sizing: border-box;
flex-shrink: 0;
background: #ffffff;
.card-head {
color: #061451;
font-size: 18px;
@ -123,6 +129,7 @@ const toIncidentDispose = (id: string) => {
align-items: center;
justify-content: space-between;
transform: translateX(-10px);
.title {
&::before {
display: inline-block;
@ -134,6 +141,7 @@ const toIncidentDispose = (id: string) => {
background: #061451;
}
}
.search {
display: flex;
align-items: center;

View File

@ -1,7 +1,7 @@
<template>
<div class="container">
<div class="el-row-left">
<DeviceModel @click="handelClickDevice" />
<DeviceModel @click="handleClickDevice" />
</div>
<div class="el-row-right scrollbar">
<MonitoringTop :funcList="funcList" />
@ -9,7 +9,7 @@
<DeviceLocationMap :device-id="deviceInfo.deviceId" />
<el-row class="box" :gutter="20">
<el-col :span="12" :xs="24" :sm="24" :md="24" :lg="24" :xl="12" style="margin-bottom: 20px">
<DeviceHistory @change="handelRadio" ref="devHisRef" />
<DeviceHistory @change="handleRadio" ref="devHisRef" />
</el-col>
<el-col :span="12" :xs="24" :sm="24" :md="24" :lg="24" :xl="12">
<DeviceRecord :deviceInfo="deviceInfo" />
@ -19,7 +19,7 @@
<div class="el-row-right-content" v-else>
<el-row :gutter="20">
<el-col :span="24" style="margin-bottom: 20px">
<DeviceHistory @change="handelRadio" ref="devHisRef" />
<DeviceHistory @change="handleRadio" ref="devHisRef" />
</el-col>
<el-col :span="24">
<DeviceRecord :deviceInfo="deviceInfo" />
@ -60,10 +60,10 @@ const getHealthLatestData = () => {
funcList.value[0].num = res.hr;
funcList.value[1].num = res.bo;
funcList.value[2].num = res.temp;
handelRadio(devHisRef.value.radio);
handleRadio(devHisRef.value.radio);
});
};
const handelRadio = (val: number) => {
const handleRadio = (val: number) => {
if (val == 1) {
devHisRef.value?.getOptionsData(HealthData.value.hrArr, "心率", "#FF0303");
} else if (val == 2) {
@ -79,7 +79,7 @@ const IntervalFn = () => {
}, 60000);
};
const handelClickDevice = (val: TDevice.IListRes) => {
const handleClickDevice = (val: TDevice.IListRes) => {
devHisRef.value.radio = "1";
deviceInfo.value = val;
getHealthLatestData();

View File

@ -15,7 +15,7 @@
</template>
<template #operator="{ rows }">
<el-button link type="primary" size="small" @click="handleEdit(rows)"> 修改 </el-button>
<el-button link type="danger" size="small" @click="handelDel(rows.id)"> 删除 </el-button>
<el-button link type="danger" size="small" @click="handleDel(rows.id)"> 删除 </el-button>
</template>
</TableCustom>
</div>
@ -91,7 +91,7 @@ const handleEdit = (row: TableItem) => {
visible.value = true;
};
//
const handelDel = (id: number) => {
const handleDel = (id: number) => {
ElMessageBox.confirm("确定要删除吗?", "提示", {
type: "warning",
})

View File

@ -179,9 +179,9 @@ const getLocateRecord = () => {
if (list.length < 50) {
let marker: any = "";
if (index == 0) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
} else if (index == list.length - 1) {
marker = newMap.marker({ icon: startIcon, position: [item.lng, item.lat], zIndex: 13 });
} else if (index == list.length - 1) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
} else {
marker = newMap.marker({ icon: ViaIcon, position: [item.lng, item.lat], zIndex: 12 });
}

View File

@ -1,37 +1,46 @@
<template>
<el-form label-width="auto">
<el-row :gutter="20" style="margin-top: 20px">
<el-col :span="12">
<el-col :span="8">
<el-form-item label="关机:">
<el-button type="primary" @click="handelControl(1)">关机</el-button>
<el-button type="primary" @click="handelControl(1)" class="btn">关机</el-button>
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="8">
<el-form-item label="重启:">
<el-button type="primary" @click="handelControl(2)">重启</el-button>
<el-button type="primary" @click="handelControl(2)" class="btn">重启</el-button>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="恢复出厂:">
<el-button type="primary" @click="handelControl(3)" class="btn">恢复出厂</el-button>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 20px">
<el-col :span="12">
<el-form-item label="恢复出厂:">
<el-button type="primary" @click="handelControl(3)">恢复出厂</el-button>
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="8">
<el-form-item label="获取实时定位:">
<el-button type="primary" @click="handelControl(4)">获取实时定位</el-button>
<el-button type="primary" @click="handelControl(4)" class="btn">获取实时定位</el-button>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="OTA">
<el-button class="btn" type="primary" @click="handelControl(6)" :disabled="!rowData.otaFlag">设备升级</el-button>
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="定位模式:">
<el-select placeholder="请选择定位模式" v-model="modelValue.mode" style="width: 240px" @change="handelControl(6)">
<el-option label="室内" :value="0" />
<el-option label="室外" :value="1" />
</el-select>
</el-form-item>
</el-col> -->
</el-row>
<el-row :gutter="20"> </el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="OTA">
<el-button type="primary" @click="handelControl(6)" :disabled="!rowData.otaFlag">设备升级</el-button>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="模式选择:">
<el-select placeholder="请选择模式" v-model="modelValue.mode" style="width: 230px" @change="handelControl(5)">
@ -88,6 +97,10 @@ const handelControl = (type: number) => {
emit("change", type);
}
};
// const model = useVModel(props, "modelValue", emit);
</script>
<style scoped>
.btn {
width: 116px;
}
</style>

View File

@ -14,10 +14,10 @@
<el-tag :type="statusColor[rows.status]">{{ statusEnum[rows.status] }}</el-tag>
</template>
<template #useStatus="{ rows }">
<el-switch v-model="rows.useStatus" :active-value="1" :inactive-value="0" @click="handelSwitch(rows, 1)" />
<el-switch v-model="rows.useStatus" :active-value="1" :inactive-value="0" @click="handleSwitch(rows, 1)" />
</template>
<template #deviceSwitch="{ rows }">
<el-switch v-model="rows.deviceSwitch" :active-value="1" :inactive-value="0" @click="handelSwitch(rows, 2)" />
<el-switch v-model="rows.deviceSwitch" :active-value="1" :inactive-value="0" @click="handleSwitch(rows, 2)" />
</template>
<template #mode="{ rows }">
<el-tag :type="modeColor[rows.mode]">{{ modeEnum[rows.mode] }}</el-tag>
@ -30,20 +30,22 @@
<el-button link type="primary" size="small" @click="toPage('deviceInfo', rows)"> 详细信息 </el-button>
<el-button link type="primary" size="small" @click="toPage('mapLocation', rows)"> 地图位置 </el-button>
<el-button link type="primary" size="small" @click="toPage('setting', rows)"> 专项配置 </el-button>
<el-button link type="primary" size="small" @click="handelRow(rows)"> 设备控制 </el-button>
<el-button link type="primary" size="small" @click="handleRow(rows)"> 设备控制 </el-button>
<el-button link type="primary" size="small" @click="handleEdit(rows)"> 修改 </el-button>
<!-- <el-button link type="danger" size="small" @click="handelDel(rows)"> 删除 </el-button> -->
<!-- <el-button link type="danger" size="small" @click="handleDel(rows)"> 删除 </el-button> -->
</template>
</TableCustom>
</div>
<el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
<TableEdit :form-data="rowData" :options="TableEditOptions" :edit="isEdit" :update="updateData" @close="closeDialog" />
</el-dialog>
<el-dialog title="设备控制" v-model="visible1" width="700px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
<el-dialog title="设备控制" v-model="visible1" width="900px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
<!-- <TableEdit :form-data="rowData" :options="controlOptions" :update="updateData" /> -->
<DeviceControl :rowData="rowData" v-model="controlForm" @change="handelControl" />
<DeviceControl :rowData="rowData" v-model="controlForm" @change="handleControl" />
</el-dialog>
<el-dialog title="设备关联" v-model="visible2" width="700px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
<BindArea :orgAllData="orgAllData" :selectDeviceList="selectDeviceList" @close="visible2 = false" :api="bindWebFn" />
</el-dialog>
@ -146,7 +148,7 @@ let columns = ref([
{ prop: "mode", label: "当前模式", width: 100 },
{ prop: "useStatus", label: "使用状态", width: 100 },
// { prop: "deviceSwitch", label: "", width: 100 },
{ prop: "createTime", label: "最新通信时间", width: 180 },
{ prop: "lastHeartbeatTime", label: "最新通信时间", width: 180 },
{ prop: "createTime", label: "创建时间", width: 180 },
{ prop: "operator", label: "操作", width: 400, fixed: "right" },
]);
@ -205,12 +207,12 @@ const handleEdit = (row?: TDevice.IListRes) => {
visible2.value = true;
};
const handelRow = (row?: TDevice.IListRes) => {
const handleRow = (row?: TDevice.IListRes) => {
rowData.value = { ...row };
controlForm.mode = row.mode;
visible1.value = true;
};
const handelSwitch = (val: TDevice.IListRes, type: number) => {
const handleSwitch = (val: TDevice.IListRes, type: number) => {
let api = type == 1 ? setUseStatus : setStatus;
api({
deviceId: val.deviceId,
@ -230,7 +232,7 @@ const getOrgAllList = () => {
orgAllData.value = res;
});
};
const handelControl = (type: number) => {
const handleControl = (type: number) => {
let api: Function;
let params: any = {};
if (type == 4) {
@ -295,6 +297,9 @@ const toPage = (path: string, row: TDevice.IListRes) => {
query: p,
});
};
defineExpose({
getData, //
});
</script>
<style scoped>

View File

@ -48,9 +48,9 @@ const sectionDateChange = (val) => {
const getLocateRecord = () => {
locateRecord(params).then((res) => {
newMap.clearMap();
if (res && res.length) {
let list = res;
newMap.setCenter([list[0].lng, list[0].lat]);
newMap.polyline(list);
let startIcon = newMap.newIcon({
@ -69,9 +69,9 @@ const getLocateRecord = () => {
list.forEach((item, index) => {
let marker: any = "";
if (index == 0) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
} else if (index == list.length - 1) {
marker = newMap.marker({ icon: startIcon, position: [item.lng, item.lat], zIndex: 13 });
} else if (index == list.length - 1) {
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat], zIndex: 13 });
} else {
marker = newMap.marker({ icon: ViaIcon, position: [item.lng, item.lat], zIndex: 12 });
}

View File

@ -72,6 +72,17 @@
<el-input v-model="ruleForm.minBo" placeholder="请输入最低血氧" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="户外模式上传频率:" style="width: 100%">
<el-select placeholder="请选择上传频率">
<el-option label="30s" :value="0" />
<el-option label="1分钟" :value="1" />
<el-option label="2分钟" :value="2" />
<el-option label="3分钟" :value="3" />
<el-option label="10分钟" :value="4" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>

View File

@ -5,7 +5,7 @@
<TableCustom :columns="columns" :tableData="tableData" :paging="paging" :refresh="getData" :changePage="changePage">
<template #toolbarBtn>
<el-button type="primary" @click="typeVisible = true">类型编辑</el-button>
<el-button type="primary" @click="handelRow('add')">新增用户</el-button>
<el-button type="primary" @click="handleRow('add')">新增用户</el-button>
<el-button @click="handleImp">批量创建用户</el-button>
<!-- <el-button>导出</el-button> -->
<!-- <el-button type="danger">删除</el-button> -->
@ -18,7 +18,7 @@
<template #roleId="{ rows }">
{{ roleEnum[rows.roleId] }}
</template>
<!--
<!--
<template #password="{ rows }">
<div v-if="rows.flag" @click="rows.flag = false">
{{ rows.password }}
@ -31,9 +31,9 @@
</template> -->
<template #operator="{ rows }">
<el-button link type="primary" size="small" @click="handelRow('pwd', rows)"> 重置密码 </el-button>
<el-button link type="primary" size="small" @click="handelRow('edit', rows)"> 修改 </el-button>
<el-button link type="danger" size="small" @click="handelDel(rows)"> 删除 </el-button>
<el-button link type="primary" size="small" @click="handleRow('pwd', rows)"> 重置密码 </el-button>
<el-button link type="primary" size="small" @click="handleRow('edit', rows)"> 修改 </el-button>
<el-button link type="danger" size="small" @click="handleDel(rows)"> 删除 </el-button>
</template>
</TableCustom>
</div>
@ -85,7 +85,6 @@ enum roleEnum {
"辅警" = 2,
"协警" = 3,
}
const comm = useCommonStore();
const visible = ref(false);
const visible1 = ref(false);
@ -184,7 +183,7 @@ const getOrgAllList = () => {
});
};
//
const handelDel = (row: TableItem) => {
const handleDel = (row: TableItem) => {
ElMessageBox.confirm("确定要删除吗?", "提示", {
type: "warning",
}).then(async () => {
@ -238,7 +237,7 @@ const closeDialog = () => {
visible.value = false;
};
const handelRow = (name: string, row?: TAccount.IListRes) => {
const handleRow = (name: string, row?: TAccount.IListRes) => {
if (name == "add") {
dialogTitle.value = "新增用户";
rowData.value = undefined;