2025年04月08日18:31:36
This commit is contained in:
parent
dab5da7c1e
commit
347feb8eb5
3
components.d.ts
vendored
3
components.d.ts
vendored
@ -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']
|
||||
}
|
||||
}
|
||||
|
44
src/api/index.d.ts
vendored
44
src/api/index.d.ts
vendored
@ -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
|
||||
@ -208,4 +249,5 @@ export interface statisticsContentRes {
|
||||
railArr: any[],
|
||||
destroyArr: any[],
|
||||
healthArr: any[],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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"> 当前指标:</div>
|
||||
<div class="value">38.4℃</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 最大值:</div>
|
||||
<div class="value">38.4℃</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 最小值:</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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
.card-head {
|
||||
color: #061451;
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -27,6 +27,7 @@ const { list } = defineProps({
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
console.log(list, "list1111");
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.monitoring-top {
|
||||
|
@ -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;
|
||||
|
48
src/views/statisticalCenter/statisticsWarning.vue
Normal file
48
src/views/statisticalCenter/statisticsWarning.vue
Normal 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>
|
@ -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>
|
||||
|
@ -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;
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user