2025年04月10日19:00:16
This commit is contained in:
parent
054d5fb5ca
commit
3346134b9a
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -49,6 +49,7 @@ declare module '@vue/runtime-core' {
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||
Header: typeof import('./src/components/header.vue')['default']
|
||||
InfoWindow: typeof import('./src/components/InfoWindow.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Sidebar: typeof import('./src/components/sidebar.vue')['default']
|
||||
|
67
src/api/index.d.ts
vendored
67
src/api/index.d.ts
vendored
@ -9,12 +9,19 @@ export interface IpagingRes<T> {
|
||||
pages: number
|
||||
records: T[]
|
||||
}
|
||||
export interface TRoleList {
|
||||
id: number
|
||||
name: string
|
||||
createTime: string
|
||||
}
|
||||
|
||||
interface TRoleMenu {
|
||||
id?: number
|
||||
type?: number
|
||||
name?: string
|
||||
createTime?: string
|
||||
}
|
||||
export interface TRoleList {
|
||||
id?: number
|
||||
name: string
|
||||
createTime?: string
|
||||
roleMenu: TRoleMenu[]
|
||||
}
|
||||
|
||||
|
||||
export interface TStatisticsDevice {
|
||||
@ -72,6 +79,14 @@ export interface TDeviceConfigModify {
|
||||
}
|
||||
|
||||
|
||||
export namespace TRoleModify {
|
||||
export interface Ireq {
|
||||
id: number
|
||||
name: string
|
||||
roleMenu: TRoleMenu[]
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TDeviceConfig {
|
||||
|
||||
interface Treq {
|
||||
@ -160,6 +175,7 @@ export namespace TDevice {
|
||||
accountId: number
|
||||
orgId: number
|
||||
status: number
|
||||
useStatus: number
|
||||
deviceSwitch: number
|
||||
mode: number
|
||||
monitorMode: number
|
||||
@ -345,4 +361,45 @@ export namespace THealthLatestData {
|
||||
tempArr: any[]
|
||||
}
|
||||
}
|
||||
export namespace TLocateRecord {
|
||||
|
||||
interface TReq {
|
||||
deviceId: number | string
|
||||
startDate: string
|
||||
endDate: string
|
||||
}
|
||||
interface TRes {
|
||||
id: number
|
||||
deviceId: string
|
||||
lat: number
|
||||
lng: number
|
||||
locationType: number
|
||||
adCode: string
|
||||
place: string
|
||||
address: string
|
||||
locationTime: string
|
||||
createTime: string
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TSetUseStatus {
|
||||
interface TReq {
|
||||
status: number
|
||||
deviceId: number
|
||||
}
|
||||
}
|
||||
export namespace TRoleMenuList {
|
||||
interface TMenus {
|
||||
id: number
|
||||
type: number
|
||||
name: string
|
||||
createTime: string
|
||||
}
|
||||
|
||||
interface TRes {
|
||||
name: string
|
||||
type: number
|
||||
menus: TMenus[]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import request from '../utils/request';
|
||||
import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes, TStatisticsCount, TWarnRecord, TWarningDetail, TWarningConfirm, TDeviceConfigModify, TDeviceConfig, THealthLatestData } from "./index.d";
|
||||
import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes, TStatisticsCount, TWarnRecord, TWarningDetail, TWarningConfirm, TDeviceConfigModify, TDeviceConfig, THealthLatestData, TLocateRecord, TSetUseStatus, TRoleMenuList, TRoleModify } from "./index.d";
|
||||
|
||||
export const fetchLogin = (p: TLogin.Ireq): Promise<TLogin.IRes> => {
|
||||
return request({
|
||||
@ -191,6 +191,15 @@ export const roleList = (): Promise<TRoleList[]> => {
|
||||
});
|
||||
};
|
||||
|
||||
// 修改角色信息
|
||||
export const roleModify = (p: TRoleModify.Ireq): Promise<null> => {
|
||||
return request({
|
||||
url: '/v1/web/role/modify',
|
||||
method: 'post',
|
||||
data: p
|
||||
});
|
||||
};
|
||||
|
||||
// 设备在线统计
|
||||
export const statisticsDevice = (): Promise<TStatisticsDevice> => {
|
||||
return request({
|
||||
@ -278,4 +287,39 @@ export const healthLatestData = (p: THealthLatestData.TReq): Promise<THealthLate
|
||||
});
|
||||
};
|
||||
|
||||
// 设备定位记录
|
||||
export const locateRecord = (p: TLocateRecord.TReq): Promise<TLocateRecord.TRes[]> => {
|
||||
return request({
|
||||
url: '/v1/web/device/locate/record',
|
||||
method: 'get',
|
||||
params: p
|
||||
});
|
||||
};
|
||||
|
||||
// 设置使用状态
|
||||
export const setUseStatus = (p: TSetUseStatus.TReq): Promise<null> => {
|
||||
return request({
|
||||
url: '/v1/web/device/set/useStatus',
|
||||
method: 'post',
|
||||
data: p
|
||||
});
|
||||
};
|
||||
|
||||
// 设置禁用状态
|
||||
export const setStatus = (p: TSetUseStatus.TReq): Promise<null> => {
|
||||
return request({
|
||||
url: '/v1/web/device/set/status',
|
||||
method: 'post',
|
||||
data: p
|
||||
});
|
||||
};
|
||||
|
||||
// 获取菜单列表
|
||||
export const roleMenuList = (): Promise<TRoleMenuList.TRes[]> => {
|
||||
return request({
|
||||
url: '/v1/web/role/menu/list',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -2,26 +2,28 @@
|
||||
<div class="infoBox">
|
||||
<div class="infoBox-head">
|
||||
<div class="item">
|
||||
<div class="span">姓名:</div>
|
||||
<div class="span">{{ value.username }}</div>
|
||||
<div class="span">手铐:</div>
|
||||
<div class="span">{{ value.id }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<i class="el-icon-close" style="font-size: 24px; cursor: pointer" @click="$emit('close')" />
|
||||
<div class="item" style="cursor: pointer" @click="emit('close')">
|
||||
<svg t="1744273365398" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8493" width="24" height="24">
|
||||
<path
|
||||
d="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z"
|
||||
fill="#444444"
|
||||
p-id="8494"
|
||||
></path>
|
||||
</svg>
|
||||
<!-- <i class="el-icon-close" style="font-size: 24px; cursor: pointer" @click="emit('close')" /> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="infoBox-content">
|
||||
2
|
||||
<div class="item">
|
||||
<div class="item-left">IMEI号</div>
|
||||
<div class="item-right">{{ value.deviceId }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="item-left">定位方式</div>
|
||||
<div class="item-right">{{ locateEnum[value.locateType == -1 ? 3 : value.locateType] }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="item-left">定位时间</div>
|
||||
<div class="item-right">{{ value.locateTime }}</div>
|
||||
<div class="item-right">{{ value.locationTime }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="item-left">位置</div>
|
||||
@ -40,6 +42,8 @@ defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["close"]);
|
||||
|
||||
enum locateEnum {
|
||||
"WIFI" = 0,
|
||||
"LBS",
|
||||
@ -48,7 +52,7 @@ enum locateEnum {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="less" scoped>
|
||||
.infoBox {
|
||||
width: 400px;
|
||||
background: #fff;
|
@ -6,7 +6,7 @@
|
||||
<div class="app-main" :class="{ 'content-collapse': sidebar.collapse }">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="move" mode="out-in">
|
||||
<keep-alive>
|
||||
<keep-alive :include="[]">
|
||||
<component :is="Component"></component>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
@ -19,9 +19,24 @@
|
||||
import { useSidebarStore } from "@/store/sidebar";
|
||||
import vHeader from "@/components/header.vue";
|
||||
import vSidebar from "@/components/sidebar.vue";
|
||||
import { routes } from "@/router/index";
|
||||
|
||||
const sidebar = useSidebarStore();
|
||||
console.log(sidebar);
|
||||
|
||||
const getInclude = (routeList: any) => {
|
||||
if (!routeList) return [];
|
||||
let list = [];
|
||||
routeList.forEach((item) => {
|
||||
if (item.meta && item.meta.keepAlive) {
|
||||
list.push(item.name);
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
list = [...list, ...getInclude(item.children)];
|
||||
}
|
||||
});
|
||||
return list;
|
||||
};
|
||||
// const include = getInclude(routes[0].children);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
@ -22,7 +22,7 @@ export const mix = (color1: string, color2: string, weight: number = 0.5): strin
|
||||
* @param {*} fmStr 格式化格式 YYYY-MM-DD HH:mm:ss
|
||||
* @returns
|
||||
*/
|
||||
export function format(time: Date | string, fmStr: string = "YYYY-MM-DD HH:mm:ss") {
|
||||
export function format(time: Date | string | number, fmStr: string = "YYYY-MM-DD HH:mm:ss") {
|
||||
if (!time) return "";
|
||||
return dayjs(typeof time == 'string' ? new Date(time) : time).format(fmStr);
|
||||
}
|
||||
|
@ -115,12 +115,36 @@ export class MapCustom {
|
||||
icon,
|
||||
position,
|
||||
map: this.map,
|
||||
offset: new AMap.Pixel(-25, -50),
|
||||
offset: new AMap.Pixel(-20, -40),
|
||||
})
|
||||
}
|
||||
lngLat(lng, lat) {
|
||||
return new AMap.LngLat(lng, lat);
|
||||
}
|
||||
infoWindow(option = {
|
||||
anchor: 'bottom-center',
|
||||
isCustom: true, //使用自定义窗体
|
||||
content: document.querySelector('.infoBox'),
|
||||
offset: new AMap.Pixel(-2, -40),
|
||||
}) {
|
||||
return new AMap.InfoWindow(option)
|
||||
|
||||
}
|
||||
//绘制轨迹线条
|
||||
polyline(list) {
|
||||
this.clearMap()
|
||||
let Polyline = new AMap.Polyline({
|
||||
map: this.map,
|
||||
path: list.map((item) => [item.lng, item.lat]),
|
||||
showDir: true,
|
||||
strokeColor: '#0088F6', //线颜色
|
||||
strokeWeight: 4 //线宽
|
||||
})
|
||||
this.map.setFitView(Polyline);
|
||||
}
|
||||
setCenter(position) {
|
||||
this.map.setCenter(position)
|
||||
}
|
||||
|
||||
clearMap() {
|
||||
this.map.clearMap();
|
||||
|
@ -12,7 +12,7 @@
|
||||
<div v-infinite-scroll="load" :infinite-scroll-immediate="false" class="device-list noScrollbar infinite-list" style="overflow: auto">
|
||||
<el-popover :width="350" class="box-item" placement="bottom" v-for="item in list" :key="item.id">
|
||||
<template #reference>
|
||||
<div class="item">
|
||||
<div class="item" :class="{ active: deviceId === item.deviceId }" @click="emit('click', item)">
|
||||
<div class="item-img">
|
||||
<img src="@/assets/img/handcuffs.png" alt="" srcset="" />
|
||||
</div>
|
||||
@ -74,8 +74,8 @@ enum modeEnum {
|
||||
"审讯模式",
|
||||
"户外押送",
|
||||
}
|
||||
|
||||
const { list, paging, api } = defineProps({
|
||||
const emit = defineEmits(["click"]);
|
||||
const { list, paging, api, deviceId } = defineProps({
|
||||
list: {
|
||||
type: Array<TDevice.IListRes>,
|
||||
default: () => [],
|
||||
@ -88,6 +88,10 @@ const { list, paging, api } = defineProps({
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
deviceId: {
|
||||
type: Number || String,
|
||||
default: () => "",
|
||||
},
|
||||
});
|
||||
|
||||
const handelMode = () => {
|
||||
@ -145,6 +149,9 @@ const load = () => {
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #dedede;
|
||||
cursor: pointer;
|
||||
&.active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
&:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<el-row class="el-row" :gutter="20">
|
||||
<el-col :span="6" class="el-row-left"><DeviceInfo :paging="devicePaging" :api="getdeviceList" :list="deviceData" /></el-col>
|
||||
<el-col :span="6" class="el-row-left"
|
||||
><DeviceInfo :deviceId="deviceInfo?.deviceId" :paging="devicePaging" :api="getdeviceList" :list="deviceData" @click="handelClickDevice"
|
||||
/></el-col>
|
||||
<el-col :span="18" class="el-row-right scrollbar">
|
||||
<MonitoringTop :funcList="funcList" />
|
||||
<div v-if="deviceInfo?.status != 2">
|
||||
<div v-if="deviceInfo?.status == 2">
|
||||
<div class="monitoringMap" id="mapcontainer"></div>
|
||||
<el-row :gutter="20" style="margin-top: 20px">
|
||||
<el-col :span="12">
|
||||
@ -44,16 +46,18 @@ import DeviceHistory from "./deviceHistory.vue";
|
||||
import DeviceRecord from "./deviceRecord.vue";
|
||||
import { MapCustom } from "@/utils/mapCustom";
|
||||
import * as echarts from "echarts";
|
||||
import { deviceList, healthLatestData, warningRecord } from "@/api/index";
|
||||
import { deviceList, healthLatestData, warningRecord, locateRecord } from "@/api/index";
|
||||
import { TDevice, THealthLatestData } from "@/api/index.d";
|
||||
import { onMounted, onDeactivated, ref, reactive } from "vue";
|
||||
import { debounce, format } from "@/utils";
|
||||
import heart from "@/assets/img/heart.png";
|
||||
import temperature from "@/assets/img/temperature.png";
|
||||
import blood from "@/assets/img/blood.png";
|
||||
import location from "@/assets/img/location.png";
|
||||
|
||||
const chartRef = ref(null);
|
||||
let myChart = null;
|
||||
let newMap = null;
|
||||
let funcList = ref([
|
||||
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
||||
{ title: "当前血氧", en: "DANGQIANXUEYANG", icon: blood, unit: "%", num: 0, color: "#8B51FD" },
|
||||
@ -86,13 +90,6 @@ const options = {
|
||||
},
|
||||
};
|
||||
|
||||
const paging = reactive({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
status: undefined,
|
||||
warnType: undefined,
|
||||
});
|
||||
const devicePaging = reactive({
|
||||
page: 1,
|
||||
size: 10,
|
||||
@ -101,7 +98,6 @@ const devicePaging = reactive({
|
||||
const HealthData = ref<THealthLatestData.TRes>();
|
||||
|
||||
const deviceInfo = ref<TDevice.IListRes>();
|
||||
const tableData = ref<TDevice.IWarningRecordRes[]>([]);
|
||||
const deviceData = ref<TDevice.IListRes[]>([]);
|
||||
|
||||
const getdeviceList = async () => {
|
||||
@ -110,29 +106,20 @@ const getdeviceList = async () => {
|
||||
if (res.records.length > 0) {
|
||||
deviceInfo.value = res.records[1];
|
||||
getHealthLatestData();
|
||||
// getData();
|
||||
getLocateRecord();
|
||||
}
|
||||
};
|
||||
const getData = async () => {
|
||||
const res = await warningRecord({ ...paging, deviceId: deviceInfo.value.deviceId });
|
||||
tableData.value = res.records;
|
||||
paging.total = res.total;
|
||||
};
|
||||
|
||||
const getHealthLatestData = () => {
|
||||
healthLatestData({ deviceId: deviceInfo.value.deviceId }).then((res) => {
|
||||
HealthData.value = res;
|
||||
funcList.value[0].num = res.hr;
|
||||
funcList.value[1].num = res.bo;
|
||||
funcList.value[2].num = res.temp;
|
||||
|
||||
getOptionsData(HealthData.value.hrArr, "心率", "#FF0303");
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val: number) => {
|
||||
paging.page = val;
|
||||
getData();
|
||||
};
|
||||
const handelRadio = (val: number) => {
|
||||
if (val == 1) {
|
||||
getOptionsData(HealthData.value.hrArr, "心率", "#FF0303");
|
||||
@ -145,22 +132,49 @@ const handelRadio = (val: number) => {
|
||||
const getOptionsData = (list: { time: string; value: number }[], name: string, color: string) => {
|
||||
options.xAxis.data = [];
|
||||
options.series.data = [];
|
||||
if (list && list.length) {
|
||||
list.forEach((item) => {
|
||||
options.xAxis.data.push(format(item.time, "HH:mm:ss"));
|
||||
options.series.data.push(item.value);
|
||||
});
|
||||
options.series.name = name;
|
||||
options.series.itemStyle.color = color;
|
||||
}
|
||||
|
||||
myChart.setOption(options);
|
||||
};
|
||||
|
||||
const getLocateRecord = () => {
|
||||
let d = new Date();
|
||||
locateRecord({
|
||||
deviceId: deviceInfo.value.deviceId,
|
||||
startDate: `${format(d, "YYYY-MM-DD")} 00:00:00`,
|
||||
endDate: `${format(d, "YYYY-MM-DD")} 23:59:59`,
|
||||
}).then((res) => {
|
||||
if (res && res.length) {
|
||||
let list = res;
|
||||
newMap.clearMap();
|
||||
newMap.setCenter([list[0].lng, list[0].lat]);
|
||||
newMap.polyline(list);
|
||||
let icon = newMap.newIcon(location);
|
||||
list.forEach((item) => {
|
||||
let marker = newMap.marker({ icon, position: [item.lng, item.lat] });
|
||||
marker.setMap(newMap.map);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleResize = debounce(() => {
|
||||
myChart.resize();
|
||||
}, 200);
|
||||
|
||||
const handelClickDevice = (val: TDevice.IListRes) => {
|
||||
deviceInfo.value = val;
|
||||
getHealthLatestData();
|
||||
getLocateRecord();
|
||||
};
|
||||
onMounted(() => {
|
||||
getdeviceList();
|
||||
new MapCustom({ dom: "mapcontainer" });
|
||||
newMap = new MapCustom({ dom: "mapcontainer" });
|
||||
if (chartRef.value) {
|
||||
myChart = echarts.init(chartRef.value);
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
@ -39,14 +39,7 @@
|
||||
<template #header>
|
||||
<div class="card-header">当前设备告警记录</div>
|
||||
</template>
|
||||
<TableCustom
|
||||
:hasToolbar="false"
|
||||
:columns="columns"
|
||||
:tableData="warningTableData"
|
||||
:total="paging1.total"
|
||||
:currentPage="paging1.page"
|
||||
:changePage="changeWarningPage"
|
||||
>
|
||||
<TableCustom :hasToolbar="false" :columns="columns" :tableData="warningTableData" :paging="paging1" :changePage="changeWarningPage">
|
||||
<template #operator="{ rows }">
|
||||
<el-button link type="primary" size="small" @click="toIncidentDispose(rows.id)" v-if="rows.status == 0"> 处理事件 </el-button>
|
||||
<div v-else></div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="container">
|
||||
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
||||
<div class="table-container">
|
||||
<TableCustom :columns="columns" :tableData="tableData" :paging="paging" :refresh="getData" :changePage="changePage">
|
||||
<TableCustom :columns="columns" :tableData="tableData" :paging="paging" :changePage="changePage">
|
||||
<template #toolbarBtn>
|
||||
<!-- <el-button type="primary" @click="handleAdd">新增</el-button> -->
|
||||
<el-button @click="handleEdit">手铐关联</el-button>
|
||||
@ -13,11 +13,14 @@
|
||||
<template #status="{ rows }">
|
||||
<el-tag :type="statusColor[rows.status]">{{ statusEnum[rows.status] }}</el-tag>
|
||||
</template>
|
||||
<template #mode="{ rows }">
|
||||
<el-tag :type="modeColor[rows.mode]">{{ modeEnum[rows.mode] }}</el-tag>
|
||||
<template #useStatus="{ rows }">
|
||||
<el-switch v-model="rows.useStatus" :active-value="1" :inactive-value="0" @click="handelSwitch(rows, 1)" />
|
||||
</template>
|
||||
<template #deviceSwitch="{ rows }">
|
||||
<el-switch v-model="rows.deviceSwitch" />
|
||||
<el-switch v-model="rows.deviceSwitch" :active-value="1" :inactive-value="0" @click="handelSwitch(rows, 2)" />
|
||||
</template>
|
||||
<template #mode="{ rows }">
|
||||
<el-tag :type="modeColor[rows.mode]">{{ modeEnum[rows.mode] }}</el-tag>
|
||||
</template>
|
||||
<template #battery="{ rows }"> {{ rows.battery }}% </template>
|
||||
<template #operator="{ rows }">
|
||||
@ -44,7 +47,7 @@
|
||||
<script setup lang="ts" name="basetable">
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { deviceList, setMode, deviceGetLocation, deviceControl } from "@/api/index";
|
||||
import { deviceList, setMode, deviceGetLocation, deviceControl, setUseStatus, setStatus } from "@/api/index";
|
||||
import { TDevice } from "@/api/index.d";
|
||||
import TableCustom from "@/components/table-custom.vue";
|
||||
import TableSearch from "@/components/table-search.vue";
|
||||
@ -107,7 +110,8 @@ let columns = ref([
|
||||
{ prop: "deviceVersion", label: "版本号" },
|
||||
{ prop: "status", label: "设备状态" },
|
||||
{ prop: "mode", label: "当前模式" },
|
||||
{ prop: "deviceSwitch", label: "开关" },
|
||||
{ prop: "useStatus", label: "使用状态" },
|
||||
{ prop: "deviceSwitch", label: "启用开关" },
|
||||
{ prop: "orgName", label: "关联辖区编号" },
|
||||
{ prop: "createTime", label: "最新通信时间" },
|
||||
{ prop: "createTime", label: "创建时间" },
|
||||
@ -159,7 +163,16 @@ const handelRow = (row?: TDevice.IListRes) => {
|
||||
controlForm.mode = row.mode;
|
||||
visible1.value = true;
|
||||
};
|
||||
|
||||
const handelSwitch = (val: TDevice.IListRes, type: number) => {
|
||||
let api = type == 1 ? setUseStatus : setStatus;
|
||||
api({
|
||||
deviceId: val.deviceId,
|
||||
status: type == 1 ? val.useStatus : val.deviceSwitch,
|
||||
}).then(() => {
|
||||
getData();
|
||||
ElMessage.success("操作成功");
|
||||
});
|
||||
};
|
||||
const handelControl = (type: number) => {
|
||||
switch (type) {
|
||||
case 4:
|
||||
@ -216,7 +229,7 @@ const toPage = (path: string, row: TDevice.IListRes) => {
|
||||
if (path == "deviceInfo") {
|
||||
p = { ...row };
|
||||
} else if (path == "mapLocation") {
|
||||
p = { id: row.id };
|
||||
p = { deviceId: row.deviceId };
|
||||
} else if (path == "setting") {
|
||||
p = { deviceId: row.deviceId };
|
||||
}
|
||||
|
@ -17,23 +17,11 @@
|
||||
range-separator="-"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
v-model="time"
|
||||
@change="timeChange"
|
||||
/>
|
||||
<el-date-picker v-else type="week" value-format="YYYY-MM-DD/ww" placeholder="请选择周" @change="weekChange" />
|
||||
<el-date-picker v-model="week" v-else type="week" value-format="YYYY-MM-DD" placeholder="请选择周" @change="weekChange" />
|
||||
</div>
|
||||
<el-select
|
||||
v-model="value"
|
||||
multiple
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
placeholder="请输入设备IMEI"
|
||||
:remote-method="remoteMethod"
|
||||
:loading="loading"
|
||||
style="width: 240px"
|
||||
>
|
||||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
|
||||
<!-- <span>位置样式:</span>
|
||||
<el-radio-group v-model="styleType">
|
||||
<el-radio-button :value="1">点</el-radio-button>
|
||||
@ -66,49 +54,76 @@
|
||||
<el-col :span="24" class="container-right">
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
<div :style="{ display: 'none' }">
|
||||
<InfoWindow class="infoBox" :value="deviceInfo" @close="InfoWin.close()" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import handcuffs from "@/assets/img/handcuffs.png";
|
||||
import { onMounted } from "vue";
|
||||
import { onMounted, reactive } from "vue";
|
||||
import { MapCustom } from "@/utils/mapCustom";
|
||||
import { ref } from "vue";
|
||||
interface ListItem {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
let tabs = [
|
||||
{ label: "全部", value: "0" },
|
||||
{ label: "未处理", value: "1" },
|
||||
{ label: "已处理", value: "2" },
|
||||
];
|
||||
import { locateRecord } from "@/api";
|
||||
import { format } from "@/utils";
|
||||
import { TLocateRecord } from "@/api/index.d";
|
||||
import { useRoute } from "vue-router";
|
||||
import location from "@/assets/img/location.png";
|
||||
import InfoWindow from "@/components/InfoWindow.vue";
|
||||
|
||||
const { query } = useRoute();
|
||||
let d = new Date();
|
||||
let newMap = null;
|
||||
let time = ref([new Date(`${format(d, "YYYY-MM-DD")} 00:00:00`), new Date(`${format(d, "YYYY-MM-DD")} 23:59:59`)]);
|
||||
let week = ref(d);
|
||||
let deviceInfo = ref({});
|
||||
let sectionType = ref(1);
|
||||
let styleType = ref(1);
|
||||
let InfoWin = null;
|
||||
|
||||
const list = ref<ListItem[]>([]);
|
||||
const options = ref<ListItem[]>([]);
|
||||
const value = ref<string[]>([]);
|
||||
const loading = ref(false);
|
||||
const params = reactive<TLocateRecord.TReq>({
|
||||
deviceId: query.deviceId as string,
|
||||
// startDate: `${format(d, "YYYY-MM-DD")} 00:00:00`,
|
||||
// endDate: `${format(d, "YYYY-MM-DD")} 23:59:59`,
|
||||
startDate: "2021-04-14 00:00:00",
|
||||
endDate: "2025-05-14 23:59:59",
|
||||
});
|
||||
|
||||
//处理展示数据
|
||||
const weekChange = (value: any) => {};
|
||||
const remoteMethod = (query: string) => {
|
||||
if (query) {
|
||||
loading.value = true;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
options.value = list.value.filter((item) => {
|
||||
return item.label.toLowerCase().includes(query.toLowerCase());
|
||||
const weekChange = (val: any) => {
|
||||
let endTime = new Date(val).getTime() + 6 * 24 * 60 * 60 * 1000;
|
||||
params.startDate = `${val} 00:00:00`;
|
||||
params.endDate = `${format(endTime, "YYYY-MM-DD")} 23:59:59`;
|
||||
getLocateRecord();
|
||||
};
|
||||
const timeChange = (val: any) => {
|
||||
params.startDate = `${format(val[0], "YYYY-MM-DD")} 00:00:00`;
|
||||
params.endDate = `${format(val[1], "YYYY-MM-DD")} 23:59:59`;
|
||||
getLocateRecord();
|
||||
};
|
||||
|
||||
const getLocateRecord = () => {
|
||||
locateRecord(params).then((res) => {
|
||||
if (res && res.length) {
|
||||
let list = res;
|
||||
newMap.clearMap();
|
||||
newMap.setCenter([list[0].lng, list[0].lat]);
|
||||
newMap.polyline(list);
|
||||
let icon = newMap.newIcon(location);
|
||||
list.forEach((item) => {
|
||||
let marker = newMap.marker({ icon, position: [item.lng, item.lat] });
|
||||
marker.setMap(newMap.map);
|
||||
marker.on("click", () => {
|
||||
deviceInfo.value = item;
|
||||
InfoWin = newMap.infoWindow();
|
||||
InfoWin.open(newMap.map, marker.getPosition());
|
||||
});
|
||||
});
|
||||
}, 200);
|
||||
} else {
|
||||
options.value = [];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
new MapCustom({ dom: "mapcontainer" });
|
||||
newMap = new MapCustom({ dom: "mapcontainer" });
|
||||
getLocateRecord();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -41,16 +41,16 @@
|
||||
<TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData" @close="closeDialog" />
|
||||
</el-dialog>
|
||||
<el-dialog title="编辑类型" v-model="typeVisible" width="800px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
|
||||
<UserType />
|
||||
<UserType :typeHeadList="typeHeadList" :roleListData="roleListData" @complete="saveType" @addType="addType" />
|
||||
</el-dialog>
|
||||
<BatchImp ref="batchImpRef" @success="handleSearch" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="basetable">
|
||||
import { ref, reactive } from "vue";
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { accountAdd, accountModify, accountList, accountDeletet, passwordReset, roleList } from "@/api/index";
|
||||
import { accountAdd, accountModify, accountList, accountDeletet, passwordReset, roleList, roleMenuList, roleModify } from "@/api/index";
|
||||
import TableCustom from "@/components/table-custom.vue";
|
||||
import TableSearch from "@/components/table-search.vue";
|
||||
import TableEdit from "@/components/table-edit.vue";
|
||||
@ -59,7 +59,7 @@ import { useCommonStore } from "@/store/common";
|
||||
import UserType from "./userType.vue";
|
||||
import { TableItem } from "@/types/table";
|
||||
import { FormOption, FormOptionList } from "@/types/form-option";
|
||||
import { TAccount, TRoleList } from "@/api/index.d";
|
||||
import { TAccount, TRoleList, TRoleMenuList } from "@/api/index.d";
|
||||
// import { Hide, View } from "@element-plus/icons-vue";
|
||||
|
||||
enum roleEnum {
|
||||
@ -75,7 +75,8 @@ const typeVisible = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const dialogTitle = ref("");
|
||||
const rowData = ref<TAccount.IListRes | undefined>();
|
||||
|
||||
// 类型列表头列表
|
||||
let typeHeadList = ref<TRoleMenuList.TRes[]>([]);
|
||||
// 查询相关
|
||||
const query = reactive({
|
||||
name: "",
|
||||
@ -182,6 +183,7 @@ const changePage = (val: number) => {
|
||||
};
|
||||
const roleListFn = () => {
|
||||
roleList().then((res) => {
|
||||
roleListData.value = res;
|
||||
let opts = res?.map((item) => {
|
||||
return { label: item.name, value: item.id };
|
||||
});
|
||||
@ -196,8 +198,6 @@ const getData = async () => {
|
||||
});
|
||||
paging.total = res.total;
|
||||
};
|
||||
roleListFn();
|
||||
getData();
|
||||
|
||||
// 删除相关
|
||||
const handelDel = (row: TableItem) => {
|
||||
@ -229,7 +229,16 @@ const updateData = (res) => {
|
||||
getData();
|
||||
});
|
||||
};
|
||||
|
||||
const saveType = (row: TRoleList) => {
|
||||
roleModify(row).then(() => {
|
||||
ElMessage.success("保存成功");
|
||||
roleListFn();
|
||||
typeVisible.value = false;
|
||||
});
|
||||
};
|
||||
const addType = () => {
|
||||
roleListData.value.push({ name: "", roleMenu: [] });
|
||||
};
|
||||
const closeDialog = () => {
|
||||
visible.value = false;
|
||||
isEdit.value = false;
|
||||
@ -254,6 +263,16 @@ const handelRow = (name: string, row?: TAccount.IListRes) => {
|
||||
}
|
||||
visible.value = true;
|
||||
};
|
||||
const getRoleMenuList = () => {
|
||||
roleMenuList().then((res) => {
|
||||
typeHeadList.value = res;
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
roleListFn();
|
||||
getData();
|
||||
getRoleMenuList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -1,51 +1,21 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table :data="roleListData" style="width: 100%">
|
||||
<el-table-column prop="name" label="" width="150" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox value="Value 1" size="large" v-if="row.flag" />
|
||||
<el-input v-model="row.name" v-else />
|
||||
<el-input v-model="row.name" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="date" label="web管理权限" width="150" align="center">
|
||||
<el-table-column :label="item.name" align="center" v-for="(item, index) in typeHeadList" :key="index">
|
||||
<el-table-column prop="name" :label="ite.name" align="center" v-for="(ite, ide) in item.menus" :key="`${index}_${ide}`">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox size="large" v-model="row.check" disabled>
|
||||
<el-checkbox value="Value 1" size="large">
|
||||
<template #default>
|
||||
<div class="box box1" v-if="!row.check">
|
||||
<div class="box box1" v-if="!isCheck(ite, row)" @click="clickItem(ite, row)">
|
||||
<el-icon><CloseBold style="color: red" /></el-icon>
|
||||
</div>
|
||||
<div class="box box2" v-else>
|
||||
<el-icon><Select style="color: #fff" /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="APP权限" align="center">
|
||||
<el-table-column prop="name" label="手铐管理权限" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox value="Value 1" size="large" disabled>
|
||||
<template #default>
|
||||
<div class="box box1" v-if="!row.check">
|
||||
<el-icon><CloseBold style="color: red" /></el-icon>
|
||||
</div>
|
||||
<div class="box box2" v-else>
|
||||
<el-icon><Select style="color: #fff" /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="告警管理权限" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox value="Value 1" size="large" disabled>
|
||||
<template #default>
|
||||
<div class="box box1" v-if="!row.check">
|
||||
<el-icon><CloseBold style="color: red" /></el-icon>
|
||||
</div>
|
||||
<div class="box box2" v-else>
|
||||
<div class="box box2" v-else @click="clickItem(ite, row)">
|
||||
<el-icon><Select style="color: #fff" /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
@ -55,50 +25,47 @@
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="date" label="操作" width="200" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" size="small">锁定</el-button>
|
||||
<el-button link type="primary" size="small">修改</el-button>
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="emit('complete', row)">保存</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button class="mt-4" style="width: 100%" @click="addType"> 添加类型 </el-button>
|
||||
<el-button class="mt-4" style="width: 100%" @click="emit('addType')"> 添加类型 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { TRoleList, TRoleMenuList } from "@/api/index.d";
|
||||
import { PropType, ref } from "vue";
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
name: "管理员",
|
||||
flag: false,
|
||||
check: false,
|
||||
const { roleListData, typeHeadList } = defineProps({
|
||||
typeHeadList: {
|
||||
type: Array as PropType<TRoleMenuList.TRes[]>,
|
||||
default: () => [],
|
||||
},
|
||||
{
|
||||
name: "警察",
|
||||
flag: false,
|
||||
check: false,
|
||||
roleListData: {
|
||||
type: Array as PropType<TRoleList[]>,
|
||||
default: () => [],
|
||||
},
|
||||
{
|
||||
name: "辅警",
|
||||
flag: false,
|
||||
check: false,
|
||||
},
|
||||
{
|
||||
name: "协警",
|
||||
flag: false,
|
||||
check: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
const addType = () => {
|
||||
tableData.value = [
|
||||
...tableData.value,
|
||||
{
|
||||
name: "",
|
||||
flag: false,
|
||||
check: false,
|
||||
},
|
||||
];
|
||||
const emit = defineEmits(["complete", "addType"]);
|
||||
|
||||
const isCheck = (ite, row) => {
|
||||
let flag = false;
|
||||
row.roleMenu.forEach((item) => {
|
||||
if (ite.id == item.id) {
|
||||
flag = true;
|
||||
}
|
||||
});
|
||||
return flag;
|
||||
};
|
||||
const clickItem = (val, e) => {
|
||||
let flag = e.roleMenu.some((item) => val.id == item.id);
|
||||
if (!flag) {
|
||||
e.roleMenu.push(val);
|
||||
} else {
|
||||
e.roleMenu = e.roleMenu.filter((item) => item.id != val.id);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user