2025年04月09日18:45:43

This commit is contained in:
luojiayi 2025-04-09 18:45:44 +08:00
parent 347feb8eb5
commit 5f0cda3d45
15 changed files with 519 additions and 263 deletions

4
components.d.ts vendored
View File

@ -9,7 +9,9 @@ declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
Alarm: typeof import('./src/components/alarm.vue')['default'] Alarm: typeof import('./src/components/alarm.vue')['default']
BatchImp: typeof import('./src/components/batch-imp.vue')['default'] BatchImp: typeof import('./src/components/batch-imp.vue')['default']
copy: typeof import('./src/components/upload-img copy.vue')['default']
Countup: typeof import('./src/components/countup.vue')['default'] Countup: typeof import('./src/components/countup.vue')['default']
CustomInput: typeof import('./src/components/CustomInput.vue')['default']
DeviceInfo: typeof import('./src/components/deviceInfo.vue')['default'] DeviceInfo: typeof import('./src/components/deviceInfo.vue')['default']
ElAvatar: typeof import('element-plus/es')['ElAvatar'] ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
@ -54,8 +56,10 @@ declare module '@vue/runtime-core' {
TableEdit: typeof import('./src/components/table-edit.vue')['default'] TableEdit: typeof import('./src/components/table-edit.vue')['default']
TableSearch: typeof import('./src/components/table-search.vue')['default'] TableSearch: typeof import('./src/components/table-search.vue')['default']
UploadImg: typeof import('./src/components/upload-img.vue')['default'] UploadImg: typeof import('./src/components/upload-img.vue')['default']
UploadImgsa: typeof import('./src/components/upload-imgsa.vue')['default']
} }
export interface ComponentCustomProperties { export interface ComponentCustomProperties {
vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll'] vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
} }
} }

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

@ -15,6 +15,86 @@ export interface TRoleList {
createTime: string createTime: string
} }
export interface TStatisticsDevice {
addCount: number
deviceTotal: number
onlineCount: number
warnCount: number
}
export interface TStatisticsCount {
addCount: number
deviceTotal: number
onlineCount: number
warnCount: number
}
export interface statisticsContentReq {
type: string
startDate: string
endDate: string
}
export interface statisticsContentRes {
sosCount: number
railCount: number
destroyCount: number
batteryCount: number
heartRateCount: number
bloodOxygenCount: number
tempCount: number
times: any[],
sosArr: any[],
railArr: any[],
destroyArr: any[],
healthArr: any[],
}
export interface TWarningConfirm {
id?: number | string
name: string
username: string
content: string
images: string[]
}
export interface TDeviceConfigModify {
deviceId: string | string[]
userNumber: string
minHr: number
maxHr: number
minBo: number
minTemp: number
maxTemp: number
contacts: any[]
}
export namespace TDeviceConfig {
interface Treq {
deviceId: string | string[]
}
interface Tcontacts {
name: string
phone: string
}
interface Tres {
deviceId: string | string[]
userNumber: string
minHr: number
minBo: number
minTemp: number
maxTemp: number
maxHr: number
name?: string
phone?: string
contacts: Tcontacts[]
}
}
export namespace TLogin { export namespace TLogin {
export interface Ireq { export interface Ireq {
username: string; username: string;
@ -103,7 +183,7 @@ export namespace TDevice {
} }
export interface IRecordReq extends Ipaging { export interface IRecordReq extends Ipaging {
deviceId?: number; deviceId?: string | string[];
} }
export interface IRecordRes { export interface IRecordRes {
id: number id: number
@ -212,42 +292,34 @@ export namespace TWarnRecord {
} }
} }
export namespace TWarningDetail {
interface TParams {
id: number | string
export interface TStatisticsDevice {
addCount: number
deviceTotal: number
onlineCount: number
warnCount: number
} }
interface TRes {
export interface TStatisticsCount { address: string
addCount: number adminName: string
deviceTotal: number adminPhone: string
onlineCount: number creatUser: string
warnCount: number createTime: string
deviceId: string
healthData: string
id: number
lat: number
lng: number
maxValue: number
minValue: number
rcontent: string
rimg: any
rname: string
status: number
type: number
updateTime: string
updateUser: string
userNumber: string
username: string
value: string
orgName: string
warnType: number
} }
export interface statisticsContentReq {
type: string
startDate: string
endDate: string
} }
export interface statisticsContentRes {
sosCount: number
railCount: number
destroyCount: number
batteryCount: number
heartRateCount: number
bloodOxygenCount: number
tempCount: number
times: any[],
sosArr: any[],
railArr: any[],
destroyArr: any[],
healthArr: any[],
}

View File

@ -1,5 +1,5 @@
import request from '../utils/request'; import request from '../utils/request';
import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes, TStatisticsCount, TWarnRecord } from "./index.d"; import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes, TStatisticsCount, TWarnRecord, TWarningDetail, TWarningConfirm, TDeviceConfigModify, TDeviceConfig } from "./index.d";
export const fetchLogin = (p: TLogin.Ireq): Promise<TLogin.IRes> => { export const fetchLogin = (p: TLogin.Ireq): Promise<TLogin.IRes> => {
return request({ return request({
@ -116,7 +116,7 @@ export const setMode = (p: TDevice.ISetMonitor): Promise<null> => {
// 获取定位 // 获取定位
export const deviceGetLocation = (p: TDevice.ISetMonitor): Promise<null> => { export const deviceGetLocation = (p: TDevice.ISetMonitor): Promise<null> => {
return request({ return request({
url: '/v1/web/device/getLocation', url: '/v1/web/device/getLocate',
method: 'post', method: 'post',
data: p data: p
}); });
@ -143,7 +143,7 @@ export const deviceUseRecord = (p: TDevice.IRecordReq): Promise<IpagingRes<TDevi
// 预警记录 // 预警记录
export const warningRecord = (p: TDevice.IRecordReq): Promise<IpagingRes<TDevice.IWarningRecordRes>> => { export const warningRecord = (p: TDevice.IRecordReq): Promise<IpagingRes<TDevice.IWarningRecordRes>> => {
return request({ return request({
url: '/v1/web/device/warning/record', url: '/v1/web/warning/record',
method: 'get', method: 'get',
params: p params: p
}); });
@ -186,7 +186,7 @@ export const orgDelete = (p?: TOrg.Idel): Promise<null> => {
// 获取角色列表 // 获取角色列表
export const roleList = (): Promise<TRoleList[]> => { export const roleList = (): Promise<TRoleList[]> => {
return request({ return request({
url: '/v1/web/account/role/list', url: '/v1/web/role/list',
method: 'get', method: 'get',
}); });
}; };
@ -227,10 +227,46 @@ export const statisticsWarningapi = (): Promise<statisticsContentRes> => {
// 预警记录 // 预警记录
export const warnRecord = (p: TWarnRecord.IListReq): Promise<IpagingRes<TWarnRecord.IListRes>> => { export const warnRecord = (p: TWarnRecord.IListReq): Promise<IpagingRes<TWarnRecord.IListRes>> => {
return request({ return request({
url: '/v1/web/warn/record', url: '/v1/web/warning/record',
method: 'get', method: 'get',
params: p params: p
}); });
}; };
// 预警记录
export const warningDetail = (p: TWarningDetail.TParams): Promise<TWarningDetail.TRes> => {
return request({
url: '/v1/web/warning/detail',
method: 'get',
params: p
});
};
// 预警记录
export const warningConfirm = (p: TWarningConfirm): Promise<null> => {
return request({
url: '/v1/web/warning/confirm',
method: 'post',
data: p
});
};
// 获取专项配置
export const deviceConfig = (p: TDeviceConfig.Treq): Promise<TDeviceConfig.Tres> => {
return request({
url: '/v1/web/device/deviceConfig',
method: 'get',
params: p
});
};
// 修改专项配置
export const deviceConfigModify = (p: TDeviceConfigModify): Promise<null> => {
return request({
url: '/v1/web/device/deviceConfig/modify',
method: 'post',
data: p
});
};

BIN
src/assets/img/location.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,12 +1,17 @@
<template> <template>
<el-upload <el-upload
v-model:file-list="fileList"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:style="`--width: ${size}px; --height: ${size}px`" :style="`--width: ${size}px; --height: ${size}px`"
class="upload" class="upload"
accept="image/*"
list-type="picture-card"
v-model:file-list="fileList"
:action="ACTION"
:headers="HEADERS"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:limit="9"
:before-upload="beforeUpload"
> >
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</el-upload> </el-upload>
@ -19,31 +24,57 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import { Plus } from "@element-plus/icons-vue"; import { Plus } from "@element-plus/icons-vue";
import type { UploadProps, UploadUserFile } from "element-plus"; import { ElMessage, UploadProps } from "element-plus";
const { size } = defineProps({ import { useCommonStore } from "@/store/common";
interface Tdata {
code: number;
data: {
imeUrl: string;
};
msg: string;
}
const comm = useCommonStore();
const ACTION = import.meta.env.VITE_APP_URL + "/v1/web/upload/warning/img";
const HEADERS = {
"Access-Token": comm.user.token,
};
const { size, modelValue } = defineProps({
size: { size: {
type: Number, type: Number,
default: 100, default: 100,
}, },
modelValue: {
type: Array,
default: () => [],
},
}); });
const fileList = ref<UploadUserFile[]>([ const emit = defineEmits(["update:modelValue"]);
{
name: "food.jpeg",
url: "https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100",
},
{ const fileList = ref<any[]>([]);
name: "food.jpeg",
url: "https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100",
},
]);
const dialogImageUrl = ref(""); const dialogImageUrl = ref("");
const dialogVisible = ref(false); const dialogVisible = ref(false);
const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => { const beforeUpload = (rawFile: any) => {
console.log(uploadFile, uploadFiles); const isLtSize = rawFile.size / 1024 / 1024 < 5;
if (!isLtSize) {
ElMessage.error("上传图片大小不能超过 5MB!");
return false;
}
return true;
};
const handleSuccess = ({ code, data, msg }: Tdata) => {
if (code != 200) return ElMessage.error(msg);
let list = fileList.value.map((item) => item?.response?.data?.imeUrl);
emit("update:modelValue", list);
};
const handleRemove: UploadProps["onRemove"] = () => {
let list = fileList.value.map((item) => item?.response?.data?.imeUrl);
emit("update:modelValue", list);
}; };
const handlePictureCardPreview: UploadProps["onPreview"] = (uploadFile) => { const handlePictureCardPreview: UploadProps["onPreview"] = (uploadFile) => {

View File

@ -11,15 +11,6 @@
</keep-alive> </keep-alive>
</transition> </transition>
</router-view> </router-view>
<!-- <el-scrollbar>
<router-view v-slot="{ Component }">
<transition name="move" mode="out-in">
<keep-alive>
<component :is="Component"></component>
</keep-alive>
</transition>
</router-view>
</el-scrollbar> -->
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@ export class MapCustom {
this.map = new AMap.Map(data.dom, { this.map = new AMap.Map(data.dom, {
version: "1.4.15", version: "1.4.15",
zoom: 13, zoom: 13,
center: [116.397428, 39.90923], //初始化地图中心点 center: data.center || [116.397428, 39.90923], //初始化地图中心点
...data, ...data,
}); });
} }
@ -102,6 +102,25 @@ export class MapCustom {
}) })
} }
newIcon(url) {
return new AMap.Icon({
size: new AMap.Size(36, 42),
image: url, // Icon的图像
imageSize: new AMap.Size(36, 42)
})
}
// 创建marker
marker({ icon, position }) {
return new AMap.Marker({
icon,
position,
map: this.map,
offset: new AMap.Pixel(-25, -50),
})
}
lngLat(lng, lat) {
return new AMap.LngLat(lng, lat);
}
clearMap() { clearMap() {
this.map.clearMap(); this.map.clearMap();

View File

@ -15,7 +15,6 @@ service.interceptors.request.use(
return config; return config;
}, },
(error: AxiosError) => { (error: AxiosError) => {
console.log(error);
return Promise.reject(); return Promise.reject();
} }
); );
@ -38,7 +37,6 @@ service.interceptors.response.use(
}, },
(error: AxiosError) => { (error: AxiosError) => {
console.log(error);
return Promise.reject(); return Promise.reject();
} }
); );

View File

@ -12,7 +12,7 @@
{{ warnTypeEnum[rows.warnType] }} {{ warnTypeEnum[rows.warnType] }}
</template> </template>
<template #operator="{ rows }"> <template #operator="{ rows }">
<el-button type="primary" size="small" link @click="toIncidentDispose(rows.deviceId)"> 处理事件 </el-button> <el-button type="primary" size="small" link @click="toIncidentDispose(rows.id)"> 处理事件 </el-button>
</template> </template>
</TableCustom> </TableCustom>
</div> </div>

View File

@ -12,57 +12,61 @@
<el-col :span="7"> <el-col :span="7">
<div class="right-content"> <div class="right-content">
<div class="info scrollbar"> <div class="info scrollbar">
<div class="info-text">设备序号05</div> <div class="info-text">设备序号{{ curData.id }}</div>
<div class="info-text">IMEI号860116079430636</div> <div class="info-text">IMEI号{{ curData.deviceId }}</div>
<div class="info-text">告警时间2025/03/26 18:33:32</div> <div class="info-text">告警时间{{ curData.createTime }}</div>
<div class="info-text">告警类型<span style="color: red">体表温度过低</span></div> <div class="info-text">
<div class="info-text">绑定关联人名称张三</div> 告警类型<span style="color: red">{{ warnTypeEnum[curData.warnType] }}</span>
<div class="info-text">绑定关联人警号123456</div> </div>
<div class="info-text">现在状态禁用</div> <div class="info-text">绑定关联人名称{{ curData.username }}</div>
<div class="info-text">紧急电话10000000000</div> <div class="info-text">绑定关联人警号{{ curData.userNumber }}</div>
<div class="info-text">隶属辖区87</div> <div class="info-text">状态{{ statusEnum[curData.status] }}</div>
<div class="info-box"> <div class="info-text">紧急电话{{ curData.adminPhone }}</div>
<div class="info-text">隶属辖区{{ curData.orgName }}</div>
<div class="info-box" v-if="curData.type == 1">
<div class="info-box-title">生理指标</div> <div class="info-box-title">生理指标</div>
<div class="info-box-contetn"> <div class="info-box-contetn">
<div class="item"> <div class="item">
<div class="label">&nbsp;&nbsp;当前指标</div> <div class="label">&nbsp;&nbsp;当前指标</div>
<div class="value">38.4</div> <div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
</div> </div>
<div class="item"> <div class="item" v-if="curData.warnType == 5">
<div class="label">&nbsp;&nbsp;最大值</div> <div class="label">&nbsp;&nbsp;最大值</div>
<div class="value">38.4</div> <div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
</div> </div>
<div class="item"> <div class="item">
<div class="label">&nbsp;&nbsp;最小值</div> <div class="label">&nbsp;&nbsp;最小值</div>
<div class="value">36.4</div> <div class="value">{{ curData.maxValue }}{{ unitEnum[curData.warnType] }}</div>
</div> </div>
</div> </div>
</div> </div>
<div class="info-form"> <div class="info-form">
<el-form :model="formInline" label-position="top"> <el-form :model="ruleForm" :rules="rules" ref="ruleFormRef" label-position="top">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="处理人:"> <el-form-item label="处理人:" prop="name">
<el-input v-model="formInline.user" clearable /> <el-input v-model="ruleForm.name" clearable :disabled="curData.status == 1" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="警号:"> <el-form-item label="警号:" prop="username">
<el-input v-model="formInline.user" clearable /> <el-input v-model="ruleForm.username" clearable :disabled="curData.status == 1" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="处理记录:"> <el-form-item label="处理记录:" prop="content">
<el-input v-model="formInline.user" clearable :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" /> <el-input v-model="ruleForm.content" clearable :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" :disabled="curData.status == 1" />
</el-form-item> </el-form-item>
<el-form-item label="处理图片:"> <el-form-item label="处理图片:" prop="images">
<Upload /> <Upload v-model="ruleForm.images" :disabled="curData.status == 1" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</div> </div>
<div class="right-foot"> <div class="right-foot">
<el-button type="primary">保存</el-button> <el-button type="primary" @click="submitForm(ruleFormRef)">保存</el-button>
</div> </div>
</div> </div>
</el-col> </el-col>
@ -71,24 +75,39 @@
</template> </template>
<script setup lang="ts" name="incidentDispose"> <script setup lang="ts" name="incidentDispose">
import handcuffs from "@/assets/img/handcuffs.png"; import location from "@/assets/img/location.png";
import { MapCustom } from "@/utils/mapCustom"; import { MapCustom } from "@/utils/mapCustom";
import { onMounted, ref, reactive } from "vue"; import { onMounted, ref, reactive } from "vue";
import Upload from "@/components/upload-img.vue"; import Upload from "@/components/upload-img.vue";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { warnRecord } from "@/api/index"; import { warningDetail, warningConfirm } from "@/api/index";
import { TWarnRecord } from "@/api/index.d"; import { TWarningConfirm, TWarningDetail } from "@/api/index.d";
import { useRoute } from "vue-router";
import { ElMessage, FormInstance, FormRules } from "element-plus";
//
enum unitEnum {
"次/分" = 4,
"%",
"℃",
}
enum statusEnum { enum statusEnum {
"待处理", "待处理",
"已处理", "已处理",
} }
enum warnTypeEnum {
"SOS告警",
"围栏告警",
"破坏告警",
"低电告警",
"心率告警",
"血氧告警",
"体温告警",
}
const { query } = useRoute();
const chartRef = ref(null); const chartRef = ref(null);
let tabs = [ const ruleFormRef = ref<FormInstance>();
{ label: "全部", value: undefined }, let map = null;
{ label: "未处理", value: 0 },
{ label: "已处理", value: 1 },
];
const ringOptions = { const ringOptions = {
title: { title: {
@ -115,45 +134,80 @@ const ringOptions = {
}, },
], ],
}; };
const formInline = reactive({ const ruleForm = reactive<TWarningConfirm>({
user: "", id: query.deviceId as string,
region: "", name: "",
date: "", username: "",
content: "",
images: [],
}); });
let curData = ref<TWarningDetail.TRes>({
const paging = reactive({ address: "",
page: 1, adminName: "",
size: 10, adminPhone: "",
total: 0, creatUser: "",
createTime: "",
deviceId: "", deviceId: "",
status: undefined, healthData: "",
id: 0,
lat: 0,
lng: 0,
maxValue: 0,
minValue: 0,
rcontent: "",
rimg: [],
rname: "",
status: 0,
type: 0,
updateTime: "",
updateUser: "",
userNumber: "",
username: "",
orgName: "",
value: "",
warnType: 0,
}); });
const tableData = ref<TWarnRecord.IListRes[]>([]);
const rules = reactive<FormRules<TWarningConfirm>>({
name: [{ required: true, message: "请输入处理人", trigger: "blur" }],
username: [{ required: true, message: "请输入警号", trigger: "blur" }],
content: [{ required: true, message: "请输入处理记录", trigger: "blur" }],
images: [{ required: true, message: "请上传图片", trigger: "blur" }],
});
const getData = async () => { const getData = async () => {
try { try {
const res = await warnRecord(paging); const res = await warningDetail({ id: query.deviceId as string });
tableData.value = res.records; curData.value = res;
paging.total = res.total; ruleForm.name = res.rname;
ruleForm.username = res.rname;
ruleForm.content = res.rcontent;
ruleForm.images = JSON.parse(res.rimg);
console.log(ruleForm, "ruleFormruleFormruleFormruleForm");
let icon = map.newIcon(location);
let marker = map.marker({ icon, position: [116.406315, 39.908775] });
marker.setMap(map.map);
} catch (error) {} } catch (error) {}
}; };
const load = () => { const submitForm = async (formEl: FormInstance | undefined) => {
paging.page++; if (!formEl) return;
getData(); await formEl.validate((valid) => {
if (valid) {
warningConfirm(ruleForm).then(() => {
ElMessage.success("处理成功");
curData.value.status = 1;
});
}
});
}; };
const checkTabs = (item: number | undefined) => {
// paging.status = item;
// paging.page = 1;
// getData();
};
onMounted(() => { onMounted(() => {
getData();
map = new MapCustom({ dom: "mapcontainer", center: [116.406315, 39.908775] });
if (chartRef.value) { if (chartRef.value) {
const myChart = echarts.init(chartRef.value); const myChart = echarts.init(chartRef.value);
myChart.setOption(ringOptions); myChart.setOption(ringOptions);
} }
new MapCustom({ dom: "mapcontainer" });
// getData();
}); });
</script> </script>

View File

@ -54,8 +54,7 @@ const submitForm = async (formEl: FormInstance | undefined) => {
await formEl.validate((valid, fields) => { await formEl.validate((valid, fields) => {
if (valid) { if (valid) {
fetchLogin(ruleForm) fetchLogin(ruleForm).then((res) => {
.then((res) => {
comm.setUser(res); comm.setUser(res);
ElMessage({ ElMessage({
message: "登录成功", message: "登录成功",
@ -64,9 +63,6 @@ const submitForm = async (formEl: FormInstance | undefined) => {
setTimeout(() => { setTimeout(() => {
router.push("/"); router.push("/");
}, 1000); }, 1000);
})
.catch((err) => {
console.log(err, "err");
}); });
} }
}); });

View File

@ -47,11 +47,15 @@
:currentPage="paging1.page" :currentPage="paging1.page"
:changePage="changeWarningPage" :changePage="changeWarningPage"
> >
<template #operator> <template #operator="{ rows }">
<el-button link type="primary" size="small"> 处理事件 </el-button> <el-button link type="primary" size="small" @click="toIncidentDispose(rows.id)" v-if="rows.status == 0"> 处理事件 </el-button>
<div v-else></div>
</template> </template>
<template #status="{ rows }"> <template #status="{ rows }">
{{ warningStatusEnum[rows.status] }} <el-tag :type="statusColor[rows.status]">{{ warningStatusEnum[rows.status] }}</el-tag>
</template>
<template #warnType="{ rows }">
{{ warnTypeEnum[rows.status] }}
</template> </template>
</TableCustom> </TableCustom>
</el-card> </el-card>
@ -65,8 +69,9 @@ import TableCustom from "@/components/table-custom.vue";
import { TableItem } from "@/types/table"; import { TableItem } from "@/types/table";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import { TDevice } from "@/api/index.d"; import { TDevice } from "@/api/index.d";
const router = useRouter();
const { query } = useRoute(); const { query } = useRoute();
const router = useRouter();
enum statusEnum { enum statusEnum {
"使用中" = 0, "使用中" = 0,
"在线", "在线",
@ -80,7 +85,16 @@ enum recordStatusEnum {
"使用中" = 1, "使用中" = 1,
"结束使用", "结束使用",
} }
enum warnTypeEnum {
"SOS告警",
"围栏告警",
"破坏告警",
"低电告警",
"心率告警",
"血氧告警",
"体温告警",
}
const statusColor = ["danger", "success"];
// //
let record = ref([ let record = ref([
{ type: "index", label: "序号", width: 55, align: "center" }, { type: "index", label: "序号", width: 55, align: "center" },
@ -95,17 +109,19 @@ let columns = ref([
{ type: "index", label: "序号", width: 55, align: "center" }, { type: "index", label: "序号", width: 55, align: "center" },
{ prop: "userNumber", label: "佩戴者" }, { prop: "userNumber", label: "佩戴者" },
{ prop: "warnType", label: "事件类型" }, { prop: "warnType", label: "事件类型" },
{ prop: "creatUser", label: "触发时间" }, { prop: "createTime", label: "触发时间" },
{ prop: "status", label: "处理状态" }, { prop: "status", label: "处理状态" },
{ prop: "operator", label: "操作" }, { prop: "operator", label: "操作" },
]); ]);
const paging = reactive({ const paging = reactive({
deviceId: query.deviceId,
page: 1, page: 1,
size: 10, size: 10,
total: 0, total: 0,
}); });
const paging1 = reactive({ const paging1 = reactive({
deviceId: query.deviceId,
page: 1, page: 1,
size: 10, size: 10,
total: 0, total: 0,
@ -134,6 +150,12 @@ const changeWarningPage = (val: number) => {
paging1.page = val; paging1.page = val;
getWarningData(); getWarningData();
}; };
const toIncidentDispose = (deviceId: string) => {
router.push({
path: "/incidentDispose",
query: { deviceId },
});
};
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

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

View File

@ -10,20 +10,16 @@
<!-- <el-button>导出</el-button> --> <!-- <el-button>导出</el-button> -->
</template> </template>
<template #state="{ rows }"> <template #status="{ rows }">
{{ stateEnum[rows.state] }} <el-tag :type="statusColor[rows.status]">{{ statusEnum[rows.status] }}</el-tag>
</template>
<template #deviceSwitch="{ rows }">
{{ deviceSwitchEnum[rows.deviceSwitch] }}
</template> </template>
<template #mode="{ rows }"> <template #mode="{ rows }">
{{ modeEnum[rows.mode] }} <el-tag :type="modeColor[rows.mode]">{{ modeEnum[rows.mode] }}</el-tag>
</template> </template>
<template #monitorMode="{ rows }"> <template #deviceSwitch="{ rows }">
{{ monitorModeEnum[rows.monitorMode] }} <el-switch v-model="rows.deviceSwitch" />
</template> </template>
<template #battery="{ rows }"> {{ rows.battery }}% </template> <template #battery="{ rows }"> {{ rows.battery }}% </template>
<template #operator="{ rows }"> <template #operator="{ rows }">
<el-button link type="primary" size="small" @click="toPage('deviceInfo', rows)"> 详细信息 </el-button> <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('mapLocation', rows)"> 地图位置 </el-button>
@ -46,8 +42,8 @@
</template> </template>
<script setup lang="ts" name="basetable"> <script setup lang="ts" name="basetable">
import { ref, reactive } from "vue"; import { ref, reactive, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage } from "element-plus";
import { deviceList, setMode, deviceGetLocation, deviceControl } from "@/api/index"; import { deviceList, setMode, deviceGetLocation, deviceControl } from "@/api/index";
import { TDevice } from "@/api/index.d"; import { TDevice } from "@/api/index.d";
import TableCustom from "@/components/table-custom.vue"; import TableCustom from "@/components/table-custom.vue";
@ -58,24 +54,21 @@ import { TableItem } from "@/types/table";
import { FormOption, FormOptionList } from "@/types/form-option"; import { FormOption, FormOptionList } from "@/types/form-option";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
enum stateEnum { enum statusEnum {
"离线" = 0, "离线" = 0,
"在线", "在线",
"充电中", "充电中",
} }
enum deviceSwitchEnum {
"禁用" = 0,
"启用",
}
enum modeEnum { enum modeEnum {
"室内" = 0, "常规",
"室外", "审讯模式",
} "户外押送",
enum monitorModeEnum {
"室内" = 0,
"室外",
} }
const statusColor = ["danger", "success", "warning"];
const modeColor = ["primary", "danger", "warning"];
const router = useRouter(); const router = useRouter();
// / // /
let TableEditOptions = ref<FormOption>({ let TableEditOptions = ref<FormOption>({
@ -110,14 +103,15 @@ let columns = ref([
{ prop: "deviceId", label: "手铐IMEI" }, { prop: "deviceId", label: "手铐IMEI" },
{ prop: "name", label: "绑定警察名称" }, { prop: "name", label: "绑定警察名称" },
{ prop: "username", label: "绑定警察账户" }, { prop: "username", label: "绑定警察账户" },
{ prop: "state", label: "设备状态" },
{ prop: "mode", label: "当前模式" },
{ prop: "deviceSwitch", label: "开关" },
{ prop: "monitorMode", label: "监测模式" },
{ prop: "battery", label: "电量" }, { prop: "battery", label: "电量" },
{ prop: "deviceVersion", label: "版本号" }, { prop: "deviceVersion", label: "版本号" },
{ prop: "createTime", label: "创建时间" }, { prop: "status", label: "设备状态" },
{ prop: "mode", label: "当前模式" },
{ prop: "deviceSwitch", label: "开关" },
{ prop: "orgName", label: "关联辖区编号" }, { prop: "orgName", label: "关联辖区编号" },
{ prop: "createTime", label: "最新通信时间" },
{ prop: "createTime", label: "创建时间" },
{ prop: "operator", label: "操作", width: 400 }, { prop: "operator", label: "操作", width: 400 },
]); ]);
const paging = reactive({ const paging = reactive({
@ -126,7 +120,7 @@ const paging = reactive({
total: 0, total: 0,
}); });
const controlForm = reactive({ const controlForm = reactive({
pattern: 1, mode: 0,
location: 1, location: 1,
}); });
@ -136,7 +130,6 @@ const getData = async () => {
tableData.value = res.records; tableData.value = res.records;
paging.total = res.total; paging.total = res.total;
}; };
getData();
const changePage = (val: number) => { const changePage = (val: number) => {
paging.page = val; paging.page = val;
@ -163,6 +156,7 @@ const handleEdit = (row?: TDevice.IListRes) => {
const handelRow = (row?: TDevice.IListRes) => { const handelRow = (row?: TDevice.IListRes) => {
rowData.value = { ...row }; rowData.value = { ...row };
controlForm.mode = row.mode;
visible1.value = true; visible1.value = true;
}; };
@ -175,6 +169,15 @@ const handelControl = (type: number) => {
ElMessage.success("操作成功"); ElMessage.success("操作成功");
}); });
break; break;
case 5:
setMode({
deviceId: rowData.value.deviceId,
mode: controlForm.mode,
}).then(() => {
getData();
ElMessage.success("操作成功");
});
break;
default: default:
let cmdEnum = { let cmdEnum = {
1: "poweroff", 1: "poweroff",
@ -192,16 +195,6 @@ const handelControl = (type: number) => {
visible1.value = false; visible1.value = false;
}; };
//
const handelDel = (row: TableItem) => {
ElMessageBox.confirm("确定要删除吗?", "提示", {
type: "warning",
})
.then(async () => {
// ElMessage.success("");
})
.catch(() => {});
};
const updateData = () => { const updateData = () => {
closeDialog(); closeDialog();
@ -212,11 +205,13 @@ const closeDialog = () => {
visible.value = false; visible.value = false;
isEdit.value = false; isEdit.value = false;
}; };
console.log(222222);
onMounted(() => {
console.log(111111);
getData();
});
//
const handleDelete = (row: TableItem) => {
ElMessage.success("删除成功");
};
// //
const toPage = (path: string, row: TDevice.IListRes) => { const toPage = (path: string, row: TDevice.IListRes) => {
let p; let p;
@ -225,7 +220,7 @@ const toPage = (path: string, row: TDevice.IListRes) => {
} else if (path == "mapLocation") { } else if (path == "mapLocation") {
p = { id: row.id }; p = { id: row.id };
} else if (path == "setting") { } else if (path == "setting") {
p = { id: row.id }; p = { deviceId: row.deviceId };
} }
router.push({ router.push({
path, path,

View File

@ -4,100 +4,72 @@
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<div class="card-header-text">专项设置</div> <div class="card-header-text">专项设置</div>
<el-button type="primary">执行</el-button> <el-button type="primary" @click="submitForm(ruleFormRef)">执行</el-button>
</div> </div>
</template> </template>
<el-form :inline="true" :model="ruleForm" class="demo-form-inline"> <el-form :rules="rules" label-width="200px" :inline="true" :model="ruleForm" ref="ruleFormRef" class="demo-form-inline">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="IMEI号"> <el-form-item style="width: 100%" prop="deviceId" label="IMEI号">
<el-input v-model="ruleForm.user" placeholder="请输入IMEI号" clearable /> <el-input :disabled="true" v-model="ruleForm.deviceId" placeholder="请输入IMEI号" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="佩戴者编号:"> <el-form-item style="width: 100%" prop="userNumber" label="佩戴者编号:">
<el-input v-model="ruleForm.user" placeholder="请输入佩戴者编号" clearable /> <el-input v-model="ruleForm.userNumber" placeholder="请输入佩戴者编号" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <!-- <el-col :span="12">
<el-form-item label="模式选择"> <el-form-item style="width: 100%;" prop="age" label="模式选择">
<el-input v-model="ruleForm.user" placeholder="请输入IMEI号" clearable /> <el-input v-model="ruleForm.user" placeholder="请输入IMEI号" clearable />
</el-form-item> </el-form-item>
</el-col> -->
</el-row>
<el-divider />
<el-row :gutter="20" v-for="(item, index) in ruleForm.contacts" :key="index">
<el-col :span="12">
<el-form-item style="width: 100%" :prop="index == 0 ? 'name' : ''" :label="`姓名 ${index + 1}`">
<el-input v-model="item.name" placeholder="请输入姓名" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item style="width: 100%" :prop="index == 0 ? 'phone' : ''" :label="`紧急电话 ${index + 1}`">
<el-input v-model="item.phone" placeholder="请输入紧急电话" clearable />
</el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-divider /> <el-divider />
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="姓名 1"> <el-form-item style="width: 100%" prop="minHr" label="最低心率(次/分)">
<el-input v-model="ruleForm.user" placeholder="请输入姓名" clearable /> <el-input v-model="ruleForm.minHr" placeholder="请输入最低心率" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="紧急电话 1"> <el-form-item style="width: 100%" prop="maxHr" label="最高心率(次/分)">
<el-input v-model="ruleForm.user" placeholder="请输入紧急电话" clearable /> <el-input v-model="ruleForm.maxHr" placeholder="请输入最高心率" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="姓名 2"> <el-form-item style="width: 100%" prop="minTemp" label="最低体表温度(℃)">
<el-input v-model="ruleForm.user" placeholder="请输入姓名" clearable /> <el-input v-model="ruleForm.minTemp" placeholder="请输入最低体表温度" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="紧急电话 2"> <el-form-item style="width: 100%" prop="maxTemp" label="最高体表温度(℃)">
<el-input v-model="ruleForm.user" placeholder="请输入紧急电话" clearable /> <el-input v-model="ruleForm.maxTemp" placeholder="请输入最高体表温度" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="姓名 3"> <el-form-item style="width: 100%" prop="minBo" label="最低血氧(%">
<el-input v-model="ruleForm.user" placeholder="请输入姓名" clearable /> <el-input v-model="ruleForm.minBo" placeholder="请输入最低血氧" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="紧急电话 3">
<el-input v-model="ruleForm.user" placeholder="请输入紧急电话" clearable />
</el-form-item>
</el-col>
</el-row>
<el-divider />
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最小心率(次/分):">
<el-input v-model="ruleForm.user" placeholder="请输入最小心率" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最大心率(次/分):">
<el-input v-model="ruleForm.user" placeholder="请输入最大心率" clearable />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最小血氧(%">
<el-input v-model="ruleForm.user" placeholder="请输入最小血氧" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最大血氧(%">
<el-input v-model="ruleForm.user" placeholder="请输入最大血氧" clearable />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最小体表温度(℃):">
<el-input v-model="ruleForm.user" placeholder="请输入最小体表温度" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最大体表温度(℃):">
<el-input v-model="ruleForm.user" placeholder="请输入最大体表温度" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -107,11 +79,77 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive } from "vue"; import { onMounted, reactive, ref } from "vue";
const ruleForm = reactive({ import { deviceConfig, deviceConfigModify } from "@/api";
user: "", import { useRoute } from "vue-router";
region: "", import { TDeviceConfig } from "@/api/index.d";
date: "", import { ElMessage, FormInstance, FormRules } from "element-plus";
const { query } = useRoute();
const ruleForm = ref<TDeviceConfig.Tres>({
deviceId: query.deviceId,
userNumber: "",
minHr: 0,
minBo: 0,
minTemp: 0,
maxTemp: 0,
maxHr: 0,
contacts: [],
});
const validate = (rule: any, value: any, callback: any) => {
if (rule.field == "name" && !ruleForm.value.contacts[0].name) return callback(new Error("请输入姓名1"));
if (rule.field == "phone" && !ruleForm.value.contacts[0].phone) return callback(new Error("请输入紧急电话1"));
callback();
};
const rules = reactive<FormRules<TDeviceConfig.Tres>>({
userNumber: [{ required: true, message: "请输入佩戴者编号", trigger: "blur" }],
minHr: [{ required: true, message: "请输入最低心率", trigger: "blur" }],
minBo: [{ required: true, message: "请输入最低血氧", trigger: "blur" }],
minTemp: [{ required: true, message: "请输入最低温度", trigger: "blur" }],
maxTemp: [{ required: true, message: "请输入最高温度", trigger: "blur" }],
maxHr: [{ required: true, message: "请输入最高心率", trigger: "blur" }],
name: [{ required: true, validator: validate, trigger: "blur" }],
phone: [{ required: true, validator: validate, trigger: "blur" }],
});
const ruleFormRef = ref<FormInstance>();
const getDeviceConfig = () => {
deviceConfig({ deviceId: query.deviceId }).then((res) => {
let arr = res.contacts
.sort((a: any, b: any) => a.id - b.id)
.map((item) => {
return {
name: item.name,
phone: item.phone,
};
});
ruleForm.value = {
...res,
contacts: arr.length
? arr
: [
{ name: "", phone: "" },
{ name: "", phone: "" },
{ name: "", phone: "" },
],
};
});
};
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid) => {
if (valid) {
deviceConfigModify({
...ruleForm.value,
contacts: ruleForm.value.contacts,
}).then(() => {
ElMessage.success("执行成功");
});
}
});
};
onMounted(() => {
getDeviceConfig();
}); });
</script> </script>