添加系统警告+设备统计+行驶统计

master
lynn 7 months ago
parent 52f8ea1470
commit 0a2fac6cdb

@ -0,0 +1,20 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"files.associations": {
"*.vue": "vue",
"*.js": "javascript",
"*.json": "json",
"*.css": "css",
"*.scss": "scss",
"*.less": "less"
},
"javascript.updateImportsOnFileMove.enabled": "always",
"typescript.updateImportsOnFileMove.enabled": "always",
"editor.semanticHighlighting.enabled": true,
"editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs": true
}

@ -0,0 +1,8 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none",
"arrowParens": "avoid",
"endOfLine": "auto"
}

@ -0,0 +1,117 @@
import request from '@/utils/request'
// 模拟数据
const mockOverviewData = {
month: {
total: 42,
onlineRate: 90.9,
communicationCount: 50,
avgCommunicationTime: 2.0
},
year: {
total: 45,
onlineRate: 92.5,
communicationCount: 580,
avgCommunicationTime: 2.2
}
}
const mockTrendData = {
month: {
legends: ['大连', '小连'],
xAxis: ['1日', '2日', '3日', '4日', '5日', '6日', '7日', '8日', '9日', '10日', '11日', '12日', '13日', '14日', '15日', '16日', '17日', '18日', '19日', '20日', '21日', '22日', '23日', '24日', '25日', '26日', '27日', '28日', '29日', '30日', '31日'],
series: [
{
name: '大连',
data: [60, 58, 65, 70, 75, 85, 80, 70, 60, 90, 85, 80, 95, 85, 65, 70, 75, 85, 80, 70, 60, 90, 85, 80, 95, 85, 65, 70, 75, 85, 80]
},
{
name: '小连',
data: [65, 70, 80, 75, 60, 55, 90, 85, 95, 85, 75, 60, 55, 65, 80, 75, 60, 55, 90, 85, 95, 85, 75, 60, 55, 65, 80, 75, 60, 55, 90]
}
]
},
year: {
legends: ['大连', '小连'],
xAxis: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
series: [
{
name: '大连',
data: [85, 88, 90, 92, 88, 85, 90, 92, 95, 90, 88, 85]
},
{
name: '小连',
data: [80, 85, 88, 90, 85, 80, 88, 90, 92, 88, 85, 80]
}
]
}
}
// 获取设备统计概览数据
export function getDeviceOverview(params) {
return {
data: mockOverviewData[params.type]
}
}
// 获取设备在线率趋势数据
export function getDeviceOnlineTrend(params) {
return {
data: mockTrendData[params.type]
}
}
// 获取行驶概览数据
export function getDrivingOverview(params) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: {
totalMileage: 12345.67,
avgMileage: 1234.56,
maxMileage: 2345.67,
minMileage: 123.45
}
})
}, 500)
})
}
// 获取行驶趋势数据
export function getDrivingTrend(params) {
return new Promise((resolve) => {
setTimeout(() => {
const isMonth = params.type === 'month'
const xAxis = isMonth
? Array.from({length: 31}, (_, i) => `${i + 1}`)
: Array.from({length: 12}, (_, i) => `${i + 1}`)
const series = Array.from({length: xAxis.length}, () =>
Math.floor(Math.random() * 2000) + 500
)
resolve({
data: {
xAxis,
series
}
})
}, 500)
})
}
// 获取行驶排名数据
export function getDrivingRanking(params) {
return new Promise((resolve) => {
setTimeout(() => {
const data = Array.from({length: params.limit}, (_, i) => ({
deviceName: `设备${i + 1}`,
mileage: Math.floor(Math.random() * 2000) + 500
})).sort((a, b) => b.mileage - a.mileage)
resolve({
data
})
}, 500)
})
}

@ -0,0 +1,71 @@
import request from '@/utils/request'
// 获取警告列表
export function getWarningList(params) {
// 模拟数据
const mockData = {
data: [
{
id: '1',
device_no: 'PT001',
device_name: '泵车A',
warning_type: '低电量',
warning_time: '2024-01-20 14:30:50',
location: '上海市浦东新区世纪大道',
status: '未处理'
},
{
id: '2',
device_no: 'PT002',
device_name: '泵车B',
warning_type: '低电量预警',
warning_time: '2024-01-20 14:30:50',
location: '上海市浦东新区世纪大道',
status: '已处理'
},
{
id: '3',
device_no: 'PT003',
device_name: '泵车C',
warning_type: '低电量超低预警',
warning_time: '2024-01-20 14:30:50',
location: '上海市浦东新区世纪大道',
status: '处理中'
}
],
total: 3
}
// 模拟 API 调用
return new Promise((resolve) => {
setTimeout(() => {
resolve(mockData);
}, 500);
});
}
// 搜索警告
export function searchWarnings(params) {
// 模拟数据
const mockData = {
data: [
{
id: '1',
device_no: 'PT001',
device_name: '泵车A',
warning_type: '低电量',
warning_time: '2024-01-20 14:30:50',
location: '上海市浦东新区世纪大道',
status: '未处理'
}
],
total: 1
}
// 模拟 API 调用
return new Promise((resolve) => {
setTimeout(() => {
resolve(mockData);
}, 500);
});
}

@ -4,7 +4,7 @@ import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import '@/styles/element-variables.scss'
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import locale from 'element-ui/lib/locale/lang/zh-CN' // 改为中文语言包
import '@/styles/index.scss' // global css
@ -38,9 +38,7 @@ if (process.env.NODE_ENV === 'production') {
import VueParticles from 'vue-particles'
Vue.use(VueParticles)
// set ElementUI lang to EN
//Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui按如下方式声明
Vue.use(ElementUI)
Vue.use(ElementUI, { locale }) // 使用中文语言包
import Message from 'element-ui/lib/message';

@ -0,0 +1,276 @@
<template>
<div class="container">
<div class="statistics-page">
<div class="filter-header">
<el-form :inline="true" class="filter-form">
<el-form-item label="统计类型">
<el-radio-group v-model="filterForm.type" @change="handleTypeChange">
<el-radio label="month">按月统计</el-radio>
<el-radio label="year">按年统计</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="filterForm.type === 'month' ? '选择月份' : '选择年份'">
<el-date-picker
v-if="filterForm.type === 'month'"
v-model="filterForm.date"
type="month"
placeholder="选择年月"
value-format="yyyy-MM">
</el-date-picker>
<el-date-picker
v-else
v-model="filterForm.date"
type="year"
placeholder="选择年份"
value-format="yyyy">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch"></el-button>
</el-form-item>
</el-form>
</div>
<div class="statistics-cards">
<el-row :gutter="20">
<el-col :span="6">
<el-card class="stat-card purple">
<div class="card-title">设备总数</div>
<div class="card-value">{{ overviewData.total }}</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card blue">
<div class="card-title">平均在线率</div>
<div class="card-value">{{ overviewData.onlineRate }}<span class="unit">%</span></div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card orange">
<div class="card-title">通联次数</div>
<div class="card-value">{{ overviewData.communicationCount }}</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card light-blue">
<div class="card-title">平均通联时间</div>
<div class="card-value">{{ overviewData.avgCommunicationTime }}<span class="unit">h</span></div>
</el-card>
</el-col>
</el-row>
</div>
<div class="trend-chart">
<el-card>
<div slot="header" class="chart-header">
<span>设备在线率趋势</span>
</div>
<div class="chart-container" ref="trendChart"></div>
</el-card>
</div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import { getDeviceOverview, getDeviceOnlineTrend } from '@/api/car/statistics'
export default {
data() {
const now = new Date()
const defaultDate = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0')
return {
filterForm: {
type: 'month',
date: defaultDate
},
chart: null,
overviewData: {
total: 0,
onlineRate: 0,
communicationCount: 0,
avgCommunicationTime: 0
}
}
},
mounted() {
this.initChart()
this.loadData()
},
methods: {
getDefaultDate() {
const now = new Date()
if (this.filterForm?.type === 'month') {
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
} else {
return `${now.getFullYear()}`
}
},
loadData() {
try {
//
const overviewRes = getDeviceOverview({
type: this.filterForm.type,
date: this.filterForm.date
})
this.overviewData = overviewRes.data
//
const trendRes = getDeviceOnlineTrend({
type: this.filterForm.type,
date: this.filterForm.date
})
this.updateChart(trendRes.data)
} catch (error) {
console.error('加载数据失败:', error)
this.$message.error('加载数据失败')
}
},
handleSearch() {
this.loadData()
},
initChart() {
this.chart = echarts.init(this.$refs.trendChart)
},
updateChart(data) {
if (!this.chart) {
this.chart = echarts.init(this.$refs.trendChart)
}
const option = {
tooltip: {
trigger: 'axis'
},
legend: {
data: data.legends || []
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: data.xAxis || [],
axisLabel: {
interval: 0,
rotate: 30
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: '{value}%'
}
},
series: data.series.map(item => ({
name: item.name,
type: 'line',
smooth: true,
data: item.data,
areaStyle: {
opacity: 0.3,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: item.name === '大连' ? 'rgba(58,77,233,0.8)' : 'rgba(73,227,172,0.8)'
}, {
offset: 1,
color: item.name === '大连' ? 'rgba(58,77,233,0.1)' : 'rgba(73,227,172,0.1)'
}])
}
}))
}
this.chart.setOption(option)
},
handleTypeChange() {
this.filterForm.date = this.getDefaultDate()
this.loadData()
}
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose()
this.chart = null
}
}
}
</script>
<style scoped>
.statistics-page {
padding: 20px;
}
.filter-header {
margin-bottom: 20px;
background: #fff;
padding: 20px;
border-radius: 4px;
}
.statistics-cards {
margin-bottom: 20px;
}
.stat-card {
height: 120px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
border: none;
}
.stat-card.purple {
background: linear-gradient(135deg, #a355f7 0%, #9061f9 100%);
}
.stat-card.blue {
background: linear-gradient(135deg, #3a4de9 0%, #3f8cfe 100%);
}
.stat-card.orange {
background: linear-gradient(135deg, #ff9f43 0%, #ff7f50 100%);
}
.stat-card.light-blue {
background: linear-gradient(135deg, #17c2d7 0%, #3bbaf5 100%);
}
.card-title {
font-size: 16px;
margin-bottom: 10px;
}
.card-value {
font-size: 32px;
font-weight: bold;
}
.unit {
font-size: 16px;
margin-left: 4px;
}
.trend-chart {
background: #fff;
border-radius: 4px;
}
.chart-header {
padding: 10px 0;
font-size: 16px;
font-weight: bold;
}
.chart-container {
height: 400px;
}
</style>

@ -0,0 +1,308 @@
<template>
<div class="container">
<div class="statistics-page">
<div class="filter-header">
<el-form :inline="true" class="filter-form">
<el-form-item label="统计类型">
<el-radio-group v-model="filterForm.type" @change="handleTypeChange">
<el-radio label="month">按月统计</el-radio>
<el-radio label="year">按年统计</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="filterForm.type === 'month' ? '选择月份' : '选择年份'">
<el-date-picker
v-if="filterForm.type === 'month'"
v-model="filterForm.date"
type="month"
placeholder="选择月份"
value-format="yyyy-MM">
</el-date-picker>
<el-date-picker
v-else
v-model="filterForm.date"
type="year"
placeholder="选择年份"
value-format="yyyy">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch"></el-button>
</el-form-item>
</el-form>
</div>
<div class="statistics-cards">
<el-row :gutter="20">
<el-col :span="6">
<el-card class="stat-card purple">
<div class="card-title">总里程</div>
<div class="card-value">{{ overviewData.totalMileage }}<span class="unit">km</span></div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card blue">
<div class="card-title">平均里程</div>
<div class="card-value">{{ overviewData.avgMileage }}<span class="unit">km</span></div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card orange">
<div class="card-title">最高里程</div>
<div class="card-value">{{ overviewData.maxMileage }}<span class="unit">km</span></div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card light-blue">
<div class="card-title">最低里程</div>
<div class="card-value">{{ overviewData.minMileage }}<span class="unit">km</span></div>
</el-card>
</el-col>
</el-row>
</div>
<div class="content-wrapper">
<el-row :gutter="20">
<el-col :span="16">
<el-card class="trend-chart">
<div slot="header" class="chart-header">
<span>{{ filterForm.type === 'month' ? '日里程趋势' : '月里程趋势' }}</span>
</div>
<div class="chart-container" ref="trendChart"></div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="ranking-list">
<div slot="header" class="chart-header">
<span>车辆里程排名</span>
</div>
<el-table :data="rankingData" style="width: 100%" height="400">
<el-table-column type="index" label="排名" width="60"></el-table-column>
<el-table-column prop="deviceName" label="设备名称"></el-table-column>
<el-table-column prop="mileage" label="里程(km)" width="100">
<template slot-scope="scope">
{{ scope.row.mileage.toFixed(2) }}
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import { getDrivingOverview, getDrivingTrend, getDrivingRanking } from '@/api/car/statistics'
export default {
data() {
const now = new Date()
const defaultDate = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0')
return {
filterForm: {
type: 'month',
date: defaultDate
},
chart: null,
overviewData: {
totalMileage: 0,
avgMileage: 0,
maxMileage: 0,
minMileage: 0
},
rankingData: [],
chartData: {
xAxis: [],
series: []
}
}
},
mounted() {
this.loadData()
},
methods: {
getDefaultDate() {
const now = new Date()
if (this.filterForm?.type === 'month') {
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
} else {
return `${now.getFullYear()}`
}
},
async loadData() {
try {
//
const overviewRes = await getDrivingOverview({
type: this.filterForm.type,
date: this.filterForm.date
})
this.overviewData = overviewRes.data
//
const trendRes = await getDrivingTrend({
type: this.filterForm.type,
date: this.filterForm.date
})
this.chartData = trendRes.data
this.updateChart()
//
const rankingRes = await getDrivingRanking({
type: this.filterForm.type,
date: this.filterForm.date,
limit: 10
})
this.rankingData = rankingRes.data
} catch (error) {
console.error('加载数据失败:', error)
this.$message.error('加载数据失败')
}
},
handleSearch() {
this.loadData()
},
updateChart() {
if (!this.chart) {
this.chart = echarts.init(this.$refs.trendChart)
}
const option = {
tooltip: {
trigger: 'axis',
formatter: '{b}<br/>{a}: {c} km'
},
legend: {
data: ['里程']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.chartData.xAxis,
axisLabel: {
interval: 0,
rotate: 30
}
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} km'
}
},
series: [{
name: '里程',
type: 'line',
smooth: true,
data: this.chartData.series,
areaStyle: {
opacity: 0.3,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(58,77,233,0.8)'
}, {
offset: 1,
color: 'rgba(58,77,233,0.1)'
}])
}
}]
}
this.chart.setOption(option)
},
handleTypeChange() {
this.filterForm.date = this.getDefaultDate()
this.loadData()
}
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose()
this.chart = null
}
}
}
</script>
<style scoped>
.statistics-page {
padding: 20px;
}
.filter-header {
margin-bottom: 20px;
background: #fff;
padding: 20px;
border-radius: 4px;
}
.statistics-cards {
margin-bottom: 20px;
}
.stat-card {
height: 120px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
border: none;
}
.stat-card.purple {
background: linear-gradient(135deg, #a355f7 0%, #9061f9 100%);
}
.stat-card.blue {
background: linear-gradient(135deg, #3a4de9 0%, #3f8cfe 100%);
}
.stat-card.orange {
background: linear-gradient(135deg, #ff9f43 0%, #ff7f50 100%);
}
.stat-card.light-blue {
background: linear-gradient(135deg, #17c2d7 0%, #3bbaf5 100%);
}
.card-title {
font-size: 16px;
margin-bottom: 10px;
}
.card-value {
font-size: 32px;
font-weight: bold;
}
.unit {
font-size: 16px;
margin-left: 4px;
}
.content-wrapper {
margin-top: 20px;
}
.trend-chart, .ranking-list {
height: 100%;
}
.chart-header {
padding: 10px 0;
font-size: 16px;
font-weight: bold;
}
.chart-container {
height: 400px;
}
</style>

@ -49,9 +49,9 @@
</div>
<div>
GPS{{boatEquipment}}
</div>
<div>
车牌/船号{{boatPlate}}
</div>
<div>
车牌/船号{{boatPlate}}
</div>
</div>
<div class="searchmap">
@ -84,9 +84,9 @@
<div class="maptime">
<div v-if="showMapTime">
<i class="el-icon-close" @click="showMapTime=false"></i>
<div>名称{{boatName}}</div>
<div>
车牌/船号{{boatPlate}}
<div>名称{{boatName}}</div>
<div>
车牌/船号{{boatPlate}}
</div>
<div>GPS{{boatEquipment}}</div>
<div>开始{{start_time}}</div>
@ -194,7 +194,7 @@
boatName: '',
boatBranch: '',
modelName: "",
boatEquipment: "",
boatEquipment: "",
boatPlate:'',
start_time: "",
end_time: "",
@ -325,50 +325,50 @@
prop: 'latitude',
label: '纬度',
align: 'center'
}],
columnsZJ: [{
prop: 'area',
label: '状态',
align: 'center',
width: "120",
formatter: (row, column, cellValue) => {
return `<i class="iconfont icon-daohang" style="color:#00AAFF;display:inline-block !important;transform:rotate(${row.direction}deg)"></i>`
}
}, {
prop: 'created_at',
label: '定位时间',
align: 'center',
width: "180"
},{
prop: 'orp',
label: 'ORP',
align: 'center'
},{
prop: 'oxygen',
label: '溶解氧',
align: 'center'
}, {
prop: 'ph',
label: 'PH',
align: 'center'
}, {
prop: 'shipbow',
label: '船艏测距仪',
align: 'center'
}, {
prop: 'temperature',
label: '温度',
align: 'center'
},{
prop: 'longitude',
label: '经度',
align: 'center',
width: "180"
}, {
prop: 'latitude',
label: '纬度',
align: 'center',
width: "180"
}],
columnsZJ: [{
prop: 'area',
label: '状态',
align: 'center',
width: "120",
formatter: (row, column, cellValue) => {
return `<i class="iconfont icon-daohang" style="color:#00AAFF;display:inline-block !important;transform:rotate(${row.direction}deg)"></i>`
}
}, {
prop: 'created_at',
label: '定位时间',
align: 'center',
width: "180"
},{
prop: 'orp',
label: 'ORP',
align: 'center'
},{
prop: 'oxygen',
label: '溶解氧',
align: 'center'
}, {
prop: 'ph',
label: 'PH',
align: 'center'
}, {
prop: 'shipbow',
label: '船艏测距仪',
align: 'center'
}, {
prop: 'temperature',
label: '温度',
align: 'center'
},{
prop: 'longitude',
label: '经度',
align: 'center',
width: "180"
}, {
prop: 'latitude',
label: '纬度',
align: 'center',
width: "180"
}],
//
speedArr: {
@ -387,7 +387,7 @@
mounted() {
this.$store.dispatch('app/toggleSideBar')
//
this.boatEquipment = this.$route.query.boatEquipment ? this.$route.query.boatEquipment : ""
this.boatEquipment = this.$route.query.boatEquipment ? this.$route.query.boatEquipment : ""
this.boatPlate = this.$route.query.boatPlate ? this.$route.query.boatPlate : ""
this.boatName = this.$route.query.boatName ? this.$route.query.boatName : ""
this.boatBranch = this.$route.query.boatBranch ? this.$route.query.boatBranch : ""
@ -405,7 +405,7 @@
this.$refs.boatTree.filter(val);
}
},
created() {
created() {
this.getData()
this.getmapHeight()
this.chart2(7);
@ -498,45 +498,45 @@
})
},
//
getList(checkTime, callday) {
// this.pointsArr = [{
// longitude:"120.630041",
// latitude:'31.314108',
// },{
// longitude:"120.640773",
// latitude:'31.291506',
// },{
// longitude:"120.633048",
// latitude:'31.294151',
// },{
// longitude:"120.633073",
// latitude:'31.294158',
// },{
// longitude:"120.640076",
// latitude:'31.326990',
// },{
// longitude:"120.635291",
// latitude:'31.329283',
// },{
// longitude:"120.630042",
// latitude:'31.314108',
// },{
// longitude:"120.640774",
// latitude:'31.291506',
// },{
// longitude:"120.633049",
// latitude:'31.294151',
// },{
// longitude:"120.633079",
// latitude:'31.294158',
// },{
// longitude:"120.640071",
// latitude:'31.326990',
// },{
// longitude:"120.635299",
// latitude:'31.329283',
// }]
getList(checkTime, callday) {
// this.pointsArr = [{
// longitude:"120.630041",
// latitude:'31.314108',
// },{
// longitude:"120.640773",
// latitude:'31.291506',
// },{
// longitude:"120.633048",
// latitude:'31.294151',
// },{
// longitude:"120.633073",
// latitude:'31.294158',
// },{
// longitude:"120.640076",
// latitude:'31.326990',
// },{
// longitude:"120.635291",
// latitude:'31.329283',
// },{
// longitude:"120.630042",
// latitude:'31.314108',
// },{
// longitude:"120.640774",
// latitude:'31.291506',
// },{
// longitude:"120.633049",
// latitude:'31.294151',
// },{
// longitude:"120.633079",
// latitude:'31.294158',
// },{
// longitude:"120.640071",
// latitude:'31.326990',
// },{
// longitude:"120.635299",
// latitude:'31.329283',
// }]
// return
if (!checkTime) {
this.getCurrentTime(callday)
@ -547,8 +547,8 @@
start_time: this.start_time,
end_time: this.end_time,
equipment_number: this.boatEquipment,
status: this.status,
sort_name:'id',
status: this.status,
sort_name:'id',
sort_type:'ASC'
}).then(res => {
this.paginations.total = res.total
@ -584,7 +584,7 @@
if (!val.children) {
this.boatName = val.name
this.boatEquipment = val.gps
this.boatBranch = val.branch
this.boatBranch = val.branch
this.boatPlate = val.plate
this.modelName = val.model ? val.model : ''
this.showMapTime = true
@ -596,7 +596,7 @@
getListTime(val, time) {
console.log("val", val)
this.boatName = val.data.name
this.boatEquipment = val.data.gps
this.boatEquipment = val.data.gps
this.boatPlate = val.data.plate
this.boatBranch = val.data.branch
this.modelName = val.data.model
@ -679,8 +679,8 @@
height: 60%;
overflow: hidden;
}
.treeInput{
margin: 10px 0;
.treeInput{
margin: 10px 0;
}
.treewrap .el-tree {
height: calc(100% - 60px);
@ -759,4 +759,4 @@
/deep/ .el-tabs--border-card>.el-tabs__content {
padding: 0
}
</style>
</style>

@ -1,24 +1,207 @@
<template>
<div class="container">
<div style="padding: 0px 20px">
<el-image
style="width: 100%"
:src="require('/src/assets/chart.png')"
fit="fill"></el-image>
<!-- <div ref="lxHeader">
<lx-header icon="md-apps" text="数据统计" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
</slot>
</lx-header>
</div> -->
<div class="statistics-page">
<div class="filter-header">
<el-form :inline="true" class="filter-form">
<el-form-item label="统计类型">
<el-radio-group v-model="filterForm.statType" @change="handleStatTypeChange">
<el-radio label="month">按月统计</el-radio>
<el-radio label="year">按年统计</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="选择时间">
<el-date-picker
v-if="filterForm.statType === 'month'"
v-model="filterForm.date"
type="month"
placeholder="选择年月"
value-format="yyyy-MM"
@change="handleDateChange">
</el-date-picker>
<el-date-picker
v-else
v-model="filterForm.date"
type="year"
placeholder="选择年份"
value-format="yyyy"
@change="handleDateChange">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch"></el-button>
<el-button @click="resetForm"></el-button>
</el-form-item>
</el-form>
</div>
<div class="chart-container">
<div class="chart-item">
<div class="chart-title">设备使用时长统计</div>
<div class="chart-content">
<div ref="usageChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { getDeviceStatistics } from '@/api/car/statistics'
import * as echarts from 'echarts'
export default {
data() {
return {
filterForm: {
statType: 'month', //
date: this.getDefaultDate()
},
usageChart: null,
chartData: {
xAxis: [],
series: []
}
}
},
methods: {
getDefaultDate() {
const now = new Date()
if (this.filterForm?.statType === 'month') {
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
} else {
return `${now.getFullYear()}`
}
},
handleStatTypeChange() {
//
this.filterForm.date = this.getDefaultDate()
this.loadData()
},
handleDateChange() {
this.loadData()
},
async loadData() {
try {
const response = await getDeviceStatistics({
statType: this.filterForm.statType,
date: this.filterForm.date
})
this.chartData = response.data
this.updateChart()
} catch (error) {
console.error('加载数据失败:', error)
this.$message.error('加载数据失败')
}
},
updateChart() {
if (!this.usageChart) {
this.usageChart = echarts.init(this.$refs.usageChart)
}
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['使用时长']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: this.chartData.xAxis,
axisLabel: {
interval: 0,
rotate: 30
}
},
yAxis: {
type: 'value',
name: '小时'
},
series: [
{
name: '使用时长',
type: 'bar',
data: this.chartData.series,
itemStyle: {
color: '#409EFF'
}
}
]
}
this.usageChart.setOption(option)
},
handleSearch() {
this.loadData()
},
resetForm() {
this.filterForm = {
statType: 'month',
date: this.getDefaultDate()
}
this.loadData()
}
},
mounted() {
this.loadData()
window.addEventListener('resize', () => {
if (this.usageChart) {
this.usageChart.resize()
}
})
},
beforeDestroy() {
if (this.usageChart) {
this.usageChart.dispose()
}
window.removeEventListener('resize', () => {
if (this.usageChart) {
this.usageChart.resize()
}
})
}
}
</script>
<style>
</style>
<style scoped>
.statistics-page {
padding: 20px;
}
.filter-header {
margin-bottom: 20px;
background: #fff;
padding: 20px;
border-radius: 4px;
}
.chart-container {
background: #fff;
padding: 20px;
border-radius: 4px;
}
.chart-item {
margin-bottom: 20px;
}
.chart-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 20px;
}
.chart-content {
height: 400px;
}
</style>

@ -1,24 +1,167 @@
<template>
<div class="container">
<div style="padding: 0px 20px">
<el-image
style="width: 100%"
:src="require('/src/assets/warning.png')"
fit="fill"></el-image>
<!-- <div ref="lxHeader">
<lx-header icon="md-apps" text="系统预警" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<div class="warning-page">
<div class="filter-header">
<el-form :inline="true" class="filter-form">
<el-form-item label="设备">
<el-input v-model="filterForm.keyword" placeholder="请输入设备号或设备名称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch"></el-button>
<el-button @click="resetForm"></el-button>
</el-form-item>
</el-form>
</div>
</slot>
</lx-header>
</div> -->
<el-table :data="tableData" style="width: 100%" border>
<el-table-column prop="device_no" label="泵车编号" width="120"></el-table-column>
<el-table-column prop="device_name" label="泵车名称" width="120"></el-table-column>
<el-table-column label="预警类型" width="150">
<template slot-scope="scope">
<el-tag :type="getWarningTypeStyle(scope.row.warning_type)">
{{ scope.row.warning_type }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="warning_time" label="预警时间" width="180"></el-table-column>
<el-table-column prop="location" label="位置信息"></el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<el-tag :type="getStatusStyle(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 30, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
import { getWarningList, searchWarnings } from '@/api/car/warning'
export default {
data() {
return {
filterForm: {
keyword: ''
},
tableData: [],
loading: false,
currentPage: 1,
pageSize: 10,
total: 0
}
},
methods: {
async loadData() {
this.loading = true;
try {
const response = await getWarningList({
page: this.currentPage,
pageSize: this.pageSize
});
this.tableData = response.data;
this.total = response.total;
} catch (error) {
console.error('加载数据失败:', error);
this.$message.error('加载数据失败');
} finally {
this.loading = false;
}
},
async handleSearch() {
this.loading = true;
try {
if (this.filterForm.keyword) {
const response = await searchWarnings({
keyword: this.filterForm.keyword,
page: this.currentPage,
pageSize: this.pageSize
});
this.tableData = response.data;
this.total = response.total;
} else {
await this.loadData();
}
} catch (error) {
console.error('搜索失败:', error);
this.$message.error('搜索失败');
} finally {
this.loading = false;
}
},
resetForm() {
this.filterForm = {
keyword: ''
};
this.loadData();
},
handleSizeChange(val) {
this.pageSize = val;
this.loadData();
},
handleCurrentChange(val) {
this.currentPage = val;
this.loadData();
},
getWarningTypeStyle(type) {
switch (type) {
case '低电量':
return 'warning' //
case '低电量预警':
return 'primary' //
case '低电量超低预警':
return 'danger' //
default:
return ''
}
},
getStatusStyle(status) {
switch (status) {
case '未处理':
return 'danger'
case '处理中':
return 'warning'
case '已处理':
return 'success'
default:
return ''
}
}
},
created() {
this.loadData();
}
}
</script>
<style>
<style scoped>
.warning-page {
padding: 20px;
}
.filter-header {
margin-bottom: 20px;
background: #fff;
padding: 20px;
border-radius: 4px;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
</style>

Loading…
Cancel
Save