2025年04月28日17:18:08
This commit is contained in:
parent
9b61be74c7
commit
5d600041cf
@ -1,5 +1,11 @@
|
|||||||
# VITE_APP_URL = 'http://192.168.3.116:8001/'
|
# VITE_APP_URL = 'http://192.168.3.116:8001/'
|
||||||
# VITE_APP_URL_WEBSOCKET = 'http://192.168.3.116:8000/api/websocket'
|
# VITE_APP_URL_WEBSOCKET = 'http://192.168.3.116:8000/api/websocket'
|
||||||
|
|
||||||
VITE_APP_URL = 'http://api.handcuff.youaikang.cn'
|
VITE_APP_URL = 'http://47.112.185.26:8001/'
|
||||||
VITE_APP_URL_WEBSOCKET = 'ws://device.handcuff.youaikang.cn:8000/api/websocket'
|
VITE_APP_URL_WEBSOCKET = 'ws://47.112.185.26:8000/api/websocket'
|
||||||
|
|
||||||
|
# VITE_APP_URL = 'http://api.handcuff.zhuhaiguangdun.cn'
|
||||||
|
# VITE_APP_URL_WEBSOCKET = 'ws://device.handcuff.zhuhaiguangdun.cn:8000/api/websocket'
|
||||||
|
|
||||||
|
# VITE_APP_URL = 'http://api.handcuff.youaikang.cn'
|
||||||
|
# VITE_APP_URL_WEBSOCKET = 'http://device.handcuff.youaikang.cn:8000/api/websocket'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
VITE_APP_URL = 'http://api.handcuff.youaikang.cn'
|
VITE_APP_URL = 'http://47.112.185.26:8001/'
|
||||||
VITE_APP_URL_WEBSOCKET = 'http://device.handcuff.youaikang.cn:8000/api/websocket'
|
VITE_APP_URL_WEBSOCKET = 'ws://47.112.185.26:8000/api/websocket'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# VITE_APP_URL = 'http://api.handcuff.zhuhaiguangdun.cn'
|
||||||
|
# VITE_APP_URL_WEBSOCKET = 'ws://device.handcuff.zhuhaiguangdun.cn:8000/api/websocket'
|
BIN
src/assets/img/end-marker.png
Normal file
BIN
src/assets/img/end-marker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/img/start-marker.png
Normal file
BIN
src/assets/img/start-marker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
src/assets/img/via-marker.png
Normal file
BIN
src/assets/img/via-marker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
@ -2,8 +2,7 @@
|
|||||||
<div class="infoBox">
|
<div class="infoBox">
|
||||||
<div class="infoBox-head">
|
<div class="infoBox-head">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="span">手铐:</div>
|
{{ value.deviceId }}
|
||||||
<div class="span">{{ value.id }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="item" style="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">
|
<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">
|
||||||
@ -17,10 +16,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="infoBox-content">
|
<div class="infoBox-content">
|
||||||
<div class="item">
|
|
||||||
<div class="item-left">IMEI号</div>
|
|
||||||
<div class="item-right">{{ value.deviceId }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="item-left">定位时间</div>
|
<div class="item-left">定位时间</div>
|
||||||
<div class="item-right">{{ value.locationTime }}</div>
|
<div class="item-right">{{ value.locationTime }}</div>
|
||||||
@ -86,12 +81,8 @@ enum locateEnum {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #333;
|
color: #333;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
flex-shrink: 0;
|
||||||
.span {
|
font-weight: 700;
|
||||||
flex-shrink: 0;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.battery {
|
.battery {
|
||||||
width: 34px;
|
width: 34px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
|
@ -38,7 +38,6 @@ const handleBeforeUnload = (event: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onMessage = (res) => {
|
const onMessage = (res) => {
|
||||||
console.log(res, "WebSocket接收服务器消息");
|
|
||||||
if (res.cmd == "warning") {
|
if (res.cmd == "warning") {
|
||||||
alarmRef.value.visible = true;
|
alarmRef.value.visible = true;
|
||||||
alarmRef.value.warningList.unshift({ ...res, createTime: format(new Date(), "HH:mm:ss") });
|
alarmRef.value.warningList.unshift({ ...res, createTime: format(new Date(), "HH:mm:ss") });
|
||||||
@ -51,20 +50,21 @@ const onMessage = (res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// const isReload = localStorage.getItem("isReload");
|
const isReload = localStorage.getItem("isReload");
|
||||||
// if (isReload !== "true") {
|
if (isReload !== "true") {
|
||||||
// ElMessageBox.alert("由于浏览器安全策略,用户必须点击屏幕才能播放告警声音", "提示", {
|
ElMessageBox.alert("由于浏览器安全策略,用户必须点击屏幕才能播放告警声音", "提示", {
|
||||||
// confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
// callback: () => {
|
callback: () => {
|
||||||
// localStorage.setItem("isReload", "true");
|
localStorage.setItem("isReload", "true");
|
||||||
// },
|
},
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
|
|
||||||
if (ws.socket == null) {
|
if (ws.socket == null) {
|
||||||
ws.connect();
|
ws.connect();
|
||||||
}
|
}
|
||||||
ws.onMessage(onMessage);
|
ws.onMessage(onMessage);
|
||||||
|
|
||||||
window.addEventListener("beforeunload", handleBeforeUnload);
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -103,20 +103,30 @@ export class MapCustom {
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
newIcon(url) {
|
newIcon(option) {
|
||||||
return new AMap.Icon({
|
let data = {
|
||||||
size: new AMap.Size(36, 42),
|
size: new AMap.Size(36, 42),
|
||||||
image: url, // Icon的图像
|
image: '', // Icon的图像
|
||||||
imageSize: new AMap.Size(36, 42)
|
imageSize: new AMap.Size(36, 42)
|
||||||
})
|
}
|
||||||
|
if (typeof option == 'string') {
|
||||||
|
data.image = option
|
||||||
|
} else {
|
||||||
|
data = {
|
||||||
|
image: option.image, // Icon的图像
|
||||||
|
size: new AMap.Size(option.size[0], option.size[1]),
|
||||||
|
imageSize: new AMap.Size(option.size[0], option.size[1]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new AMap.Icon({ ...data })
|
||||||
}
|
}
|
||||||
// 创建marker
|
// 创建marker
|
||||||
marker({ icon, position }) {
|
marker({ icon, position, offset }) {
|
||||||
return new AMap.Marker({
|
return new AMap.Marker({
|
||||||
icon,
|
icon,
|
||||||
position,
|
position,
|
||||||
map: this.map,
|
map: this.map,
|
||||||
offset: new AMap.Pixel(-20, -40),
|
offset: new AMap.Pixel(-13, -26),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
lngLat(lng, lat) {
|
lngLat(lng, lat) {
|
||||||
|
@ -41,9 +41,10 @@ export default class WebSocketService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
webScoketLogin() {
|
webScoketLogin() {
|
||||||
|
const comm = useCommonStore();
|
||||||
this.sendMessage({
|
this.sendMessage({
|
||||||
username: "admin",
|
username: comm.user.username,
|
||||||
password: "111111",
|
token: comm.user.token,
|
||||||
type: 'web',
|
type: 'web',
|
||||||
cmd: "webLogin",
|
cmd: "webLogin",
|
||||||
})
|
})
|
||||||
@ -106,6 +107,8 @@ export default class WebSocketService {
|
|||||||
onMessage = (callback) => {
|
onMessage = (callback) => {
|
||||||
this.socket.onmessage = (event) => {
|
this.socket.onmessage = (event) => {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
|
console.log(data, 'onMessage');
|
||||||
|
|
||||||
if (data.cmd == "webLogin" && !data.code == 200) return this.webScoketLogin()
|
if (data.cmd == "webLogin" && !data.code == 200) return this.webScoketLogin()
|
||||||
callback && callback(data);
|
callback && callback(data);
|
||||||
if (event.data.includes('heartbeat')) {
|
if (event.data.includes('heartbeat')) {
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
<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">设备序号:{{ curData.id }}</div>
|
|
||||||
<div class="info-text">IMEI号:{{ curData.deviceId }}</div>
|
<div class="info-text">IMEI号:{{ curData.deviceId }}</div>
|
||||||
<div class="info-text">告警时间:{{ curData.createTime }}</div>
|
<div class="info-text">告警时间:{{ curData.createTime }}</div>
|
||||||
<div class="info-text">
|
<div class="info-text">
|
||||||
@ -77,6 +76,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<div :style="{ display: 'none' }">
|
||||||
|
<InfoWindow class="infoBox" :value="locationInfo" @close="InfoWin.close()" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -117,6 +119,8 @@ const disabled = ref(false);
|
|||||||
const ruleFormRef = ref<FormInstance>();
|
const ruleFormRef = ref<FormInstance>();
|
||||||
let map = null;
|
let map = null;
|
||||||
let myChart = null;
|
let myChart = null;
|
||||||
|
let InfoWin = null;
|
||||||
|
let locationInfo = ref({});
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@ -138,7 +142,7 @@ const options = {
|
|||||||
grid: {
|
grid: {
|
||||||
left: "0%",
|
left: "0%",
|
||||||
right: "4%",
|
right: "4%",
|
||||||
bottom: "3%",
|
bottom: "6%",
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
@ -150,6 +154,28 @@ const options = {
|
|||||||
yAxis: {
|
yAxis: {
|
||||||
type: "value",
|
type: "value",
|
||||||
},
|
},
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: "slider", //slider表示有滑动块的,inside表示内置的
|
||||||
|
start: 90, // 左边在 10% 的位置。
|
||||||
|
end: 100, // 右边在 60% 的位置。
|
||||||
|
show: true,
|
||||||
|
xAxisIndex: [0],
|
||||||
|
handleSize: 0, //滑动条的 左右2个滑动条的大小
|
||||||
|
height: 12, //组件高度
|
||||||
|
bottom: -2, //右边的距离
|
||||||
|
borderColor: "#eee",
|
||||||
|
fillerColor: "#E7E7E7",
|
||||||
|
backgroundColor: "#eee", //两边未选中的滑动条区域的颜色
|
||||||
|
showDataShadow: false, //是否显示数据阴影 默认auto
|
||||||
|
showDetail: false, //即拖拽时候是否显示详细数值信息 默认true
|
||||||
|
realtime: true, //是否实时更新
|
||||||
|
filterMode: "filter",
|
||||||
|
handleStyle: {
|
||||||
|
borderRadius: "20",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
@ -235,14 +261,13 @@ watch(
|
|||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await warningDetail({ id: query.id as string });
|
const res = await warningDetail({ id: query.id as string });
|
||||||
|
locationInfo.value = res;
|
||||||
curData.value = res;
|
curData.value = res;
|
||||||
ruleForm.name = res.rname;
|
ruleForm.name = res.rname;
|
||||||
ruleForm.username = res.rname;
|
ruleForm.username = res.rname;
|
||||||
ruleForm.content = res.rcontent;
|
ruleForm.content = res.rcontent;
|
||||||
ruleForm.images = JSON.parse(res.rimg);
|
ruleForm.images = JSON.parse(res.rimg);
|
||||||
let icon = map.newIcon(location);
|
|
||||||
let marker = map.marker({ icon, position: [116.406315, 39.908775] });
|
|
||||||
marker.setMap(map.map);
|
|
||||||
if (res.healthData && res.healthData.length) {
|
if (res.healthData && res.healthData.length) {
|
||||||
res.healthData.forEach((item) => {
|
res.healthData.forEach((item) => {
|
||||||
options.times.push(item.time);
|
options.times.push(item.time);
|
||||||
@ -253,6 +278,16 @@ const getData = async () => {
|
|||||||
});
|
});
|
||||||
myChart.setOption(options);
|
myChart.setOption(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map.clearMap();
|
||||||
|
map.setCenter([res.lng, res.lat]);
|
||||||
|
let icon = map.newIcon(location);
|
||||||
|
let marker = map.marker({ icon, position: [res.lng, res.lat] });
|
||||||
|
marker.setMap(map.map);
|
||||||
|
marker.on("click", () => {
|
||||||
|
InfoWin = map.infoWindow();
|
||||||
|
InfoWin.open(map.map, marker.getPosition());
|
||||||
|
});
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
|
@ -14,10 +14,7 @@
|
|||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" :disabled="disabled" @click="submitForm(ruleFormRef)" class="btn" size="large">登 录</el-button>
|
<el-button type="primary" :disabled="disabled" @click="submitForm(ruleFormRef)" class="btn" size="large">登 录</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="hint">
|
<div class="hint">如遇到账号问题,请联系管理员</div>
|
||||||
如遇到账号问题,请联系管理员<br />
|
|
||||||
管理员联系方式:13812345678 邮箱:123456@qq.com
|
|
||||||
</div>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,30 +8,118 @@
|
|||||||
<el-radio-button label="体表温度" value="3" />
|
<el-radio-button label="体表温度" value="3" />
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-chart">
|
<div ref="chartRef" class="card-chart"></div>
|
||||||
<slot name="chart"></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { debounce, format } from "@/utils";
|
||||||
|
import { onMounted, onUnmounted, ref } from "vue";
|
||||||
|
import * as echarts from "echarts";
|
||||||
|
|
||||||
const radio = ref("1");
|
const radio = ref("1");
|
||||||
|
const chartRef = ref(null);
|
||||||
|
let myChart: any = null;
|
||||||
const emit = defineEmits(["change"]);
|
const emit = defineEmits(["change"]);
|
||||||
defineExpose({ radio });
|
const options = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: "axis",
|
||||||
|
formatter: function (params) {
|
||||||
|
let unit = { 心率: "次/分", 血氧: "%", 体表温度: "℃" };
|
||||||
|
var res = format(options.times[params[0].dataIndex]) + "<br/>";
|
||||||
|
res += params
|
||||||
|
.map(function (param, index) {
|
||||||
|
return param.marker + param.seriesName + ":" + param.value + unit[param.seriesName] + "<br/>";
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
times: [],
|
||||||
|
xAxis: {
|
||||||
|
type: "category",
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: "value",
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: "5%",
|
||||||
|
right: "4%",
|
||||||
|
bottom: "20%",
|
||||||
|
},
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: "slider", //slider表示有滑动块的,inside表示内置的
|
||||||
|
start: 90, // 左边在 10% 的位置。
|
||||||
|
end: 100, // 右边在 60% 的位置。
|
||||||
|
show: true,
|
||||||
|
xAxisIndex: [0],
|
||||||
|
handleSize: 0, //滑动条的 左右2个滑动条的大小
|
||||||
|
height: 12, //组件高度
|
||||||
|
bottom: -2, //右边的距离
|
||||||
|
borderColor: "#eee",
|
||||||
|
fillerColor: "#E7E7E7",
|
||||||
|
backgroundColor: "#eee", //两边未选中的滑动条区域的颜色
|
||||||
|
showDataShadow: false, //是否显示数据阴影 默认auto
|
||||||
|
showDetail: false, //即拖拽时候是否显示详细数值信息 默认true
|
||||||
|
realtime: true, //是否实时更新
|
||||||
|
filterMode: "filter",
|
||||||
|
handleStyle: {
|
||||||
|
borderRadius: "20",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: {
|
||||||
|
name: "",
|
||||||
|
data: [],
|
||||||
|
type: "line",
|
||||||
|
showSymbol: false,
|
||||||
|
itemStyle: {
|
||||||
|
color: "#ff4567", // 设置线条颜色
|
||||||
|
},
|
||||||
|
smooth: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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.times.push(item.time);
|
||||||
|
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 handleResize = debounce(() => {
|
||||||
|
myChart.resize();
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
defineExpose({ radio, getOptionsData });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
myChart = echarts.init(chartRef.value);
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
});
|
||||||
const change = (e) => {
|
const change = (e) => {
|
||||||
emit("change", e);
|
emit("change", e);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.card {
|
.card {
|
||||||
// height: 100%;
|
min-height: 385px;
|
||||||
|
flex-shrink: 0;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
padding: 16px 10px;
|
padding: 16px 10px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 1;
|
|
||||||
margin-right: 20px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
@ -10,7 +10,9 @@ import { format } from "@/utils";
|
|||||||
import { MapCustom } from "@/utils/mapCustom";
|
import { MapCustom } from "@/utils/mapCustom";
|
||||||
import { onMounted, ref, watch } from "vue";
|
import { onMounted, ref, watch } from "vue";
|
||||||
import InfoWindow from "@/components/InfoWindow.vue";
|
import InfoWindow from "@/components/InfoWindow.vue";
|
||||||
import location from "@/assets/img/location.png";
|
import ViaMarker from "@/assets/img/via-marker.png";
|
||||||
|
import endMarker from "@/assets/img/end-marker.png";
|
||||||
|
import startMarker from "@/assets/img/start-marker.png";
|
||||||
|
|
||||||
let InfoWin = null;
|
let InfoWin = null;
|
||||||
let newMap = null;
|
let newMap = null;
|
||||||
@ -44,9 +46,28 @@ const getLocateRecord = () => {
|
|||||||
newMap.clearMap();
|
newMap.clearMap();
|
||||||
newMap.setCenter([list[0].lng, list[0].lat]);
|
newMap.setCenter([list[0].lng, list[0].lat]);
|
||||||
newMap.polyline(list);
|
newMap.polyline(list);
|
||||||
let icon = newMap.newIcon(location);
|
let startIcon = newMap.newIcon({
|
||||||
list.forEach((item) => {
|
image: startMarker,
|
||||||
let marker = newMap.marker({ icon, position: [item.lng, item.lat] });
|
size: [20, 29],
|
||||||
|
});
|
||||||
|
let endIcon = newMap.newIcon({
|
||||||
|
image: endMarker,
|
||||||
|
size: [20, 29],
|
||||||
|
});
|
||||||
|
let ViaIcon = newMap.newIcon({
|
||||||
|
image: ViaMarker,
|
||||||
|
size: [20, 29],
|
||||||
|
});
|
||||||
|
|
||||||
|
list.forEach((item, index) => {
|
||||||
|
let marker: any = "";
|
||||||
|
if (index == 0) {
|
||||||
|
marker = newMap.marker({ icon: startIcon, position: [item.lng, item.lat] });
|
||||||
|
} else if (index == list.length - 1) {
|
||||||
|
marker = newMap.marker({ icon: endIcon, position: [item.lng, item.lat] });
|
||||||
|
} else {
|
||||||
|
marker = newMap.marker({ icon: ViaIcon, position: [item.lng, item.lat] });
|
||||||
|
}
|
||||||
marker.setMap(newMap.map);
|
marker.setMap(newMap.map);
|
||||||
marker.on("click", () => {
|
marker.on("click", () => {
|
||||||
locationInfo.value = item;
|
locationInfo.value = item;
|
||||||
|
@ -48,7 +48,7 @@ enum warnTypeEnum {
|
|||||||
const warnTypeList = ["SOS告警", "围栏告警", "破坏告警", "低电告警", "心率告警", "血氧告警", "体温告警"];
|
const warnTypeList = ["SOS告警", "围栏告警", "破坏告警", "低电告警", "心率告警", "血氧告警", "体温告警"];
|
||||||
const paging = reactive({
|
const paging = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 4,
|
size: 5,
|
||||||
total: 0,
|
total: 0,
|
||||||
deviceId: undefined,
|
deviceId: undefined,
|
||||||
status: undefined,
|
status: undefined,
|
||||||
@ -98,10 +98,12 @@ watch(
|
|||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.card {
|
.card {
|
||||||
background: #ffffff;
|
min-height: 345px;
|
||||||
|
height: 100%;
|
||||||
padding: 16px 10px;
|
padding: 16px 10px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: #ffffff;
|
||||||
.card-head {
|
.card-head {
|
||||||
color: #061451;
|
color: #061451;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
@ -1,38 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<el-row class="el-row" :gutter="20">
|
<div class="el-row-left">
|
||||||
<el-col :span="6" class="el-row-left"
|
<DeviceInfo :deviceInfo="deviceInfo" :paging="devicePaging" :list="deviceData" :handelMode="handelMode" :load="handelLoad" @click="handelClickDevice" />
|
||||||
><DeviceInfo :deviceInfo="deviceInfo" :paging="devicePaging" :list="deviceData" :handelMode="handelMode" :load="handelLoad" @click="handelClickDevice"
|
</div>
|
||||||
/></el-col>
|
<div class="el-row-right scrollbar">
|
||||||
<el-col :span="18" class="el-row-right scrollbar">
|
<MonitoringTop :funcList="funcList" />
|
||||||
<MonitoringTop :funcList="funcList" />
|
<div class="el-row-right-content" v-if="deviceInfo?.mode == 0 || deviceInfo?.mode == 2">
|
||||||
<div class="el-row-right-content" v-if="deviceInfo?.mode == 0 || deviceInfo?.mode == 2">
|
<DeviceLocationMap :device-id="deviceInfo.deviceId" />
|
||||||
<DeviceLocationMap :device-id="deviceInfo.deviceId" />
|
<el-row class="box" :gutter="20">
|
||||||
<div class="box">
|
<el-col :span="12" :xs="24" :sm="24" :md="24" :lg="24" :xl="12" style="margin-bottom: 20px">
|
||||||
<DeviceHistory @change="handelRadio" ref="devHisRef">
|
<DeviceHistory @change="handelRadio" ref="devHisRef" />
|
||||||
<template #chart>
|
</el-col>
|
||||||
<div ref="chartRef" style="width: 100%; height: 100%"></div>
|
<el-col :span="12" :xs="24" :sm="24" :md="24" :lg="24" :xl="12">
|
||||||
</template>
|
|
||||||
</DeviceHistory>
|
|
||||||
<DeviceRecord :deviceInfo="deviceInfo" />
|
<DeviceRecord :deviceInfo="deviceInfo" />
|
||||||
</div>
|
</el-col>
|
||||||
</div>
|
</el-row>
|
||||||
<div class="el-row-right-content" v-else>
|
</div>
|
||||||
<el-row :gutter="20" style="margin-top: 20px">
|
<div class="el-row-right-content" v-else>
|
||||||
<el-col :span="24">
|
<el-row :gutter="20">
|
||||||
<DeviceHistory @change="handelRadio" ref="devHisRef">
|
<el-col :span="24" style="margin-bottom: 20px">
|
||||||
<template #chart>
|
<DeviceHistory @change="handelRadio" ref="devHisRef" />
|
||||||
<div ref="chartRef1" style="width: 100%; height: 350px"></div>
|
</el-col>
|
||||||
</template>
|
<el-col :span="24">
|
||||||
</DeviceHistory>
|
<DeviceRecord :deviceInfo="deviceInfo" />
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24" style="margin-top: 20px">
|
</el-row>
|
||||||
<DeviceRecord :deviceInfo="deviceInfo" />
|
</div>
|
||||||
</el-col>
|
</div>
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -40,21 +34,17 @@ import DeviceInfo from "./deviceInfo.vue";
|
|||||||
import MonitoringTop from "./monitoringTop.vue";
|
import MonitoringTop from "./monitoringTop.vue";
|
||||||
import DeviceHistory from "./deviceHistory.vue";
|
import DeviceHistory from "./deviceHistory.vue";
|
||||||
import DeviceRecord from "./deviceRecord.vue";
|
import DeviceRecord from "./deviceRecord.vue";
|
||||||
import * as echarts from "echarts";
|
import DeviceLocationMap from "./deviceLocationMap.vue";
|
||||||
import { deviceList, healthLatestData } from "@/api/index";
|
import { deviceList, healthLatestData } from "@/api/index";
|
||||||
import { TDevice, THealthLatestData } from "@/api/index.d";
|
import { TDevice, THealthLatestData } from "@/api/index.d";
|
||||||
import { onMounted, ref, reactive, onUnmounted, watch, nextTick } from "vue";
|
import { onMounted, ref, reactive, onUnmounted } from "vue";
|
||||||
import { debounce, format } from "@/utils";
|
import { format } from "@/utils";
|
||||||
import heart from "@/assets/img/heart.png";
|
import heart from "@/assets/img/heart.png";
|
||||||
import temperature from "@/assets/img/temperature.png";
|
import temperature from "@/assets/img/temperature.png";
|
||||||
import blood from "@/assets/img/blood.png";
|
import blood from "@/assets/img/blood.png";
|
||||||
import DeviceLocationMap from "./deviceLocationMap.vue";
|
|
||||||
|
|
||||||
const chartRef = ref(null);
|
|
||||||
const chartRef1 = ref(null);
|
|
||||||
const devHisRef = ref(null);
|
const devHisRef = ref(null);
|
||||||
const loadFlag = ref(false);
|
const loadFlag = ref(false);
|
||||||
let myChart = null;
|
|
||||||
let Interval = null;
|
let Interval = null;
|
||||||
let funcList = ref([
|
let funcList = ref([
|
||||||
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
||||||
@ -126,28 +116,6 @@ const HealthData = ref<THealthLatestData.TRes>();
|
|||||||
const deviceInfo = ref<TDevice.IListRes>();
|
const deviceInfo = ref<TDevice.IListRes>();
|
||||||
const deviceData = ref<TDevice.IListRes[]>([]);
|
const deviceData = ref<TDevice.IListRes[]>([]);
|
||||||
|
|
||||||
watch(
|
|
||||||
() => deviceInfo,
|
|
||||||
(newVal) => {
|
|
||||||
if (newVal.value) {
|
|
||||||
if (newVal.value?.mode == 0 || newVal.value?.mode == 2) {
|
|
||||||
nextTick(() => {
|
|
||||||
myChart = echarts.init(chartRef.value);
|
|
||||||
});
|
|
||||||
options.grid.left = "10%";
|
|
||||||
options.grid.bottom = "30%";
|
|
||||||
} else {
|
|
||||||
options.grid.left = "5%";
|
|
||||||
options.grid.bottom = "20%";
|
|
||||||
nextTick(() => {
|
|
||||||
myChart = echarts.init(chartRef1.value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const getdeviceList = async () => {
|
const getdeviceList = async () => {
|
||||||
const res = await deviceList(devicePaging);
|
const res = await deviceList(devicePaging);
|
||||||
deviceData.value = [...deviceData.value, ...res.records];
|
deviceData.value = [...deviceData.value, ...res.records];
|
||||||
@ -167,35 +135,19 @@ const getHealthLatestData = () => {
|
|||||||
funcList.value[0].num = res.hr;
|
funcList.value[0].num = res.hr;
|
||||||
funcList.value[1].num = res.bo;
|
funcList.value[1].num = res.bo;
|
||||||
funcList.value[2].num = res.temp;
|
funcList.value[2].num = res.temp;
|
||||||
|
|
||||||
handelRadio(devHisRef.value.radio);
|
handelRadio(devHisRef.value.radio);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handelRadio = (val: number) => {
|
const handelRadio = (val: number) => {
|
||||||
console.log("刷新");
|
|
||||||
|
|
||||||
if (val == 1) {
|
if (val == 1) {
|
||||||
getOptionsData(HealthData.value.hrArr, "心率", "#FF0303");
|
devHisRef.value?.getOptionsData(HealthData.value.hrArr, "心率", "#FF0303");
|
||||||
} else if (val == 2) {
|
} else if (val == 2) {
|
||||||
getOptionsData(HealthData.value.boArr, "血氧", "#983AFC");
|
devHisRef.value?.getOptionsData(HealthData.value.boArr, "血氧", "#983AFC");
|
||||||
} else if (val == 3) {
|
} else if (val == 3) {
|
||||||
getOptionsData(HealthData.value.tempArr, "体表温度", "#FFA91F");
|
devHisRef.value?.getOptionsData(HealthData.value.tempArr, "体表温度", "#FFA91F");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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.times.push(item.time);
|
|
||||||
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 IntervalFn = () => {
|
const IntervalFn = () => {
|
||||||
Interval = setInterval(() => {
|
Interval = setInterval(() => {
|
||||||
@ -218,47 +170,42 @@ const handelClickDevice = (val: TDevice.IListRes) => {
|
|||||||
deviceInfo.value = val;
|
deviceInfo.value = val;
|
||||||
getHealthLatestData();
|
getHealthLatestData();
|
||||||
};
|
};
|
||||||
const handleResize = debounce(() => {
|
|
||||||
myChart.resize();
|
|
||||||
}, 200);
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getdeviceList();
|
getdeviceList();
|
||||||
myChart = echarts.init(chartRef.value ? chartRef.value : chartRef1.value);
|
|
||||||
window.addEventListener("resize", handleResize);
|
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
clearInterval(Interval);
|
clearInterval(Interval);
|
||||||
window.removeEventListener("resize", handleResize);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.container {
|
.container {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
.el-row {
|
flex-direction: row;
|
||||||
flex: 1;
|
.el-row-left {
|
||||||
overflow: hidden;
|
width: 335px;
|
||||||
|
// height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
.el-row-left {
|
overflow: hidden;
|
||||||
height: 100%;
|
flex-shrink: 0;
|
||||||
display: flex;
|
}
|
||||||
|
.el-row-right {
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
margin-left: 20px;
|
||||||
|
|
||||||
|
.el-row-right-content {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
// height: 100%;
|
||||||
.el-row-right {
|
.box {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
flex-shrink: 0;
|
||||||
.el-row-right-content {
|
margin-top: 20px;
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: space-between;
|
||||||
overflow: hidden;
|
.el-col {
|
||||||
.box {
|
height: 100%;
|
||||||
height: 388px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
<template #location="{ rows }">
|
<template #location="{ rows }">
|
||||||
<el-button type="success" link :icon="View" v-if="rows.warnType == 0 || rows.warnType == 1" @click="toIncidentDispose(rows.id)"> 查看 </el-button>
|
<el-button type="success" link :icon="View" v-if="rows.warnType == 0 || rows.warnType == 1" @click="toIncidentDispose(rows.id)"> 查看 </el-button>
|
||||||
</template>
|
</template>
|
||||||
|
<template #warnType="{ rows }">
|
||||||
|
{{ warnTypeEnum[rows.warnType] }}
|
||||||
|
</template>
|
||||||
<template #status="{ rows }">
|
<template #status="{ rows }">
|
||||||
<el-tag :type="rows.status == 1 ? 'success' : 'danger'">
|
<el-tag :type="rows.status == 1 ? 'success' : 'danger'">
|
||||||
{{ statusEnum[rows.status] }}
|
{{ statusEnum[rows.status] }}
|
||||||
@ -38,6 +41,15 @@ enum statusEnum {
|
|||||||
"待处理",
|
"待处理",
|
||||||
"已处理",
|
"已处理",
|
||||||
}
|
}
|
||||||
|
enum warnTypeEnum {
|
||||||
|
"SOS告警",
|
||||||
|
"围栏告警",
|
||||||
|
"破坏告警",
|
||||||
|
"低电告警",
|
||||||
|
"心率告警",
|
||||||
|
"血氧告警",
|
||||||
|
"体温告警",
|
||||||
|
}
|
||||||
const search = ref("");
|
const search = ref("");
|
||||||
|
|
||||||
const { tableData, page, getData, changePage } = defineProps({
|
const { tableData, page, getData, changePage } = defineProps({
|
||||||
@ -66,6 +78,7 @@ const { tableData, page, getData, changePage } = defineProps({
|
|||||||
let columns = [
|
let columns = [
|
||||||
{ type: "index", label: "序号", width: 55, align: "center" },
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
{ prop: "deviceId", label: "IMEI号" },
|
{ prop: "deviceId", label: "IMEI号" },
|
||||||
|
{ prop: "warnType", label: "事件类型" },
|
||||||
{ prop: "createTime", label: "时间" },
|
{ prop: "createTime", label: "时间" },
|
||||||
{ prop: "location", label: "地理位置" },
|
{ prop: "location", label: "地理位置" },
|
||||||
{ prop: "status", label: "处理状态" },
|
{ prop: "status", label: "处理状态" },
|
||||||
|
@ -228,43 +228,36 @@ const getOrgAllList = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handelControl = (type: number) => {
|
const handelControl = (type: number) => {
|
||||||
switch (type) {
|
let api: Function;
|
||||||
case 4:
|
let params: any = {};
|
||||||
deviceGetLocation({
|
if (type == 4) {
|
||||||
deviceId: rowData.value.deviceId,
|
api = deviceGetLocation;
|
||||||
}).then(() => {
|
params = { deviceId: rowData.value.deviceId };
|
||||||
ElMessage.success("操作成功");
|
} else if (type == 5) {
|
||||||
});
|
api = setMode;
|
||||||
break;
|
params = {
|
||||||
case 5:
|
deviceId: rowData.value.deviceId,
|
||||||
setMode({
|
mode: controlForm.mode,
|
||||||
deviceId: rowData.value.deviceId,
|
};
|
||||||
mode: controlForm.mode,
|
} else if (type == 6) {
|
||||||
}).then(() => {
|
api = deviceOta;
|
||||||
getData();
|
params = rowData.value.deviceId;
|
||||||
ElMessage.success("操作成功");
|
} else {
|
||||||
});
|
let cmdEnum = {
|
||||||
break;
|
1: "poweroff",
|
||||||
case 6:
|
2: "restart",
|
||||||
deviceOta(rowData.value.deviceId).then(() => {
|
3: "factory",
|
||||||
getData();
|
};
|
||||||
ElMessage.success("操作成功");
|
api = deviceControl;
|
||||||
});
|
params = {
|
||||||
break;
|
deviceId: rowData.value.deviceId,
|
||||||
default:
|
cmd: cmdEnum[type],
|
||||||
let cmdEnum = {
|
};
|
||||||
1: "poweroff",
|
|
||||||
2: "restart",
|
|
||||||
3: "factory",
|
|
||||||
};
|
|
||||||
deviceControl({
|
|
||||||
deviceId: rowData.value.deviceId,
|
|
||||||
cmd: cmdEnum[type],
|
|
||||||
}).then(() => {
|
|
||||||
ElMessage.success("操作成功");
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
api(params).then(() => {
|
||||||
|
getData();
|
||||||
|
ElMessage.success("操作成功");
|
||||||
|
});
|
||||||
|
|
||||||
visible1.value = false;
|
visible1.value = false;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user