Commit e7939cdb authored by 张牧越's avatar 张牧越

联调安全帽、塔吊检测

parent d73c08a6
NODE_ENV = "development"
Mock: true
VUE_APP_API_URL = "http://qjwl.ythplan.com/"
VUE_APP_RESOURCE_URL= "http://qjwl.ythplan.com/"
\ No newline at end of file
NODE_ENV = "production"
Mock: false
VUE_APP_API_URL = "http://qjwl.ythplan.com/"
\ No newline at end of file
VUE_APP_RESOURCE_URL= "http://qjwl.ythplan.com/"
\ No newline at end of file
......@@ -6,7 +6,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>
绍兴二院兰亭院区(康复医院)工程
数字工地大屏
</title>
<style>
.el-icon-loading {
......@@ -24,12 +24,16 @@
.amap-copyright {
opacity: 0 !important;
}
.el-loading-mask {
z-index: 99999 !important;
}
</style>
</head>
<body style="min-width: 1300px;">
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly wi thout JavaScript enabled.
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
......
......@@ -20,13 +20,19 @@ export function getBaseData() {
})
}
export function getSecurityData() {
export function getPersonData() {
return request({
url: '/pweb/s/project/safe/statis',
url: '/pweb/s/project/person/statis',
method: 'get',
})
}
export function getAIWarningData() {
return request({
url: '/pweb/s/project/aiwarning/statis',
method: 'get',
})
}
export function getDeviceStatus() {
return request({
......@@ -141,20 +147,84 @@ export function getMonthWarningStatis() {
})
}
// tower
export function getTowerDevice(params) {
return request({
url: '/pweb/s/towercrane/device/statis',
method: 'get',
params
})
}
export function get24hTowerStatis() {
return request({
url: '/pweb/s/towercrane/statis/hour',
method: 'get'
})
}
//noise
export function getTowerWarnings() {
return request({
url: '/pweb/s/towercrane/warning/list',
method: 'get',
})
}
export function getTowerMonitors() {
return request({
url: '/pweb/s/towercrane/warning/list',
method: 'get',
})
}
export function getTowerDeviceList() {
return request({
url: '/pweb/s/towercrane/device/list',
method: 'get',
})
}
export function getCurrentTowerStatis(params) {
return request({
url: '/pweb/s/towercrane/device/actual',
method: 'get',
params
})
}
export function getDeviceDetail(deviceId) {
return request({
url: `/pweb/s/towercrane/device/${deviceId}`,
method: 'get',
})
}
export function getDeviceTodayChart(deviceId) {
return request({
url: `/pweb/s/towercrane/device/realtime/statis/${deviceId}`,
method: 'get',
})
}
//noise
export function getDeviceTotalStatus(params) {
return request({
url: '/pweb/s/device/basedata',
url: '/pweb/s/env/device/statis',
method: 'get',
params
})
}
export function getNearMonthStatis(params) {
return request({
url: '/pweb/s/env/statis',
method: 'get',
params
})
}
export function getNoiseDeviceList(params) {
return request({
url: '/pweb/s/device/list',
url: '/pweb/s/env/device/list',
method: 'get',
params
})
......@@ -162,7 +232,14 @@ export function getNoiseDeviceList(params) {
export function getCurrentMonitorStatis() {
return request({
url: '/pweb/s/env/basedata',
url: '/pweb/s/env/realtime/data',
method: 'get',
})
}
export function getTodayAqiLineChartData() {
return request({
url: '/pweb/s/env/statis/hour',
method: 'get',
})
}
......@@ -174,3 +251,38 @@ export function getWarningMessageList(params) {
params
})
}
// safecap
export function getSafeCapDeviceList(params) {
return request({
url: '/pweb/s/safetyhat/device/list',
method: 'get',
params
})
}
export function getSafeCapArea() {
return request({
url: '/pweb/s/safetyhat/project/boundary',
method: 'get',
})
}
export function getSafeCapRoute(params) {
return request({
url: '/pweb/s/safetyhat/patrol/line',
method: 'get',
params
})
}
export function getSafeCapUseRecords(params) {
return request({
url: '/pweb/s/safetyhat/device/use/list',
method: 'get',
params
})
}
......@@ -135,7 +135,7 @@
<img class="lb" src="@/assets/lb.png" alt="" />
<el-carousel :interval="5000" arrow="always" height="520px">
<el-carousel-item
v-for="(item, index) in screenDetail.plane_image_arr"
v-for="(item, index) in screenDetail.banner_image_arr"
:key="index"
>
<img class="container-img" :src="item.url" alt="" />
......@@ -217,9 +217,10 @@
<script>
import {
getBaseData,
getSecurityData,
getPersonData,
getDeviceStatus,
getProgressDetail,
getAIWarningData,
} from "@/api/index";
export default {
name: "Construction",
......@@ -252,11 +253,7 @@ export default {
{ value: 735, name: "整改中" },
{ value: 580, name: "已完成" },
],
securityPieData: {
wzg: 0,
zgz: 0,
ywc: 0,
},
personData: [],
active: 4,
deviceStatus: [
{
......@@ -321,15 +318,12 @@ export default {
zgq_num: 0,
step: 0,
},
aiwarningData: [],
};
},
methods: {
renderSecurityChart() {
const chartData = [
{ value: this.securityPieData.wzg, name: "未整改" },
{ value: this.securityPieData.zgz, name: "整改中" },
{ value: this.securityPieData.ywc, name: "已完成" },
];
renderPersonChart() {
const chartData = [...this.personData];
const chart = this.$echarts.init(this.$refs.securityChart);
let total = 0;
chartData.map((item) => {
......@@ -425,12 +419,16 @@ export default {
});
},
renderQualityChart() {
let total = 0;
this.aiwarningData.map((item) => {
total += item.value;
});
const chart = this.$echarts.init(this.$refs.qualityChart);
const option = {
title: {
x: "49%", //X坐标
y: "30%",
text: "0",
text: total,
subtext: "AI预警",
textAlign: "center",
textStyle: {
......@@ -474,7 +472,7 @@ export default {
},
},
formatter: (name) => {
let data = this.pieChartData;
let data = this.aiwarningData;
let target;
for (let i = 0, l = data.length; i < l; i++) {
if (data[i].name == name) {
......@@ -500,11 +498,20 @@ export default {
position: "center",
},
data: this.pieChartData,
data: this.aiwarningData,
},
],
};
chart.setOption(option);
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("quality-chart"));
});
},
getBaseData() {
getBaseData().then((res) => {
......@@ -512,10 +519,10 @@ export default {
this.screenDetail = res.data;
}
});
getSecurityData().then((res) => {
getPersonData().then((res) => {
if (res.status == 200) {
this.securityPieData = res.data;
this.renderSecurityChart();
this.personData = res.data;
this.renderPersonChart();
}
});
getDeviceStatus().then((res) => {
......@@ -528,20 +535,14 @@ export default {
this.progressDetail = res.data;
}
});
getAIWarningData().then((res) => {
this.aiwarningData = res.data;
this.renderQualityChart();
});
},
},
mounted() {
this.renderQualityChart();
this.getBaseData();
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("quality-chart"));
});
},
};
</script>
......
......@@ -120,8 +120,9 @@ export default {
},
screenDetail: {},
date: "",
todayPieChartData: {},
historyChartData: {},
todayPieChartData: [],
historyChartData: [],
intervalTimer: null,
};
},
methods: {
......@@ -218,10 +219,7 @@ export default {
});
},
renderTodayChart() {
const chartData = [
{ value: this.todayPieChartData.yclCount, name: "已处理" },
{ value: this.todayPieChartData.wclCount, name: "未处理" },
];
const chartData = [...this.todayPieChartData];
const chart = this.$echarts.init(this.$refs.todayChart);
let total = 0;
chartData.map((item) => {
......@@ -280,7 +278,7 @@ export default {
target = data[i].value;
}
}
let arr = [`{a|${name}}`, `{b|${target}} `];
let arr = [`{a|${name}}`, `{b|${target}} `];
return arr.join(" ");
},
},
......@@ -315,10 +313,7 @@ export default {
});
},
renderHistoryChart() {
const chartData = [
{ value: this.historyChartData.yclCount, name: "已处理" },
{ value: this.historyChartData.wclCount, name: "未处理" },
];
const chartData = [...this.historyChartData];
let total = 0;
chartData.map((item) => {
total += item.value;
......@@ -377,7 +372,7 @@ export default {
target = data[i].value;
}
}
let arr = [`{a|${name}}`, `{b|${target}} `];
let arr = [`{a|${name}}`, `{b|${target}} `];
return arr.join(" ");
},
},
......@@ -423,7 +418,7 @@ export default {
}).then((res) => {
if (res.status == 200) {
this.warningList = [...res.data];
setInterval(() => {
this.intervalTimer = setInterval(() => {
getWarningList({
start_log_time: `${this.date} 00:00:00`,
end_log_time: `${this.date} 23:59:59`,
......@@ -460,6 +455,9 @@ export default {
this.getTime();
this.getAIdata();
},
beforeDestroy() {
clearInterval(this.intervalTimer);
},
};
</script>
<style lang="less" scoped>
......
......@@ -19,18 +19,19 @@
<ShadowContainer>
<div v-for="(iType, index) in noiseTypes" :key="index" class="i-type">
<div class="i-type-name">
{{ iType.text }}
{{ iType.name }}
</div>
<div class="slider">
<el-progress
:percentage="50"
:color="customColors"
v-if="!isNaN(iType.value)"
:percentage="computedPercentage(iType.value, 30)"
:color="iType.color"
:show-text="false"
define-back-color="#183C6B"
></el-progress>
</div>
<div class="i-type-count">
<span>{{ iType.count }}</span>
<span>{{ iType.value }}</span>
</div>
</div>
......@@ -43,15 +44,13 @@
<div class="lt-status">
<el-divider></el-divider>
<el-progress
v-if="currentMonitorStatis.pm10.percentage"
type="circle"
:percentage="
computedPercentage(
currentMonitorStatis.pm10,
currentMonitorStatis.pm10_max
)
:percentage="Number(currentMonitorStatis.pm10.percentage)"
:format="
(value) => formatText(value, currentMonitorStatis.pm10.value)
"
:format="(value) => formatText(value, currentMonitorStatis.pm10)"
:color="customMonitorColors"
:color="currentMonitorStatis.pm10.color"
:stroke-width="12"
></el-progress>
<div class="status-unit">
......@@ -59,15 +58,13 @@
</div>
<el-divider></el-divider>
<el-progress
v-if="currentMonitorStatis.pm25.percentage"
type="circle"
:percentage="
computedPercentage(
currentMonitorStatis.pm25,
currentMonitorStatis.pm25_max
)
:percentage="Number(currentMonitorStatis.pm25.percentage)"
:format="
(value) => formatText(value, currentMonitorStatis.pm25.value)
"
:format="(value) => formatText(value, currentMonitorStatis.pm25)"
:color="customMonitorColors"
:color="currentMonitorStatis.pm25.color"
:stroke-width="12"
></el-progress>
<div class="status-unit">
......@@ -77,15 +74,13 @@
<el-divider></el-divider>
<el-progress
v-if="currentMonitorStatis.noise.percentage"
type="circle"
:percentage="
computedPercentage(
currentMonitorStatis.noise,
currentMonitorStatis.noise_max
)
:percentage="Number(currentMonitorStatis.noise.percentage)"
:format="
(value) => formatText(value, currentMonitorStatis.noise.value)
"
:format="(value) => formatText(value, currentMonitorStatis.noise)"
:color="customMonitorColors"
:color="currentMonitorStatis.noise.color"
:stroke-width="12"
></el-progress>
<div class="status-unit">
......@@ -101,16 +96,15 @@
<div class="aqi-level">
<div class="aqi-level-line">
<div
v-for="(color, index) in color_arr"
v-for="(color, index) in currentMonitorStatis.aqi.level_list"
:key="index"
:style="{ background: color }"
:style="{ background: color.color }"
></div>
</div>
<div class="aqi-level-text">
<div
v-for="(
aqi_level, index
) in currentMonitorStatis.aqi_level_arr"
v-for="(aqi_level, index) in currentMonitorStatis.aqi
.level_list"
:key="index"
>
{{ aqi_level.name }}
......@@ -183,7 +177,7 @@
</ShadowContainer>
</div>
<div class="side-area">
<Title text="报警信息"></Title>
<Title text="近30日报警信息"></Title>
<ShadowContainer>
<div class="warp">
<div
......@@ -225,62 +219,41 @@
<script>
import {
getDeviceTotalStatus,
getNearMonthStatis,
getCurrentMonitorStatis,
getNoiseDeviceList,
getTodayAqiLineChartData,
getWarningMessageList,
} from "@/api/index";
export default {
name: "Noise",
data() {
return {
pieChartData: {},
noiseData: [
{ value: 4, name: "达标" },
{ value: 3, name: "超标" },
],
noiseTypes: [
{ text: "优", count: 13 },
{ text: "良", count: 17 },
{ text: "轻度污染", count: 0 },
{ text: "中度污染", count: 0 },
{ text: "重度污染", count: 0 },
{ text: "严重污染", count: 0 },
],
customColors: [
{ color: "#f56c6c", percentage: 20 },
{ color: "#e6a23c", percentage: 40 },
{ color: "#5cb87a", percentage: 60 },
{ color: "#1989fa", percentage: 80 },
{ color: "#6f7ad3", percentage: 100 },
],
customMonitorColors: [
{ color: "#18D7B9", percentage: 25 },
{ color: "#2CBCFF", percentage: 50 },
{ color: "#FF754C", percentage: 75 },
{ color: "#FF754C", percentage: 100 },
],
pieChartData: [],
noiseData: [],
noiseTypes: [],
warnings: [],
noiseMonitors: [],
classOption: {
singleHeight: 36,
},
currentMonitorStatis: {
aqi_level_arr: [],
},
color_arr: [
"#18d7b9",
"#feba01",
"#ff754c",
"#f11b1f",
"#6339e6",
"#751dbf",
],
aqi: {
level_list: [],
},
pm10: {},
pm25: {},
noise: {},
},
aqiLineChartData: [],
};
},
computed: {},
methods: {
computedPercentage(value, max) {
return Number(Number(Number(value) / max) * 100).toFixed(2);
return Number(
Number(Number(Number(value) / Number(max)) * 100).toFixed(2)
);
},
getTime(ts) {
let date = new Date(ts);
......@@ -299,11 +272,7 @@ export default {
return `${today} ${hour}:${min}:${sec}`;
},
renderDeviceChart() {
const pieData = [
{ value: this.pieChartData.zxCount, name: "在线设备数量" },
{ value: this.pieChartData.lxCount, name: "离线设备数量" },
{ value: this.pieChartData.bjCount, name: "报警设备数量" },
];
const pieData = [...this.pieChartData];
const chart = this.$echarts.init(this.$refs.deviceChart);
let total = 0;
pieData.map((item) => {
......@@ -397,6 +366,7 @@ export default {
});
},
renderNoiseChart() {
const chartData = [...this.noiseData];
const chart = this.$echarts.init(this.$refs.noiseChart);
const option = {
title: {
......@@ -404,7 +374,6 @@ export default {
y: "32%",
subtext: "近30日\n噪音情况",
textAlign: "center",
subtextStyle: {
//副标题样式
fontSize: 16,
......@@ -439,7 +408,7 @@ export default {
},
},
formatter: (name) => {
let data = this.noiseData;
let data = chartData;
let target;
for (let i = 0, l = data.length; i < l; i++) {
if (data[i].name == name) {
......@@ -465,13 +434,28 @@ export default {
position: "center",
},
data: this.noiseData,
data: chartData,
},
],
};
chart.setOption(option);
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("noise-chart"));
});
},
renderAQIChart() {
const xAxisData = this.aqiLineChartData.map((item) => {
return item.hour;
});
const yAxisData = this.aqiLineChartData.map((item) => {
return item.aqi_value;
});
const chart = this.$echarts.init(this.$refs.aqiChart);
const option = {
color: ["#5E97F6"],
......@@ -486,7 +470,7 @@ export default {
},
xAxis: {
type: "category",
data: ["09:00", "12:00", "13:00", "16:00", "19:00", "22:00", "01:00"],
data: xAxisData,
axisTick: { show: false },
axisLabel: {
fontSize: "12",
......@@ -508,8 +492,7 @@ export default {
},
series: [
{
name: "NJBR-TD-01#",
data: [2, 5, 4, 4, 7, 5, 6],
data: yAxisData,
type: "line",
smooth: true,
areaStyle: {
......@@ -528,36 +511,33 @@ export default {
],
};
chart.setOption(option);
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("aqi-chart"));
});
},
formatText(value, text) {
return text;
return String(text);
},
renderAqiQualityChart() {
this.currentMonitorStatis.aqi_level_arr.map((item, index) => {
item.color = this.color_arr[index];
});
const currentLevel = this.currentMonitorStatis.aqi_level_arr.filter(
(item) => {
return (
Number(this.currentMonitorStatis.aqi) >= item.min &&
Number(this.currentMonitorStatis.aqi) < item.max
);
}
)[0];
console.log(currentLevel);
const chart = this.$echarts.init(this.$refs.aqiQualityChart);
const option = {
title: {
x: "49%", //X坐标
y: "64%",
subtext: this.currentMonitorStatis.aqi_level_name,
subtext: this.currentMonitorStatis.aqi.level,
textAlign: "center",
subtextStyle: {
//副标题样式
fontSize: 24,
fontWeight: "bolder",
lineHeight: 24,
color: currentLevel.color,
color: this.currentMonitorStatis.aqi.color,
},
},
series: [
......@@ -566,12 +546,10 @@ export default {
center: ["50%", "60%"],
startAngle: 230,
endAngle: -50,
min: this.currentMonitorStatis.aqi_level_arr[0].min,
max: this.currentMonitorStatis.aqi_level_arr[
this.currentMonitorStatis.aqi_level_arr.length - 1
].max,
min: 0,
max: 100,
itemStyle: {
color: currentLevel.color,
color: this.currentMonitorStatis.aqi.color,
},
progress: {
show: true,
......@@ -614,12 +592,14 @@ export default {
offsetCenter: [0, -10],
fontSize: 46,
fontWeight: "bolder",
formatter: "{value}",
formatter: () => {
return this.currentMonitorStatis.aqi.value;
},
color: "#fff",
},
data: [
{
value: Number(this.currentMonitorStatis.aqi),
value: Number(this.currentMonitorStatis.aqi.percentage),
},
],
},
......@@ -641,12 +621,26 @@ export default {
this.pieChartData = res.data;
this.renderDeviceChart();
});
getNearMonthStatis({
start_log_time: this.getTime(new Date().getTime() - 2592000000),
end_log_time: this.getTime(new Date().getTime()),
}).then((res) => {
this.noiseData = res.data.noise_data;
this.noiseTypes = res.data.aqi_data;
this.renderNoiseChart();
});
getCurrentMonitorStatis().then((res) => {
this.currentMonitorStatis = res.data;
this.$nextTick(() => {
this.renderAqiQualityChart();
});
});
getTodayAqiLineChartData().then((res) => {
this.aqiLineChartData = res.data;
this.$nextTick(() => {
this.renderAQIChart();
});
});
getWarningMessageList({
start_log_time: this.getTime(new Date().getTime() - 2592000000),
end_log_time: this.getTime(new Date().getTime()),
......@@ -660,19 +654,6 @@ export default {
},
mounted() {
this.getNoiseData();
this.renderNoiseChart();
this.renderAQIChart();
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("noise-chart"));
resizeOb.observe(document.getElementById("aqi-chart"));
// resizeOb.observe(document.getElementById("aqi-quality-chart"));
});
},
};
</script>
......
......@@ -161,6 +161,7 @@
).toFixed(2)
)
"
disabled
></el-slider>
</div>
<div class="i-type-count">
......@@ -196,11 +197,12 @@ export default {
},
screenDetail: {},
inOutData: [],
personAreaDetail: {},
personAreaDetail: [],
lastweekAttendanceData: [],
lastweekWorkTypeData: [],
industryTypesTotal: 0,
date: "",
intervalTimer: null,
};
},
methods: {
......@@ -217,20 +219,7 @@ export default {
renderAreaChart() {
const chart = this.$echarts.init(this.$refs.areaChart);
const areaData = [
{
value: this.personAreaDetail.city_person_num,
name: this.personAreaDetail.city_name,
},
{
value: this.personAreaDetail.province_in_city_out_person_num,
name: this.personAreaDetail.province_in_city_out_name,
},
{
value: this.personAreaDetail.province_out_person_num,
name: this.personAreaDetail.province_out_name,
},
];
const areaData = [...this.personAreaDetail];
const option = {
title: {
x: "27%", //X坐标
......@@ -573,7 +562,7 @@ export default {
end_date: this.date,
}).then((res) => {
this.checkList = [...res.data];
setInterval(() => {
this.intervalTimer = setInterval(() => {
getCurrentAttendance({
start_date: this.date,
end_date: this.date,
......@@ -615,6 +604,9 @@ export default {
this.getTime();
this.getRealNameStatus();
},
beforeDestroy() {
clearInterval(this.intervalTimer);
},
};
</script>
<style lang="less" scoped>
......
......@@ -5,6 +5,8 @@
prefix-icon="el-icon-search"
placeholder="设备编号/佩戴人员名称"
style="margin-bottom: 20px"
v-model="keywords"
@input="searchDevice"
></el-input>
<ShadowContainer>
<div id="cap-list">
......@@ -12,11 +14,12 @@
class="device-user"
v-for="(device, index) in deviceList"
:key="index"
@click="moveToDevice(device)"
>
<div>
<img
:src="
device.online
device.is_online == 1
? require('@/assets/safecap/cap-online.png')
: require('@/assets/safecap/cap-offline.png')
"
......@@ -24,11 +27,13 @@
/>
</div>
<div class="device-description">
<div>{{ device.occupation }} / {{ device.name }}</div>
<div>绑定设备:{{ device.deviceCode }}</div>
<div>{{ device.person_type }} / {{ device.person_name }}</div>
<div>绑定设备:{{ device.name }}</div>
</div>
<div :class="['status', device.online ? 'online' : 'offline']">
{{ device.status }}
<div
:class="['status', device.is_online == 1 ? 'online' : 'offline']"
>
{{ device.is_online_text }}
</div>
</div>
</div>
......@@ -45,30 +50,35 @@
<div class="cap-description">
<img
:src="
windowData.online
windowData.is_online == 1
? require('@/assets/safecap/cap-online.png')
: require('@/assets/safecap/cap-offline.png')
"
alt=""
/>
SBBH-38436 /
{{ windowData.name }} /
<span
:class="[
'online-status',
windowData.online ? 'online' : 'offline',
windowData.is_online == 1 ? 'online' : 'offline',
]"
>在线</span
>{{ windowData.is_online_text }}</span
>
<span class="name"
>{{ windowData.person_type }} / {{ windowData.person_name }}</span
>
<span class="name">经理 / 王一</span>
</div>
<div class="recent-open">最近使用:2023-03-12</div>
<div class="recent-open">最近使用:{{ windowData.last_use_time }}</div>
<div class="cap-operation">
<div
:class="['cap-button', windowData.online ? 'active' : 'disabled']"
:class="[
'cap-button',
windowData.is_online == 1 ? 'active' : 'disabled',
]"
>
<img
:src="
windowData.online
windowData.is_online == 1
? require('@/assets/safecap/watch-visory.png')
: require('@/assets/safecap/watch-visory-disabled.png')
"
......@@ -77,11 +87,14 @@
<div class="cap-text">查看监控</div>
</div>
<div
:class="['cap-button', windowData.online ? 'active' : 'disabled']"
:class="[
'cap-button',
windowData.is_online == 1 ? 'active' : 'disabled',
]"
>
<img
:src="
windowData.online
windowData.is_online == 1
? require('@/assets/safecap/phone.png')
: require('@/assets/safecap/phone-disabled.png')
"
......@@ -90,11 +103,15 @@
<div class="cap-text">语音通话</div>
</div>
<div
:class="['cap-button', windowData.online ? 'active' : 'disabled']"
:class="[
'cap-button',
windowData.is_online == 1 ? 'active' : 'disabled',
]"
@click="showCurrentRoute"
>
<img
:src="
windowData.online
windowData.is_online == 1
? require('@/assets/safecap/current-route.png')
: require('@/assets/safecap/current-route-disabled.png')
"
......@@ -102,7 +119,7 @@
/>
<div class="cap-text">当前轨迹</div>
</div>
<div class="cap-button active">
<div class="cap-button active" @click="showHistory">
<img src="@/assets/safecap/history-route.png" alt="" />
<div class="cap-text">历史轨迹</div>
</div>
......@@ -118,19 +135,18 @@
<el-form inline :model="searchForm">
<el-form-item label="使用日期">
<el-date-picker
v-model="searchForm.useDate"
v-model="searchForm.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
>
</el-date-picker>
</el-form-item>
<el-form-item label="设备名称">
<el-input v-model="searchForm.deviceName"></el-input>
</el-form-item>
<el-form-item>
<el-button
@click="searchRecords"
style="background: rgba(19, 168, 195, 1); color: #fff; border: none"
>查询</el-button
>
......@@ -138,32 +154,20 @@
</el-form>
<el-table :data="tableData" height="550px" stripe>
<el-table-column
label="设备编号"
prop="deviceNo"
align="center"
></el-table-column>
<el-table-column
label="使用职位"
prop="use"
prop="use_job"
align="center"
width="90"
></el-table-column>
<el-table-column
label="开机时间"
prop="online_time"
align="center"
></el-table-column>
<el-table-column
label="关机时间"
prop="offline_time"
label="最近使用时间"
prop="use_time"
align="center"
></el-table-column>
<el-table-column
label="设备绑定人员"
prop="bind_user"
prop="bind_person"
align="center"
width="110"
></el-table-column>
<el-table-column label="巡查轨迹" align="center" width="90">
<template slot-scope="scope">
......@@ -186,83 +190,59 @@
>
</el-pagination>
</el-dialog>
<map-dialog
:userId="currentUserId"
:visible="mapVisible"
@changeVisible="(val) => (mapVisible = val)"
></map-dialog>
</div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
import onlineIcon from "@/assets/safecap/online.png";
import offlineIcon from "@/assets/safecap/offline.png";
import {
getBaseInfo,
getSafeCapDeviceList,
getSafeCapArea,
getSafeCapUseRecords,
} from "@/api/index";
import mapDialog from "./mapDialog.vue";
import _ from "lodash";
export default {
name: "Safecap",
components: { mapDialog },
data() {
return {
markers: [
{
position: [116.377809, 39.878726],
online: true,
},
{
position: [116.376809, 39.878726],
online: false,
},
],
keywords: "",
markers: [],
map: null,
Amap: null, //高德地图amap方法实例
capWindowVisible: true,
capWindowVisible: false,
windowData: {
online: true,
},
deviceList: [
{
name: "王一",
status: "在线",
online: true,
deviceCode: "SBBH-38436",
occupation: "监理员",
},
{
name: "王一",
status: "离线",
online: false,
deviceCode: "SBBH-38436",
occupation: "监理员",
},
],
deviceList: [],
searchForm: {
useDate: [],
deviceName: "",
dateRange: ["", ""],
},
historyRouteVisible: false,
total: 100,
total: 0,
pageSize: 10,
currentPage: 1,
tableData: [
{
deviceNo: "SBBH-383476",
use: "监理人员",
online_time: "2023-03-12 00:00:00",
offline_time: "2023-03-12 00:00:00",
bind_user: "王一",
},
{
deviceNo: "SBBH-383476",
use: "监理人员",
online_time: "2023-03-12 00:00:00",
offline_time: "2023-03-12 00:00:00",
bind_user: "王一",
},
{
deviceNo: "SBBH-383476",
use: "监理人员",
online_time: "2023-03-12 00:00:00",
offline_time: "2023-03-12 00:00:00",
bind_user: "王一",
},
],
tableData: [],
mapCenter: [],
currentUserId: "",
mapVisible: false,
};
},
mounted() {
getBaseInfo().then((res) => {
this.mapCenter = [res.data.longitude, res.data.latitude];
this.$nextTick(() => {
this.initMap();
});
});
},
methods: {
initMap() {
......@@ -277,7 +257,7 @@ export default {
this.map = new AMap.Map("amap-container", {
viewMode: "2D",
zoom: 20,
center: [116.377809, 39.878726],
center: this.mapCenter,
resizeEnable: true,
mapStyle: "amap://styles/darkblue",
});
......@@ -285,17 +265,18 @@ export default {
console.log(e);
this.capWindowVisible = false;
});
this.setMarker();
this.getSafeCapDeviceList();
this.getSafeCapArea();
})
.catch((e) => {
console.log(e);
});
},
setMarker() {
this.markers.map((marker) => {
this.deviceList.map((marker) => {
const mapMarkers = new this.AMap.Marker({
icon: marker.online ? onlineIcon : offlineIcon,
position: marker.position,
icon: marker.is_online == 1 ? onlineIcon : offlineIcon,
position: [marker.longitude, marker.latitude],
offset: new this.AMap.Pixel(-25, -25),
extData: {
markerData: marker,
......@@ -303,24 +284,112 @@ export default {
});
mapMarkers.setMap(this.map);
mapMarkers.on("click", (e) => {
// 获取当前marker绑定data
console.log(e.target.getExtData());
this.map.setCenter([e.lnglat.getLng(), e.lnglat.getLat()]);
const markData = e.target.getExtData().markerData;
this.map.setCenter([markData.longitude, markData.latitude]);
this.windowData = markData;
this.$nextTick(() => {
this.showCapWindow();
});
});
});
},
showCapWindow() {
this.capWindowVisible = true;
},
handleCurrentChange(current) {
console.log(current);
getSafeCapUseRecords({
device_id: this.windowData.id,
start_time: this.searchForm.dateRange[0],
end_time: this.searchForm.dateRange[1],
limit: this.pageSize,
page: current,
}).then((res) => {
this.total = res.data.total;
this.tableData = res.data.data;
this.currentPage = current;
});
},
handleSizeChange(size) {
console.log(size);
getSafeCapUseRecords({
device_id: this.windowData.id,
start_time: this.searchForm.dateRange[0],
end_time: this.searchForm.dateRange[1],
limit: size,
page: 1,
}).then((res) => {
this.total = res.data.total;
this.tableData = res.data.data;
this.currentPage = 1;
});
},
showRoute(scope) {
this.historyRouteVisible = false;
this.currentUserId = scope.row.person_device_bind_id;
this.mapVisible = true;
},
getSafeCapDeviceList() {
getSafeCapDeviceList().then((res) => {
this.deviceList = res.data;
this.setMarker();
});
},
getSafeCapArea() {
getSafeCapArea().then((res) => {
res.data.map((area) => {
area.points.map((item) => {
new this.AMap.Polyline({
path: item.points.map((point) => {
return [Number(point.lng), Number(point.lat)];
}),
map: this.map,
strokeColor: item.color,
strokeStyle: item.lineStyle,
strokeWeight: item.weight,
});
});
});
});
},
moveToDevice(device) {
this.windowData = device;
this.capWindowVisible = true;
this.map.setCenter([device.longitude, device.latitude]);
},
searchDevice: _.debounce(function () {
getSafeCapDeviceList({ keywords: this.keywords }).then((res) => {
this.deviceList = res.data;
this.setMarker();
});
}, 2000),
showCurrentRoute() {
if (this.windowData.is_online != 1) {
return;
}
this.currentUserId = this.windowData.id;
this.mapVisible = true;
},
showRoute(row) {
console.log(row);
showHistory() {
this.historyRouteVisible = true;
this.searchForm.dateRange = ["", ""];
getSafeCapUseRecords({ device_id: this.windowData.id }).then((res) => {
this.total = res.data.total;
this.tableData = res.data.data;
this.currentPage = 1;
});
},
searchRecords() {
getSafeCapUseRecords({
device_id: this.windowData.id,
start_time: this.searchForm.dateRange[0],
end_time: this.searchForm.dateRange[1],
limit: this.pageSize,
page: 1,
}).then((res) => {
this.total = res.data.total;
this.tableData = res.data.data;
this.currentPage = 1;
});
},
},
};
......
<template>
<el-dialog
:visible.sync="dialogVisible"
title="使用轨迹"
width="80vw"
top="10vh"
append-to-body
>
<div>
<el-form inline>
<el-form-item label="使用日期">
<el-date-picker
type="date"
v-model="date"
value-format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-select v-model="hour">
<el-option
v-for="hour in 24"
:key="hour"
:label="`${hour}时`"
:value="hour"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button
@click="search"
style="background: rgba(19, 168, 195, 1); color: #fff; border: none"
>查询</el-button
>
</el-form-item>
</el-form>
<div id="route-map-container"></div>
</div>
</el-dialog>
</template>
<script>
import { getBaseInfo, getSafeCapRoute } from "@/api/index";
import AMapLoader from "@amap/amap-jsapi-loader";
export default {
name: "MapDialog",
props: {
visible: {
type: Boolean,
default: false,
},
userId: {
type: [String, Number],
default: "",
},
},
data() {
return {
date: "",
map: null,
Amap: null, //高德地图amap方法实例
mapCenter: [],
hour: "",
};
},
methods: {
getTime() {
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
month = month > 9 ? month : "0" + month;
day = day < 10 ? "0" + day : day;
let today = year + "-" + month + "-" + day;
this.date = today;
this.hour =
date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
},
init() {
getBaseInfo().then((res) => {
this.mapCenter = [res.data.longitude, res.data.latitude];
this.$nextTick(() => {
this.initMap();
});
});
},
initMap() {
AMapLoader.load({
key: "fc00c5b70f67a8414344682f217d4b6e",
version: "1.4.15",
plugins: ["AMap.MarkerClusterer", "AMap.DistrictSearch"],
}).then((AMap) => {
// 初始化地图
this.AMap = AMap;
this.map = new AMap.Map("route-map-container", {
viewMode: "2D",
zoom: 20,
center: this.mapCenter,
resizeEnable: true,
mapStyle: "amap://styles/darkblue",
});
this.search();
});
},
search() {
this.map.clearMap();
getSafeCapRoute({
bind_id: this.userId,
start_time: `${this.date} ${this.hour}:00:00`,
}).then((res) => {
const paths = res.data.line.map((point) => {
return [point.longitude, point.latitude];
});
new this.AMap.Polyline({
path: paths,
map: this.map,
showDir: true,
strokeColor: "#3366bb",
strokeWeight: 8,
});
});
},
},
computed: {
dialogVisible: {
get() {
return this.visible;
},
set(val) {
this.$emit("changeVisible", val);
},
},
},
watch: {
dialogVisible(val) {
if (val) {
this.$nextTick(() => {
this.getTime();
this.init();
});
}
},
},
};
</script>
<style lang="less" scoped>
#route-map-container {
width: 100%;
height: 700px;
}
</style>
\ No newline at end of file
......@@ -70,16 +70,6 @@
</div>
</div>
</div>
<el-dialog :visible.sync="liveVisible" append-to-body title="查看监控">
<div id="video-container">
<video
id="singleVideo"
autoplay="autoplay"
class="video-js vjs-default-skin"
></video>
</div>
</el-dialog>
</div>
</template>
<script>
......
......@@ -23,125 +23,142 @@
<img class="rt" src="@/assets/rt.png" alt="" />
<img class="rb" src="@/assets/rb.png" alt="" />
<img class="lb" src="@/assets/lb.png" alt="" />
<img class="container-img" src="@/assets/swiper-pic.png" alt="" />
<div id="amap-container"></div>
<div class="towerwindow" v-if="towerWindowVisible">
<div class="tower-description">
<img
:src="
windowData.is_online == 1
? require('@/assets/zhongji_online.png')
: require('@/assets/zhongji.png')
"
alt=""
/>
{{ windowData.device_sn }} /
<span
:class="[
'online-status',
windowData.is_online == 1 ? 'online' : 'offline',
]"
>{{ windowData.is_online_text }}</span
>
<span @click="openDetailDialog" class="name" style="cursor: pointer"
>详情
<img
style="width: 20px; vertical-align: top; margin-top: 4px"
src="@/assets/tower/arrow.png"
alt=""
/>
</span>
</div>
<div class="recent-open">最近使用:{{ windowData.log_time }}</div>
</div>
</div>
<device-dialog
:deviceId="windowData.id"
:deviceData="deviceData"
:visible="deviceDialogVisible"
@changeVisible="(val) => (deviceDialogVisible = val)"
></device-dialog>
</div>
<div class="side-area">
<Title text="报警信息"></Title>
<ShadowContainer>
<div class="warn-message">
<div class="warn-icon">
<div class="warn-icon" v-if="warnings.length == 0">
<img src="@/assets/no-message.png" alt="" />
<div>暂无信息~</div>
</div>
<div class="warp" v-else>
<div
class="warn-title"
v-for="(warn, index) in warnings"
:key="index"
>
<div class="warn-text">
<el-tooltip
class="item"
effect="dark"
:content="warn.alarm_content"
>
<div class="overflowed">
{{ warn.alarm_content }}
</div>
</el-tooltip>
</div>
<div class="warn-time">{{ warn.log_time }}</div>
</div>
</div>
</div>
</ShadowContainer>
<Title text="维护信息"></Title>
<Title text="设备列表"></Title>
<ShadowContainer>
<div class="tower-name">NJBR-TD-02#</div>
<div class="steps">
<el-steps :active="active" finish-status="success">
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">开工</div>
</template>
</el-step>
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">工程一</div>
</template>
</el-step>
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">工程二</div>
</template>
</el-step>
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">工程二</div>
</template>
</el-step>
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">工程二</div>
</template>
</el-step>
</el-steps>
<div class="monitor-list">
<div
class="noise-monitor"
v-for="(monitor, index) in monitors"
:key="index"
@click="moveToMonitor(monitor)"
>
<img
:src="
monitor.is_online == 1
? require('@/assets/zhongji_online.png')
: require('@/assets/zhongji.png')
"
alt=""
/>
{{ monitor.device_sn }}
<span
:style="{
color: monitor.is_online_text == '在线' ? '#3eec6f' : '',
}"
>{{ monitor.is_online_text }}</span
>
</div>
<el-divider></el-divider>
<div class="tower-name">NJBR-TD-02#</div>
<div class="steps">
<el-steps :active="active" finish-status="success">
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">开工</div>
</template>
</el-step>
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">工程一</div>
</template>
</el-step>
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">工程二</div>
</template>
</el-step>
<el-step>
<template #title>
<div class="step-title">2022-02-19</div>
</template>
<template #description>
<div class="step-description">工程二</div>
</template>
</el-step>
</el-steps>
</div>
</ShadowContainer>
</div>
</div>
</template>
<script>
import { getDeviceTotalStatus } from "@/api/index";
import AMapLoader from "@amap/amap-jsapi-loader";
import onlineIcon from "@/assets/tower/online_tower.png";
import offlineIcon from "@/assets/tower/offline_tower.png";
import deviceDialog from "./deviceDialog.vue";
import hooks from "@/assets/tower/hooks.png";
import {
getBaseInfo,
getTowerDevice,
get24hTowerStatis,
getTowerWarnings,
getTowerDeviceList,
getCurrentTowerStatis,
getDeviceDetail,
} from "@/api/index";
export default {
name: "Tower",
components: { deviceDialog },
data() {
return {
pieChartData: {},
active: 3,
pieChartData: [],
warnings: [],
monitors: [],
mapCenter: [],
AMap: null,
map: null,
towerWindowVisible: false,
windowData: {},
polyLineArray: [],
timer: null,
deviceDialogVisible: false,
deviceData: {},
markerArray: [],
};
},
methods: {
renderDeviceChart() {
const pieData = [
{ value: this.pieChartData.zxCount, name: "在线设备数量" },
{ value: this.pieChartData.lxCount, name: "离线设备数量" },
{ value: this.pieChartData.bjCount, name: "报警设备数量" },
];
const pieData = [...this.pieChartData];
const chart = this.$echarts.init(this.$refs.deviceChart);
let total = 0;
pieData.map((item) => {
......@@ -234,9 +251,21 @@ export default {
});
},
renderForceChart() {
const xAxisData = this.towerData[0].data.map((item) => {
return item.time;
});
const seriesData = this.towerData.map((series) => {
return {
name: series.name,
type: "line",
smooth: true,
data: series.data.map((item) => {
return item.moment_rate;
}),
};
});
const chart = this.$echarts.init(this.$refs.forceChart);
const option = {
color: ["#FFAF51", "#00a2ff"],
grid: {
top: 30,
bottom: 30,
......@@ -252,9 +281,12 @@ export default {
color: "rgba(225, 239, 255, 0.7)",
},
},
tooltip: {
trigger: "item",
},
xAxis: {
type: "category",
data: ["09:00", "12:00", "13:00", "16:00", "19:00", "22:00", "01:00"],
data: xAxisData,
axisTick: { show: false },
axisLabel: {
fontSize: "12",
......@@ -274,51 +306,35 @@ export default {
},
},
},
series: [
{
name: "NJBR-TD-01#",
data: [2, 5, 4, 4, 7, 5, 6],
type: "line",
smooth: true,
areaStyle: {
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#FFAF51",
},
{
offset: 1,
color: "rgba(0,0,0,0)",
},
]),
},
},
{
name: "NJBR-TD-02#",
type: "line",
data: [5, 2, 3, 4, 2, 2, 4],
smooth: true,
areaStyle: {
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#00a2ff",
},
{
offset: 1,
color: "rgba(0,0,0,0)",
},
]),
},
},
],
series: seriesData,
};
chart.setOption(option);
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("force-chart"));
});
},
renderDipChart() {
const xAxisData = this.towerData[0].data.map((item) => {
return item.time;
});
const seriesData = this.towerData.map((series) => {
return {
name: series.name,
type: "line",
smooth: true,
data: series.data.map((item) => {
return item.dip_angle;
}),
};
});
const chart = this.$echarts.init(this.$refs.dipChart);
const option = {
color: ["#E965C2", "#00FFDE"],
grid: {
top: 30,
bottom: 30,
......@@ -336,7 +352,7 @@ export default {
},
xAxis: {
type: "category",
data: ["09:00", "12:00", "13:00", "16:00", "19:00", "22:00", "01:00"],
data: xAxisData,
axisTick: { show: false },
axisLabel: {
fontSize: "12",
......@@ -356,69 +372,262 @@ export default {
},
},
},
series: [
{
name: "NJBR-TD-01#",
data: [2, 5, 4, 4, 7, 5, 6],
type: "line",
smooth: true,
areaStyle: {
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#E965C2",
},
{
offset: 1,
color: "rgba(0,0,0,0)",
},
]),
},
},
{
name: "NJBR-TD-02#",
type: "line",
data: [5, 2, 3, 4, 2, 2, 4],
smooth: true,
areaStyle: {
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#00FFDE",
},
{
offset: 1,
color: "rgba(0,0,0,0)",
},
]),
},
},
],
series: seriesData,
};
chart.setOption(option);
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("dip-chart"));
});
},
getTowerData() {
getDeviceTotalStatus({ top_cat: 1, child_cat: 1 }).then((res) => {
getTowerDevice({ top_cat: 1, child_cat: 1 }).then((res) => {
this.pieChartData = res.data;
this.renderDeviceChart();
});
},
},
mounted() {
this.getTowerData();
get24hTowerStatis().then((res) => {
this.towerData = res.data;
this.renderForceChart();
this.renderDipChart();
});
getTowerWarnings().then((res) => {
this.warnings = res.data;
});
getBaseInfo().then((res) => {
this.mapCenter = [res.data.longitude, res.data.latitude];
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
this.initMap();
});
});
},
initMap() {
AMapLoader.load({
key: "fc00c5b70f67a8414344682f217d4b6e",
version: "1.4.15",
plugins: ["AMap.MarkerClusterer", "AMap.DistrictSearch"],
})
.then((AMap) => {
// 初始化地图
this.AMap = AMap;
this.map = new AMap.Map("amap-container", {
viewMode: "2D",
zoom: 19,
center: this.mapCenter,
resizeEnable: true,
mapStyle: "amap://styles/darkblue",
});
this.map.on("click", (e) => {
console.log(e);
this.towerWindowVisible = false;
});
getTowerDeviceList().then((res) => {
this.monitors = res.data;
this.setMarker();
});
})
.catch((e) => {
console.log(e);
});
},
setMarker() {
this.monitors.map((marker) => {
const mapMarkers = new this.AMap.Marker({
icon: marker.is_online == 1 ? onlineIcon : offlineIcon,
position: [marker.longitude, marker.latitude],
offset: new this.AMap.Pixel(-25, -25),
extData: {
markerData: marker,
},
});
mapMarkers.setMap(this.map);
mapMarkers.on("click", (e) => {
const markData = e.target.getExtData().markerData;
this.map.setCenter([markData.longitude, markData.latitude]);
this.windowData = markData;
this.$nextTick(() => {
this.towerWindowVisible = true;
});
});
const circles = new this.AMap.Circle({
center: [marker.longitude, marker.latitude], // 圆心位置
radius: marker.arm_length, //半径
strokeColor: "#FF33FF", //线颜色
strokeOpacity: 0.5, //线透明度
strokeWeight: 3, //线宽
strokeStyle: "dashed",
fillColor: "#1791fc", //填充色
fillOpacity: 0.2, //填充透明度
});
circles.setMap(this.map);
});
this.getCurrentTowerStatis();
this.timer = setInterval(() => {
this.getCurrentTowerStatis();
}, 60000);
},
moveToMonitor(monitor) {
this.map.setCenter([monitor.longitude, monitor.latitude]);
this.windowData = monitor;
this.towerWindowVisible = true;
},
openDetailDialog() {
getDeviceDetail(this.windowData.id).then((res) => {
this.deviceData = res.data;
this.$nextTick(() => {
this.deviceDialogVisible = true;
});
});
},
getLngAndLat(lng, lat, brng, dist) {
var a = 6378137;
var b = 6356752.3142;
var f = 1 / 298.257223563;
var lon1 = lng * 1;
var lat1 = lat * 1;
var s = dist;
var alpha1 = this.rad(brng - 90);
var sinAlpha1 = Math.sin(alpha1);
var cosAlpha1 = Math.cos(alpha1);
var tanU1 = (1 - f) * Math.tan(this.rad(lat1));
var cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1),
sinU1 = tanU1 * cosU1;
var sigma1 = Math.atan2(tanU1, cosAlpha1);
var sinAlpha = cosU1 * sinAlpha1;
var cosSqAlpha = 1 - sinAlpha * sinAlpha;
var uSq = (cosSqAlpha * (a * a - b * b)) / (b * b);
var A =
1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
var sigma = s / (b * A),
sigmaP = 2 * Math.PI;
while (Math.abs(sigma - sigmaP) > 1e-12) {
var cos2SigmaM = Math.cos(2 * sigma1 + sigma);
var sinSigma = Math.sin(sigma);
var cosSigma = Math.cos(sigma);
var deltaSigma =
B *
sinSigma *
(cos2SigmaM +
(B / 4) *
(cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
(B / 6) *
cos2SigmaM *
(-3 + 4 * sinSigma * sinSigma) *
(-3 + 4 * cos2SigmaM * cos2SigmaM)));
sigmaP = sigma;
sigma = s / (b * A) + deltaSigma;
}
var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
var lat2 = Math.atan2(
sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
(1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)
);
var lambda = Math.atan2(
sinSigma * sinAlpha1,
cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1
);
var C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
var L =
lambda -
(1 - C) *
f *
sinAlpha *
(sigma +
C *
sinSigma *
(cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
var revAz = Math.atan2(sinAlpha, -tmp); // final bearing
console.log(revAz);
var lngLatObj = {
lng: lon1 + this.deg(L),
lat: this.deg(lat2),
};
return lngLatObj;
},
rad(d) {
return (d * Math.PI) / 180.0;
},
deg(d) {
return (d * 180) / Math.PI;
},
getCurrentTowerStatis() {
this.polyLineArray.map((item) => {
this.map.remove(item);
});
// resizeOb.observe(document.getElementById("device-chart"));
resizeOb.observe(document.getElementById("force-chart"));
resizeOb.observe(document.getElementById("dip-chart"));
this.markerArray.map((item) => {
this.map.remove(item);
});
const monitorIds = this.monitors
.map((item) => {
return item.id;
})
.join(",");
getCurrentTowerStatis({ device_ids: monitorIds }).then((res) => {
res.data.map((monitor) => {
const filterItem = this.monitors.filter((item) => {
return monitor.device_id == item.id;
})[0];
const startPosition = [filterItem.longitude, filterItem.latitude];
const endPosition = [
this.getLngAndLat(
filterItem.longitude,
filterItem.latitude,
monitor.rotation,
filterItem.arm_length
).lng,
this.getLngAndLat(
filterItem.longitude,
filterItem.latitude,
monitor.rotation, //0度是正东
filterItem.arm_length
).lat,
];
this.polyLineArray.push(
new this.AMap.Polyline({
map: this.map,
path: [startPosition, endPosition],
})
);
const markersPosition = [
this.getLngAndLat(
filterItem.longitude,
filterItem.latitude,
monitor.rotation,
monitor.amplitude
).lng,
this.getLngAndLat(
filterItem.longitude,
filterItem.latitude,
monitor.rotation, //0度是正东
monitor.amplitude
).lat,
];
const markers = new this.AMap.Marker({
icon: hooks,
position: markersPosition,
offset: new this.AMap.Pixel(-25, -25),
});
this.markerArray.push(markers);
markers.setMap(this.map);
});
});
},
},
mounted() {
this.getTowerData();
},
beforeDestroy() {
clearInterval(this.timer);
},
};
</script>
......@@ -543,6 +752,7 @@ export default {
.warn-message {
position: relative;
height: 420px;
overflow-y: auto;
.warn-icon {
position: absolute;
left: 50%;
......@@ -556,4 +766,139 @@ export default {
}
}
}
.warn-title {
border-left: 2px solid;
padding-left: 12px;
font-size: 14px;
color: #c6def9;
display: flex;
justify-content: space-between;
margin-bottom: 18px;
&:nth-child(3n-2) {
border-color: #fd175d;
}
&:nth-child(3n-1) {
border-color: #ab75ff;
}
&:nth-child(3n) {
border-color: #ffbb37;
}
.warn-text {
width: 60%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.warn-time {
width: 40%;
text-align: right;
}
}
.monitor-list {
height: 320px;
overflow-y: auto;
}
.noise-monitor {
font-size: 14px;
color: #c6def9;
line-height: 72px;
background: rgba(44, 96, 162, 0.05);
padding: 0 12px;
margin-bottom: 12px;
cursor: pointer;
&:last-child {
margin-bottom: 0;
}
&:hover {
color: #27acfb;
background: rgba(44, 96, 162, 0.2);
}
img {
width: 30px;
height: 30px;
margin-top: 20px;
margin-right: 12px;
vertical-align: top;
}
.device-description {
line-height: 36px;
width: 70%;
}
.online {
color: #3eec6f;
}
span {
float: right;
}
}
#amap-container {
width: 100%;
height: 100%;
}
.swagger-container {
width: 100%;
height: 100%;
}
::v-deep .amap-icon {
img {
width: 50px;
height: 50px;
}
}
.towerwindow {
width: 460px;
height: 90px;
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-120%);
background: url("@/assets/safecap/cap-window-bg.png") no-repeat;
background-size: 100% 100%;
padding: 20px;
}
.recent-open {
font-size: 16px;
color: #c6def9;
line-height: 60px;
}
.tower-description {
line-height: 32px;
font-size: 18px;
color: #c6def9;
padding-bottom: 16px;
border-bottom: 1px solid #7a8fad;
img {
width: 32px;
vertical-align: top;
}
.name {
float: right;
}
.online-status.online {
color: rgba(62, 236, 111, 1);
}
}
::v-deep .el-dialog__header {
text-align: center;
padding: 20px;
background: #2268bf;
.el-dialog__title {
color: #fff !important;
}
.el-dialog__headerbtn {
font-size: 24px;
right: 20px;
top: 20px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #fff !important;
}
}
::v-deep .el-dialog__body {
background: #164b8e;
}
</style>
\ No newline at end of file
<template>
<el-dialog
:visible.sync="dialogVisible"
title="设备详情"
append-to-body
@opened="openedEvents"
>
<div>
<div class="title-label">
<img src="@/assets/tower/arrow.png" alt="" />
{{ deviceData.device_sn }} /
<span :class="[deviceData.is_online == 1 ? 'online' : '']">{{
deviceData.is_online_text
}}</span>
</div>
<div class="base-info">
<div class="status-area">
<div class="status-window">
<div class="status-value">{{ deviceData.height }}</div>
<div class="status-text">高度/m</div>
</div>
<div class="status-window">
<div class="status-value">{{ deviceData.rotation }}</div>
<div class="status-text">回转/°</div>
</div>
<div class="status-window">
<div class="status-value">{{ deviceData.amplitude }}</div>
<div class="status-text">幅度/m</div>
</div>
<div class="status-window">
<div class="status-value">{{ deviceData.load }}</div>
<div class="status-text">载重/t</div>
</div>
<div class="status-window">
<div class="status-value">{{ deviceData.moment_rate }}</div>
<div class="status-text">力矩百分比/%</div>
</div>
<div class="status-window">
<div class="status-value">{{ deviceData.wind_speed }}</div>
<div class="status-text">风速/m/s</div>
</div>
<div class="status-window">
<div class="status-value">{{ deviceData.wind_speed_rate }}</div>
<div class="status-text">风速百分比/%</div>
</div>
<div class="status-window">
<div
class="status-value"
style="line-height: 20px; font-size: 15px"
>
{{ deviceData.log_time && deviceData.log_time.split(" ")[0] }}
<br />
{{ deviceData.log_time && deviceData.log_time.split(" ")[1] }}
</div>
<div class="status-text">数据更新</div>
</div>
</div>
<div
id="video-container"
v-if="deviceData.camera_live_address_url"
></div>
<div id="video-container-img" v-else>
<img :src="deviceData.image_url" alt="" />
</div>
</div>
<div class="title-label">
<img src="@/assets/tower/arrow.png" alt="" />
今日载重/高度实时数据
</div>
<div id="current-chart" ref="currentChart"></div>
</div>
</el-dialog>
</template>
<script>
import { getDeviceTodayChart } from "@/api/index";
require("vue-video-player/node_modules/video.js/dist/video-js.css");
import videojs from "video.js";
import "videojs-contrib-hls";
export default {
name: "DeviceDialog",
props: {
visible: {
type: Boolean,
default: false,
},
deviceId: {
type: [String, Number],
default: "",
},
deviceData: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
todayData: [],
player: null,
};
},
methods: {
renderTodayChart() {
const xAxisData = this.todayData.map((item) => {
return item.time;
});
const loadData = this.todayData.map((item) => {
return item.load;
});
const heightData = this.todayData.map((item) => {
return item.height;
});
const chart = this.$echarts.init(this.$refs.currentChart);
const option = {
grid: {
top: 30,
bottom: 30,
left: 30,
right: 30,
},
legend: {
orient: "horizontal",
x: "center",
y: "top",
textStyle: {
fontSize: 12,
color: "rgba(225, 239, 255, 0.7)",
},
},
tooltip: {
trigger: "item",
},
xAxis: {
type: "category",
data: xAxisData,
axisTick: { show: false },
axisLabel: {
fontSize: "12",
color: "#c6def9",
},
},
yAxis: {
type: "value",
axisLabel: {
fontSize: "12",
color: "#c6def9",
},
splitNumber: 4,
splitLine: {
lineStyle: {
color: "rgba(95, 120, 144, 0.4)",
},
},
},
series: [
{
name: "吊重",
type: "line",
smooth: true,
data: loadData,
},
{
name: "高度",
type: "line",
smooth: true,
data: heightData,
},
],
};
chart.setOption(option);
this.$nextTick(() => {
// 解决echarts图表放大溢出父容器
const resizeOb = new ResizeObserver((entries) => {
for (const entry of entries) {
this.$echarts.getInstanceByDom(entry.target).resize();
}
});
resizeOb.observe(document.getElementById("current-chart"));
});
},
openedEvents() {
const myVideoDiv = document.getElementById(`video-container`);
myVideoDiv.innerHTML = `<video
id="singleVideo"
autoplay="autoplay"
class="video-js vjs-default-skin"
></video>`;
const singlePlayer = videojs(`singleVideo`, {
autoplay: true, // 自动播放
controls: true, // 控件显示
preload: "auto", //定义视频加载模式
loop: true, //是否循环播放
});
singlePlayer.src({
src: this.deviceData.camera_live_address_url,
type: "application/x-mpegURL",
});
singlePlayer.play();
this.player = singlePlayer;
getDeviceTodayChart(this.deviceId).then((result) => {
this.todayData = result.data;
this.$nextTick(() => {
this.renderTodayChart();
});
});
},
},
computed: {
dialogVisible: {
get() {
return this.visible;
},
set(val) {
this.$emit("changeVisible", val);
},
},
},
watch: {
dialogVisible(val) {
if (!val) {
this.player && this.player.dispose();
}
},
},
};
</script>
<style lang="less" scoped>
.title-label {
border-bottom: 2px solid #00b7ee;
height: 18px;
font-size: 18px;
color: #c6def9;
line-height: 30px;
min-height: 30px;
margin-bottom: 20px;
img {
width: 16px;
}
}
.base-info {
display: flex;
justify-content: space-between;
}
#video-container {
width: calc(40% - 20px);
height: 200px;
}
.video-container-img {
width: calc(40% - 20px);
height: 200px;
img {
width: 100%;
height: 100%;
vertical-align: top;
}
}
.status-area {
display: flex;
width: 60%;
flex-wrap: wrap;
justify-content: space-between;
}
.status-window {
width: 20%;
border: 1px solid #00b7ee;
box-shadow: 0px 21px 24px 0px rgba(42, 78, 169, 0.4);
border-radius: 4px;
padding: 10px;
background: #113e77;
text-align: center;
margin-bottom: 20px;
.status-value {
font-size: 18px;
color: #13e0ff;
line-height: 40px;
margin-bottom: 12px;
border-bottom: 1px solid #00b7ee;
}
.status-text {
font-size: 14px;
color: #c6def9;
line-height: 20px;
}
}
#current-chart {
width: 100%;
height: 300px;
}
.online {
color: #3eec6f;
}
::v-deep .video-js {
width: 100%;
height: 100%;
}
</style>
\ No newline at end of file
......@@ -64,7 +64,7 @@ request.interceptors.response.use(
})
}
if (response.data.status == 401) {
window.location.href = process.env.VUE_APP_RESOURCE_URL + 'pweb/m/login?is_screen=1'
window.location.href = process.env.VUE_APP_API_URL + 'pweb/m/login?is_screen=1'
}
return response.data
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment