2025年04月08日18:31:36

This commit is contained in:
luojiayi 2025-04-08 18:31:37 +08:00
parent dab5da7c1e
commit 347feb8eb5
19 changed files with 511 additions and 304 deletions

3
components.d.ts vendored
View File

@ -55,4 +55,7 @@ declare module '@vue/runtime-core' {
TableSearch: typeof import('./src/components/table-search.vue')['default']
UploadImg: typeof import('./src/components/upload-img.vue')['default']
}
export interface ComponentCustomProperties {
vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
}
}

42
src/api/index.d.ts vendored
View File

@ -158,6 +158,8 @@ export namespace TDevice {
export namespace TOrg {
export interface IAdd {
name: string;
@ -182,6 +184,38 @@ export namespace TOrg {
}
}
export namespace TWarnRecord {
export interface IListReq extends Ipaging {
deviceId?: string;
warnType?: number;
status?: number;
}
export interface IListRes {
id: number
userNumber: string
deviceId: string
warnType: number
type: number
address: string
lng: number
lat: number
status: number
updateUser: string
updateTime: string
creatUser: string
createTime: string
rimg: string
rname: string
rcontent: string
}
}
export interface TStatisticsDevice {
addCount: number
deviceTotal: number
@ -189,6 +223,13 @@ export interface TStatisticsDevice {
warnCount: number
}
export interface TStatisticsCount {
addCount: number
deviceTotal: number
onlineCount: number
warnCount: number
}
export interface statisticsContentReq {
type: string
startDate: string
@ -209,3 +250,4 @@ export interface statisticsContentRes {
destroyArr: any[],
healthArr: any[],
}

View File

@ -1,5 +1,5 @@
import request from '../utils/request';
import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes } from "./index.d";
import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes, TStatisticsCount, TWarnRecord } from "./index.d";
export const fetchLogin = (p: TLogin.Ireq): Promise<TLogin.IRes> => {
return request({
@ -207,3 +207,30 @@ export const statisticsContent = (p: statisticsContentReq): Promise<statisticsCo
data: p
});
};
// 获取统计数据
export const statisticsCount = (): Promise<TStatisticsCount> => {
return request({
url: '/v1/web/statistics/count',
method: 'get',
});
};
// 告警统计
export const statisticsWarningapi = (): Promise<statisticsContentRes> => {
return request({
url: '/v1/web/statistics/warning',
method: 'get',
});
};
// 预警记录
export const warnRecord = (p: TWarnRecord.IListReq): Promise<IpagingRes<TWarnRecord.IListRes>> => {
return request({
url: '/v1/web/warn/record',
method: 'get',
params: p
});
};

View File

@ -7,7 +7,7 @@
{{ item }}{{ index != tab.list.length - 1 ? " / " : "" }}
</div>
</div>
<div class="web-time">{{ format(time) }}</div>
<div class="web-time">{{ format(time) }} 更新</div>
</div>
<div class="header-right">
<div class="header-user-con">
@ -133,7 +133,7 @@ const setFullScreen = () => {
height: 100%;
.web-title {
color: #838ca9;
font-size: 20px;
font-size: 18px;
display: flex;
align-items: center;
&::before {

View File

@ -176,6 +176,7 @@ const collapseChage = () => {
margin: 0 auto;
display: flex;
align-items: center;
// font-size: 18px;
.icon {
background-image: var(--icon);
background-repeat: no-repeat;
@ -215,6 +216,9 @@ const collapseChage = () => {
border-radius: 6px;
width: 228px;
margin: 0 auto;
// span {
// font-size: 18px;
// }
.icon {
background-image: var(--icon);
background-repeat: no-repeat;

View File

@ -23,21 +23,19 @@ service.interceptors.request.use(
service.interceptors.response.use(
(response: AxiosResponse) => {
const { data, headers } = response;
if (headers['content-type'] == 'application/json') {
if (data.code !== 200) {
ElMessage.error(data.msg)
if (data.code !== 200) {
ElMessage.error(data.msg)
if (data.code === 1003) {
const comm = useCommonStore();
comm.clearStore()
router.replace('/login');
}
return Promise.reject(data);
} else {
return data.data;
if (data.code === 1003) {
const comm = useCommonStore();
comm.clearStore()
router.replace('/login');
}
return Promise.reject(data);
} else {
return data.data
}
return data;
},
(error: AxiosError) => {
console.log(error);

View File

@ -2,18 +2,17 @@
<div class="container">
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
<div class="table-container">
<TableCustom :columns="columns" :tableData="tableData" :total="page.total" :refresh="getData" :currentPage="page.index" :changePage="changePage">
<template #money="{ rows }"> {{ rows.money }} </template>
<template #thumb="{ rows }">
<el-image class="table-td-thumb" :src="rows.thumb" :z-index="10" :preview-src-list="[rows.thumb]" preview-teleported> </el-image>
</template>
<template #state="{ rows }">
<el-tag :type="rows.state ? 'success' : 'danger'">
{{ rows.state ? "正常" : "异常" }}
<TableCustom :columns="columns" :tableData="tableData" :total="paging.total" :refresh="getData" :currentPage="paging.page" :changePage="changePage">
<template #status="{ rows }">
<el-tag :type="rows.status == 1 ? 'success' : 'danger'">
{{ statusEnum[rows.status] }}
</el-tag>
</template>
<template #operator>
<el-button type="primary" size="small" link @click="router.push('/incidentDispose')"> 处理事件 </el-button>
<template #warnType="{ rows }">
{{ warnTypeEnum[rows.warnType] }}
</template>
<template #operator="{ rows }">
<el-button type="primary" size="small" link @click="toIncidentDispose(rows.deviceId)"> 处理事件 </el-button>
</template>
</TableCustom>
</div>
@ -22,14 +21,27 @@
<script setup lang="ts" name="basetable">
import { ref, reactive } from "vue";
import { ElMessage } from "element-plus";
import { fetchData } from "@/api/index";
import { warnRecord } from "@/api/index";
import { TWarnRecord } from "@/api/index.d";
import TableCustom from "@/components/table-custom.vue";
import TableDetail from "@/components/table-detail.vue";
import TableSearch from "@/components/table-search.vue";
import { TableItem } from "@/types/table";
import { useRouter } from "vue-router";
import { FormOption, FormOptionList } from "@/types/form-option";
import { FormOptionList } from "@/types/form-option";
enum statusEnum {
"待处理",
"已处理",
}
enum warnTypeEnum {
"SOS告警",
"围栏告警",
"破坏告警",
"低电告警",
"心率告警",
"血氧告警",
"体温告警",
}
const router = useRouter();
//
const query = reactive({
@ -42,10 +54,10 @@ const searchOpt = ref<FormOptionList[]>([
{
type: "select",
label: "处理状态:",
prop: "name4",
prop: "status",
opts: [
{ label: "已处理", value: "1" },
{ label: "未处理", value: "0" },
{ label: "已处理", value: "1" },
],
},
{ type: "daterange", label: "创建时间:", prop: "name5" },
@ -57,33 +69,40 @@ const handleSearch = () => {
//
let columns = ref([
{ type: "index", label: "序号", width: 55, align: "center" },
{ prop: "name", label: "手铐IMEI号" },
{ prop: "name", label: "关联人员" },
{ prop: "name", label: "事件类型" },
{ prop: "money", label: "事件级别" },
{ prop: "thumb", label: "时间" },
{ prop: "state", label: "处理状态" },
{ prop: "deviceId", label: "手铐IMEI号" },
{ prop: "userNumber", label: "关联人员" },
{ prop: "warnType", label: "事件类型" },
{ prop: "createTime", label: "时间" },
{ prop: "status", label: "处理状态" },
{ prop: "operator", label: "操作" },
]);
const page = reactive({
index: 1,
const paging = reactive({
page: 1,
size: 10,
total: 200,
total: 0,
deviceId: undefined,
});
const tableData = ref<TableItem[]>([]);
const tableData = ref<TWarnRecord.IListRes[]>([]);
const getData = async () => {
const res = await fetchData();
tableData.value = res.data.list;
try {
const res = await warnRecord(paging);
tableData.value = res.records;
paging.total = res.total;
} catch (error) {}
};
getData();
const changePage = (val: number) => {
page.index = val;
paging.page = val;
getData();
};
const visible = ref(false);
const toIncidentDispose = (deviceId: string) => {
router.push({
path: "/incidentDispose",
query: { deviceId },
});
};
</script>
<style scoped>

View File

@ -1,26 +1,7 @@
<template>
<div class="container">
<el-row :gutter="20" class="el_row">
<el-col :span="7">
<div class="incidentList">
<div class="tabs">
<div class="tabs-item" :class="`${index == 0 ? 'active' : ''}`" v-for="(item, index) in tabs" :key="index">{{ item.label }}</div>
</div>
<div class="list scrollbar">
<div class="list-item active" v-for="item in 15" :key="item">
<div class="img">
<img :src="handcuffs" alt="" />
</div>
<div class="content">
<div class="content-name">设备序号10</div>
<div class="content-time">2025/03/26 18:33:32</div>
</div>
<el-tag type="warning" size="large">未处理</el-tag>
</div>
</div>
</div>
</el-col>
<el-col :span="10">
<el-col :span="17">
<div class="map-content">
<div class="map" id="mapcontainer"></div>
<div class="chart">
@ -29,57 +10,59 @@
</div>
</el-col>
<el-col :span="7">
<div class="info scrollbar">
<div class="info-text">设备序号05</div>
<div class="info-text">IMEI号860116079430636</div>
<div class="info-text">告警时间2025/03/26 18:33:32</div>
<div class="info-text">告警类型<span style="color: red">体表温度过低</span></div>
<div class="info-text">绑定关联人名称张三</div>
<div class="info-text">绑定关联人警号123456</div>
<div class="info-text">现在状态禁用</div>
<div class="info-text">紧急电话10000000000</div>
<div class="info-text">隶属辖区87</div>
<div class="info-box">
<div class="info-box-title">生理记录</div>
<div class="info-box-contetn">
<div class="item">
<div class="label">血氧</div>
<div class="value">97%</div>
</div>
<div class="item">
<div class="label">体表温度</div>
<div class="value">36.4</div>
</div>
<div class="item">
<div class="label">心率</div>
<div class="value">86 /</div>
<div class="right-content">
<div class="info scrollbar">
<div class="info-text">设备序号05</div>
<div class="info-text">IMEI号860116079430636</div>
<div class="info-text">告警时间2025/03/26 18:33:32</div>
<div class="info-text">告警类型<span style="color: red">体表温度过低</span></div>
<div class="info-text">绑定关联人名称张三</div>
<div class="info-text">绑定关联人警号123456</div>
<div class="info-text">现在状态禁用</div>
<div class="info-text">紧急电话10000000000</div>
<div class="info-text">隶属辖区87</div>
<div class="info-box">
<div class="info-box-title">生理指标</div>
<div class="info-box-contetn">
<div class="item">
<div class="label">&nbsp;&nbsp;当前指标</div>
<div class="value">38.4</div>
</div>
<div class="item">
<div class="label">&nbsp;&nbsp;最大值</div>
<div class="value">38.4</div>
</div>
<div class="item">
<div class="label">&nbsp;&nbsp;最小值</div>
<div class="value">36.4</div>
</div>
</div>
</div>
<div class="info-form">
<el-form :model="formInline" label-position="top">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="处理人:">
<el-input v-model="formInline.user" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="警号:">
<el-input v-model="formInline.user" clearable />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="处理记录:">
<el-input v-model="formInline.user" clearable :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" />
</el-form-item>
<el-form-item label="处理图片:">
<Upload />
</el-form-item>
</el-form>
</div>
</div>
<div class="info-form">
<el-form :model="formInline" label-position="top">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="处理人:">
<el-input v-model="formInline.user" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="警号:">
<el-input v-model="formInline.user" clearable />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="处理记录:">
<el-input v-model="formInline.user" clearable />
</el-form-item>
<el-form-item label="处理图片:">
<Upload />
</el-form-item>
<el-form-item>
<el-button type="primary">保存</el-button>
</el-form-item>
</el-form>
<div class="right-foot">
<el-button type="primary">保存</el-button>
</div>
</div>
</el-col>
@ -93,14 +76,25 @@ import { MapCustom } from "@/utils/mapCustom";
import { onMounted, ref, reactive } from "vue";
import Upload from "@/components/upload-img.vue";
import * as echarts from "echarts";
const chartRef = ref(null);
import { warnRecord } from "@/api/index";
import { TWarnRecord } from "@/api/index.d";
enum statusEnum {
"待处理",
"已处理",
}
const chartRef = ref(null);
let tabs = [
{ label: "全部", value: "0" },
{ label: "未处理", value: "1" },
{ label: "已处理", value: "2" },
{ label: "全部", value: undefined },
{ label: "未处理", value: 0 },
{ label: "已处理", value: 1 },
];
const ringOptions = {
title: {
text: "Stacked Line",
left: "3%",
},
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
@ -127,12 +121,39 @@ const formInline = reactive({
date: "",
});
const paging = reactive({
page: 1,
size: 10,
total: 0,
deviceId: "",
status: undefined,
});
const tableData = ref<TWarnRecord.IListRes[]>([]);
const getData = async () => {
try {
const res = await warnRecord(paging);
tableData.value = res.records;
paging.total = res.total;
} catch (error) {}
};
const load = () => {
paging.page++;
getData();
};
const checkTabs = (item: number | undefined) => {
// paging.status = item;
// paging.page = 1;
// getData();
};
onMounted(() => {
if (chartRef.value) {
const myChart = echarts.init(chartRef.value);
myChart.setOption(ringOptions);
}
new MapCustom({ dom: "mapcontainer" });
// getData();
});
</script>
@ -148,78 +169,7 @@ onMounted(() => {
flex-direction: column;
}
}
.incidentList {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
.tabs {
display: flex;
align-items: center;
height: 54px;
background: #ffffff;
.tabs-item {
cursor: pointer;
flex: 1;
text-align: center;
color: #787878;
font-size: 20px;
&.active {
color: #061451;
position: relative;
&::after {
content: "";
width: 20px;
height: 2px;
border-radius: 5px;
background: #061451;
display: inline-block;
position: absolute;
bottom: -13px;
left: 50%;
transform: translateX(-50%);
}
}
}
}
.list {
flex: 1;
.list-item {
cursor: pointer;
padding: 0 15px;
box-sizing: border-box;
height: 100px;
background-color: #fff;
display: flex;
align-items: center;
margin-top: 14px;
&.active {
border-left: 2px solid #061451;
}
.img {
width: 60px;
height: 60px;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
}
}
.content {
flex: 1;
margin: 0 10px;
.content-name {
color: #061451;
font-size: 20px;
}
.content-time {
color: #787878;
font-size: 18px;
}
}
}
}
}
.map-content {
display: flex;
flex-direction: column;
@ -236,50 +186,66 @@ onMounted(() => {
box-sizing: border-box;
}
}
.info {
background: #ffffff;
height: 100%;
padding: 17px;
box-sizing: border-box;
// overflow: auto;
.info-text {
color: #061451;
font-size: 18px;
margin-bottom: 20px;
}
.info-box {
padding: 20px 0;
border-radius: 3px;
background: #fafafa;
border: 1px solid #e6e6e6;
.right-content {
overflow: hidden;
display: flex;
flex-direction: column;
.info {
background: #ffffff;
height: 100%;
padding: 17px;
box-sizing: border-box;
position: relative;
// overflow: auto;
.info-box-title {
.info-text {
color: #061451;
font-size: 18px;
&::before {
content: "";
width: 2px;
height: 14px;
border-radius: 20px;
background: #061451;
display: inline-block;
margin-right: 9px;
}
margin-bottom: 20px;
}
.info-box-contetn {
padding: 0 11px;
.item {
.info-box {
padding: 20px 0;
border-radius: 3px;
background: #fafafa;
border: 1px solid #e6e6e6;
.info-box-title {
color: #061451;
font-size: 18px;
display: flex;
justify-content: space-between;
margin-top: 20px;
&::before {
content: "";
width: 2px;
height: 14px;
border-radius: 20px;
background: #061451;
display: inline-block;
margin-right: 9px;
}
}
.info-box-contetn {
padding: 0 11px;
.item {
color: #061451;
font-size: 18px;
display: flex;
justify-content: space-between;
margin-top: 20px;
}
}
}
.info-form {
margin-top: 20px;
}
}
.info-form {
margin-top: 20px;
.right-foot {
width: 100%;
padding: 5px 20px;
box-sizing: border-box;
border-top: 1px solid rgba(0, 0, 0, 0.06);
display: flex;
justify-content: flex-end;
background: #fff;
}
}
}

View File

@ -21,7 +21,7 @@
.card-head {
color: #061451;
font-size: 20px;
font-size: 18px;
display: flex;
align-items: center;
justify-content: space-between;

View File

@ -2,7 +2,7 @@
<div class="device">
<div class="device-head">
<div class="title">设备列表</div>
<el-select class="select" size="large">
<el-select class="select">
<el-option label="全部" value="0" />
<el-option label="常规模式" value="1" />
<el-option label="户外押送" value="2" />
@ -80,7 +80,7 @@
margin-top: 14px;
.title {
color: #061451;
font-size: 20px;
font-size: 18px;
&::before {
display: inline-block;
margin-right: 10px;
@ -124,7 +124,7 @@
margin: 0 15px;
.item-content-name {
color: #061451;
font-size: 20px;
font-size: 18px;
}
.item-content-num {
color: #787878;

View File

@ -60,7 +60,7 @@ let columns = [
.card-head {
color: #061451;
font-size: 20px;
font-size: 18px;
display: flex;
align-items: center;
justify-content: space-between;

View File

@ -28,6 +28,7 @@
</div>
</template>
<script setup>
import { format } from "@/utils";
import { ref } from "vue";
const value = ref("");
const value1 = ref("");
@ -39,9 +40,9 @@ const { api } = defineProps({
},
});
const handleWeekChange = (val, res) => {
console.log(val, "handleWeekChange");
api({ type: radioType.value, startDate: `${val} 00:00:00`, endDate: `${val} 00:00:00` });
const handleWeekChange = (val) => {
let time = new Date(val).getTime() + 6 * 24 * 60 * 60 * 1000;
api({ type: radioType.value, startDate: `${val} 00:00:00`, endDate: `${format(time, "YYYY-MM-DD")} 00:00:00` });
};
const handleDateChange = (val) => {
api({ type: radioType.value, startDate: val[0], endDate: val[1] });
@ -62,7 +63,7 @@ const handleDateChange = (val) => {
margin-bottom: 20px;
.card-head {
color: #061451;
font-size: 20px;
font-size: 18px;
display: flex;
align-items: center;
justify-content: space-between;

View File

@ -1,27 +1,38 @@
<template>
<div class="deviceStatistics card">
<div class="card-head">
<div class="title">内容数据</div>
<div class="title">告警列表</div>
<div class="condition">
<el-input style="width: 240px" placeholder="搜索设备IMEI号" :suffix-icon="Search" />
<el-input style="width: 240px" v-model="search" placeholder="搜索设备IMEI号" :suffix-icon="Search" @input="handleInput" />
</div>
</div>
<TableCustom :columns="columns" :tableData="tableData" :total="page.total" :refresh="getData" :currentPage="page.index" :changePage="changePage">
<TableCustom :columns="columns" :tableData="tableData" :total="page.total" :currentPage="page.index" :changePage="changePage">
<template #location="{ rows }">
<el-button type="success" link :icon="View"> 查看 </el-button>
<el-button type="success" link :icon="View" v-if="rows.warnType == 0 || rows.warnType == 1" @click="toIncidentDispose(rows.deviceId)"> 查看 </el-button>
</template>
<template #state="{ rows }">
<el-tag :type="rows.state ? 'success' : 'danger'">
{{ rows.state ? "正常" : "异常" }}
<template #status="{ rows }">
<el-tag :type="rows.status == 1 ? 'success' : 'danger'">
{{ statusEnum[rows.status] }}
</el-tag>
</template>
</TableCustom>
</div>
</template>
<script setup>
<script setup lang="ts">
import { ref } from "vue";
import { Search, View } from "@element-plus/icons-vue";
defineProps({
import { debounce } from "@/utils";
import { useRouter } from "vue-router";
import { TWarnRecord } from "@/api/index.d";
const router = useRouter();
enum statusEnum {
"待处理",
"已处理",
}
const search = ref("");
const { tableData, page, getData, changePage } = defineProps({
tableData: {
type: Array,
default: () => [],
@ -42,11 +53,22 @@ defineProps({
//
let columns = [
{ type: "index", label: "序号", width: 55, align: "center" },
{ prop: "name", label: "IMEI号" },
{ prop: "time", label: "时间" },
{ prop: "deviceId", label: "IMEI号" },
{ prop: "createTime", label: "时间" },
{ prop: "location", label: "地理位置" },
{ prop: "state", label: "处理状态" },
{ prop: "status", label: "处理状态" },
];
const handleInput = debounce((e) => {
page.deviceId = e;
getData();
}, 500);
const toIncidentDispose = (deviceId: string) => {
router.push({
path: "/incidentDispose",
query: { deviceId },
});
};
</script>
<style scoped lang="less">
.card {
@ -62,7 +84,7 @@ let columns = [
margin-bottom: 20px;
.card-head {
color: #061451;
font-size: 20px;
font-size: 18px;
display: flex;
align-items: center;
justify-content: space-between;

View File

@ -19,14 +19,14 @@
</el-row>
<el-row :gutter="20">
<el-col class="elcol" :span="16" :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
<EmergencyList :tableData="tableData" :page="page" :getData="getData" :changePage="changePage"></EmergencyList>
<EmergencyList :tableData="tableData" :page="paging" :getData="getData" :changePage="changePage"></EmergencyList>
</el-col>
<el-col class="elcol" :span="8" :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
<OnLineStatistics>
<StatisticsWarning>
<template #chart>
<div ref="chartRef2" style="width: 100%; height: 100%"></div>
</template>
</OnLineStatistics>
</StatisticsWarning>
</el-col>
</el-row>
</div>
@ -35,14 +35,14 @@
import MonitoringTop from "./monitoringTop.vue";
import DeviceHistory from "./deviceHistory.vue";
import OnLineStatistics from "./onLineStatistics.vue";
import StatisticsWarning from "./statisticsWarning.vue";
import EmergencyList from "./emergencyList.vue";
import * as echarts from "echarts";
import { MapCustom } from "@/utils/mapCustom";
import { fetchData, statisticsDevice, statisticsContent } from "@/api/index";
import { TableItem } from "@/types/table";
import { statisticsDevice, statisticsContent, statisticsCount, statisticsWarningapi, warnRecord } from "@/api/index";
import { onMounted, ref, reactive, onDeactivated } from "vue";
import { debounce } from "@/utils";
import { TStatisticsDevice } from "@/api/index.d";
import { TWarnRecord } from "@/api/index.d";
import handcuffs from "@/assets/img/handcuffs.png";
import onLine from "@/assets/img/onLine.png";
import report from "@/assets/img/report.png";
@ -63,69 +63,142 @@ let funcList = ref([
{ title: "较昨日新增", en: "JIAOZUORIXINZENG", icon: newly, num: 0, color: "#FF6905" },
]);
const option = {
const option = ref({
tooltip: {
trigger: "axis",
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
boundaryGap: false,
data: [],
},
yAxis: {
type: "value",
},
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: "line",
smooth: true,
},
],
};
let option1 = {
series: [],
});
let option1 = ref({
tooltip: {
trigger: "item",
},
legend: {
right: "left",
},
series: [
{
name: "Access From",
type: "pie",
radius: ["20%", "50%"],
data: [
{ value: 1048, name: "常规模式" },
{ value: 735, name: "户外押送" },
{ value: 580, name: "审讯模式" },
],
},
],
};
const page = reactive({
index: 1,
size: 10,
total: 200,
series: {
type: "pie",
radius: ["20%", "50%"],
data: [
{ value: 1048, name: "常规模式" },
{ value: 735, name: "户外押送" },
{ value: 580, name: "审讯模式" },
],
},
});
let option2 = ref({
tooltip: {
trigger: "item",
},
legend: {
right: "left",
},
series: {
type: "pie",
radius: ["20%", "50%"],
data: [
{ value: 0, name: "SOS告警" },
{ value: 0, name: "围栏告警" },
{ value: 0, name: "破坏告警" },
{ value: 0, name: "低电告警" },
{ value: 0, name: "心率告警" },
{ value: 0, name: "血氧告警" },
{ value: 0, name: "体温告警" },
],
},
});
const tableData = ref<TableItem[]>([]);
const paging = reactive({
page: 1,
size: 10,
total: 0,
deviceId: "",
});
const tableData = ref<TWarnRecord.IListRes[]>([]);
const getData = async () => {
const res = await fetchData();
tableData.value = res.data.list;
try {
const res = await warnRecord(paging);
tableData.value = res.records;
paging.total = res.total;
} catch (error) {}
};
const getStatisticsDevice = () => {
statisticsDevice().then((res) => {
funcList.value[0].num = res.deviceTotal;
funcList.value[1].num = res.onlineCount;
funcList.value[2].num = res.warnCount;
funcList.value[3].num = res.addCount;
statisticsDevice().then((res) => {});
};
const getStatisticsWarningApi = () => {
statisticsWarningapi().then((res) => {
option1.value.series.data = [
{ value: res?.sosCount, name: "SOS告警" },
{ value: res?.railCount, name: "围栏告警" },
{ value: res?.destroyCount, name: "破坏告警" },
{ value: res?.batteryCount, name: "低电告警" },
{ value: res?.heartRateCount, name: "心率告警" },
{ value: res?.bloodOxygenCount, name: "血氧告警" },
{ value: res?.tempCount, name: "体温告警" },
];
myChart2.setOption(option2.value);
});
};
const getStatisticsContent = (res) => {
statisticsContent(res).then((res) => {});
statisticsContent(res).then((res) => {
option.value.xAxis.data = res?.times;
option.value.series = [
{
stack: "Total",
name: "SOS预警数组",
data: res?.sosArr,
type: "line",
},
{
stack: "Total",
name: "围栏预警数组",
data: res?.railArr,
type: "line",
},
{
stack: "Total",
name: "破坏预警数组",
data: res?.destroyArr,
type: "line",
},
{
stack: "Total",
name: "生理预警数组",
data: res?.healthArr,
type: "line",
},
];
});
myChart.setOption(option.value);
};
const getStatisticsCount = () => {
statisticsCount().then((res) => {
funcList.value[0].num = res?.deviceTotal || 0;
funcList.value[1].num = res?.onlineCount || 0;
funcList.value[2].num = res?.warnCount || 0;
funcList.value[3].num = res?.addCount || 0;
});
};
const changePage = (val: number) => {
page.index = val;
paging.page = val;
getData();
};
@ -137,19 +210,21 @@ const handleResize = debounce(() => {
onMounted(() => {
getData();
getStatisticsDevice();
getStatisticsCount();
getStatisticsWarningApi();
new MapCustom({ dom: "mapcontainer" });
if (chartRef.value) {
myChart = echarts.init(chartRef.value);
myChart.setOption(option);
myChart.setOption(option.value);
myChart1 = echarts.init(chartRef1.value);
myChart1.setOption(option1);
myChart2 = echarts.init(chartRef2.value);
myChart2.setOption(option1);
myChart2.setOption(option2.value);
window.addEventListener("resize", handleResize);
}
});

View File

@ -27,6 +27,7 @@ const { list } = defineProps({
default: () => [],
},
});
console.log(list, "list1111");
</script>
<style scoped lang="less">
.monitoring-top {

View File

@ -1,7 +1,7 @@
<template>
<div class="deviceStatistics card">
<div class="card-head">
<div class="title">告警占比</div>
<div class="title">在线设备统计</div>
</div>
<slot name="chart"></slot>
</div>
@ -22,7 +22,7 @@
.card-head {
position: absolute;
color: #061451;
font-size: 20px;
font-size: 18px;
display: flex;
align-items: center;
justify-content: space-between;

View File

@ -0,0 +1,48 @@
<template>
<div class="deviceStatistics card">
<div class="card-head">
<div class="title">告警占比</div>
</div>
<slot name="chart"></slot>
</div>
</template>
<script setup></script>
<style scoped lang="less">
.card {
height: 100%;
background: #ffffff;
padding: 16px 10px;
box-sizing: border-box;
position: relative;
display: flex;
border-radius: 5px;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
margin-bottom: 20px;
.card-head {
position: absolute;
color: #061451;
font-size: 18px;
display: flex;
align-items: center;
justify-content: space-between;
transform: translateX(-10px);
margin-bottom: 20px;
.title {
&::before {
display: inline-block;
margin-right: 10px;
content: "";
width: 2px;
height: 14px;
border-radius: 20px;
background: #061451;
}
}
.search {
display: flex;
align-items: center;
}
}
}
</style>

View File

@ -29,20 +29,21 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="模式选择:">
<el-select placeholder="请选择模式" v-model="modelValue.monitorMode" style="width: 240px" @change="handelControl(5)">
<el-option label="审讯模式" :value="0" />
<el-option label="户外押送" :value="1" />
<el-select placeholder="请选择模式" v-model="modelValue.monitorMode" style="width: 230px" @change="handelControl(5)">
<el-option label="常规模式" :value="0" />
<el-option label="审讯模式" :value="1" />
<el-option label="户外押送模式" :value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <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-col> -->
</el-row>
</el-form>
</template>

View File

@ -182,7 +182,7 @@ const changePage = (val: number) => {
};
const roleListFn = () => {
roleList().then((res) => {
let opts = res.map((item) => {
let opts = res?.map((item) => {
return { label: item.name, value: item.id };
});
addOpt.list[3].opts = opts;
@ -190,7 +190,7 @@ const roleListFn = () => {
};
const getData = async () => {
const res = await accountList(paging);
tableData.value = res.records.map((item) => {
tableData.value = res.records?.map((item) => {
item.flag = false;
return item;
});