This commit is contained in:
xiaozhiyong
2026-06-11 17:09:20 +08:00
parent abe40c5ae9
commit 082b766349
15 changed files with 854 additions and 391 deletions

View File

@@ -31,7 +31,7 @@ export const getDeviceDetailsListByPage = (data) => {
data: data
})
}
// 报警
// 报警列表
export const getAlarmRecordListByPage = (data) => {
return service({
url: '/device/getAlarmRecordListByPage',

View File

@@ -0,0 +1,26 @@
import service from '@/utils/request'
// 项目列表
export const getProjectList = (data) => {
return service({
url: '/device/getProjectList',
method: 'post',
data: data
})
}
// 警情情况
export const getAlarmSituationSummary = (data) => {
return service({
url: '/device/getAlarmSituationSummary',
method: 'post',
data: data
})
}
// 折线图
export const getAlarmTrendProcessingRate = (data) => {
return service({
url: '/device/getAlarmTrendProcessingRate',
method: 'post',
data: data
})
}

View File

@@ -1,5 +1,5 @@
import service from '@/utils/request'
// echarts
//
export const getAlarmCategorySummary = (data) => {
return service({
url: '/device/getAlarmCategorySummary',
@@ -7,6 +7,7 @@ export const getAlarmCategorySummary = (data) => {
data: data
})
}
// 折线图
export const getAlarmTrend = (data) => {
return service({
url: '/device/getAlarmTrend',
@@ -14,3 +15,11 @@ export const getAlarmTrend = (data) => {
data: data
})
}
// 报警列表
export const getAlarmRecordListByPage = (data) => {
return service({
url: '/device/getAlarmRecordListByPage',
method: 'post',
data: data
})
}

View File

@@ -64,13 +64,14 @@
"/src/view/masterStation/equipment/components/list/index.vue": "Index",
"/src/view/masterStation/equipment/index.vue": "Index",
"/src/view/masterStation/index.vue": "MasterStation",
"/src/view/masterStation/project/index.vue": "Index",
"/src/view/masterStation/project/index.vue": "MasterStationProject",
"/src/view/person/person.vue": "Person",
"/src/view/routerHolder.vue": "RouterHolder",
"/src/view/securityControl/alarmList/index.vue": "Index",
"/src/view/securityControl/currentAlarm/index.vue": "Index",
"/src/view/securityControl/index.vue": "SecurityControl",
"/src/view/securityControl/temperatureAlarm/index.vue": "Index",
"/src/view/securityControl/overloadAlarm/index.vue": "Index",
"/src/view/securityControl/voltageAlarm/index.vue": "Index",
"/src/view/superAdmin/api/api.vue": "Api",
"/src/view/superAdmin/authority/authority.vue": "Authority",
"/src/view/superAdmin/authority/components/apis.vue": "Apis",

View File

@@ -2,7 +2,8 @@ import { createPinia } from 'pinia'
import { useAppStore } from '@/pinia/modules/app'
import { useUserStore } from '@/pinia/modules/user'
import { useDictionaryStore } from '@/pinia/modules/dictionary'
import { useProjectStore } from '@/pinia/modules/project'
const store = createPinia()
export { store, useAppStore, useUserStore, useDictionaryStore }
export { store, useAppStore, useUserStore, useDictionaryStore, useProjectStore }

View File

@@ -0,0 +1,26 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
const PROJECT_STORAGE_KEY = 'masterStation_current_project_id'
export const useProjectStore = defineStore('project', () => {
const currentProject = ref(null)
const setCurrentProject = (project) => {
currentProject.value = project || null
if (project?.id) {
localStorage.setItem(PROJECT_STORAGE_KEY, String(project.id))
}
}
const getSavedProjectId = () => {
const savedId = Number(localStorage.getItem(PROJECT_STORAGE_KEY))
return savedId || null
}
return {
currentProject,
setCurrentProject,
getSavedProjectId
}
})

View File

@@ -2,26 +2,13 @@
<div
class="rounded-lg flex items-center justify-evenly w-full h-full relative md:w-screen md:h-screen md:bg-[#194bfb] overflow-hidden"
>
<div
class="rounded-md w-full h-full flex items-center justify-center overflow-hidden"
>
<div
class="oblique h-[130%] w-3/5 bg-white dark:bg-slate-900 transform -rotate-12 absolute -ml-80"
/>
<div
v-if="!page.showForm"
:class="[page.showReadme ? 'slide-out-right' : 'slide-in-fwd-top']"
>
<div class="rounded-md w-full h-full flex items-center justify-center overflow-hidden">
<div class="oblique h-[130%] w-3/5 bg-white dark:bg-slate-900 transform -rotate-12 absolute -ml-80" />
<div v-if="!page.showForm" :class="[page.showReadme ? 'slide-out-right' : 'slide-in-fwd-top']">
<div class="text-lg">
<div
class="font-sans text-4xl font-bold text-center mb-4 dark:text-white"
>
GIN-VUE-ADMIN
</div>
<div class="font-sans text-4xl font-bold text-center mb-4 dark:text-white">GIN-VUE-ADMIN</div>
<p class="text-gray-600 dark:text-gray-300 mb-2">初始化须知</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">
1.您需有用一定的VUE和GOLANG基础
</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">1.您需有用一定的VUE和GOLANG基础</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">
2.请您确认是否已经阅读过<a
class="text-blue-600 font-bold"
@@ -29,54 +16,28 @@
target="_blank"
>官方文档</a
>
<a
class="text-blue-600 font-bold"
href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=2"
target="_blank"
<a class="text-blue-600 font-bold" href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=2" target="_blank"
>初始化视频</a
>
</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">3.请您确认是否了解后续的配置流程</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">
3.请您确认是否了解后续的配置流程
</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">
4.如果您使用mysql数据库请确认数据库引擎为<span
class="text-red-600 font-bold text-3xl ml-2"
>innoDB</span
>
</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">
开发组不为文档中书写过的内容提供无偿服务
4.如果您使用mysql数据库请确认数据库引擎为<span class="text-red-600 font-bold text-3xl ml-2">innoDB</span>
</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">开发组不为文档中书写过的内容提供无偿服务</p>
<p class="flex items-center justify-between mt-8">
<el-button type="primary" size="large" @click="goDoc">
阅读文档
</el-button>
<el-button type="primary" size="large" @click="showNext">
我已确认
</el-button>
<el-button type="primary" size="large" @click="goDoc"> 阅读文档 </el-button>
<el-button type="primary" size="large" @click="showNext"> 我已确认 </el-button>
</p>
</div>
</div>
<div
v-if="page.showForm"
:class="[page.showForm ? 'slide-in-left' : 'slide-out-right']"
class="w-96"
>
<div v-if="page.showForm" :class="[page.showForm ? 'slide-in-left' : 'slide-out-right']" class="w-96">
<el-form ref="formRef" :model="form" label-width="100px" size="large">
<el-form-item label="管理员密码">
<el-input
v-model="form.adminPassword"
placeholder="admin账号的默认密码"
></el-input>
<el-input v-model="form.adminPassword" placeholder="admin账号的默认密码"></el-input>
</el-form-item>
<el-form-item label="数据库类型">
<el-select
v-model="form.dbType"
placeholder="请选择"
class="w-full"
@change="changeDB"
>
<el-select v-model="form.dbType" placeholder="请选择" class="w-full" @change="changeDB">
<el-option key="mysql" label="mysql" value="mysql" />
<el-option key="pgsql" label="pgsql" value="pgsql" />
<el-option key="oracle" label="oracle" value="oracle" />
@@ -91,31 +52,19 @@
<el-input v-model="form.port" placeholder="请输入数据库端口" />
</el-form-item>
<el-form-item v-if="form.dbType !== 'sqlite'" label="userName">
<el-input
v-model="form.userName"
placeholder="请输入数据库用户名"
/>
<el-input v-model="form.userName" placeholder="请输入数据库用户名" />
</el-form-item>
<el-form-item v-if="form.dbType !== 'sqlite'" label="password">
<el-input
v-model="form.password"
placeholder="请输入数据库密码(没有则为空)"
/>
<el-input v-model="form.password" placeholder="请输入数据库密码(没有则为空)" />
</el-form-item>
<el-form-item label="dbName">
<el-input v-model="form.dbName" placeholder="请输入数据库名称" />
</el-form-item>
<el-form-item v-if="form.dbType === 'sqlite'" label="dbPath">
<el-input
v-model="form.dbPath"
placeholder="请输入sqlite数据库文件存放路径"
/>
<el-input v-model="form.dbPath" placeholder="请输入sqlite数据库文件存放路径" />
</el-form-item>
<el-form-item v-if="form.dbType === 'pgsql'" label="template">
<el-input
v-model="form.template"
placeholder="请输入postgresql指定template"
/>
<el-input v-model="form.template" placeholder="请输入postgresql指定template" />
</el-form-item>
<el-form-item>
<div style="text-align: right">
@@ -285,11 +234,13 @@
type: 'success',
center: true
}
).then(() => {
)
.then(() => {
// 点击确认按钮打开AI配置文档
window.open('https://www.gin-vue-admin.com/guide/server/mcp.html', '_blank')
router.push({ name: 'Login' })
}).catch(() => {
})
.catch(() => {
// 点击取消按钮或关闭弹窗,直接跳转到登录页
router.push({ name: 'Login' })
})
@@ -303,18 +254,15 @@
<style lang="scss" scoped>
.slide-in-fwd-top {
-webkit-animation: slide-in-fwd-top 0.4s
cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
-webkit-animation: slide-in-fwd-top 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
animation: slide-in-fwd-top 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}
.slide-out-right {
-webkit-animation: slide-out-right 0.5s
cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
-webkit-animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
}
.slide-in-left {
-webkit-animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94)
both;
-webkit-animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}
@-webkit-keyframes slide-in-fwd-top {

View File

@@ -415,7 +415,7 @@
const testData = devices.value.slice(0, 20)
testData.forEach((device, index) => {
console.log(`渲染第 ${index} 个点:`, device)
// console.log(`渲染第 ${index} 个点:`, device)
const marker = new AMap.Marker({
position: [device.gatewayLong, device.gatewayLat],

View File

@@ -137,39 +137,36 @@
<el-table :data="alarmTableData" border stripe class="alarm-table">
<el-table-column align="center" label="序号" prop="index" width="60" />
<el-table-column align="left" label="事件ID" prop="eventId" width="110" />
<el-table-column align="left" label="设备别名" prop="deviceAlias" min-width="150" show-overflow-tooltip />
<el-table-column align="left" label="设备号" prop="deviceNum" width="150" />
<el-table-column align="center" label="线路" prop="line" width="80" />
<el-table-column align="left" label="报警/预警类型" prop="alarmType" width="120" />
<el-table-column align="center" label="报警/预警值(红色)/ 阈值(蓝色)" width="200">
<template #default="scope">
<span v-if="scope.row.alarmValue" class="value-red">{{ scope.row.alarmValue }}</span>
<span v-if="scope.row.alarmValue && scope.row.threshold"> / </span>
<span v-if="scope.row.threshold" class="value-blue">{{ scope.row.threshold }}</span>
<span v-if="!scope.row.alarmValue && !scope.row.threshold">/</span>
<el-table-column align="left" label="设备别名" prop="mac" />
<el-table-column align="left" label="设备" prop="mac" />
<el-table-column align="left" label="线路" prop="nodeNumber">
<template #default="{ row }">
<span v-if="row.nodeNumber == 0">总路</span>
<span v-else>线路{{ row.nodeNumber }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="耗时" prop="duration" width="80" />
<el-table-column align="center" label="状态" prop="status" width="90">
<template #default="scope">
<el-tag :type="scope.row.status === '已处理' ? 'success' : 'danger'" size="small" effect="light">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="报警/预警时间" prop="alarmTime" width="170" />
<el-table-column align="center" label="动作" width="100" fixed="right">
<template #default="scope">
<el-button v-if="scope.row.status === '未处理'" type="primary" link @click="handleProcess(scope.row)">
处理
</el-button>
<el-button v-else type="primary" link @click="handleRecall(scope.row)">撤回</el-button>
<el-table-column align="left" label="报警类型" prop="alarmType">
<template #default="{ row }">
<span v-if="row.alarmType == '45'">设备事件</span>
<span v-else>操作事件</span>
</template>
</el-table-column>
<el-table-column align="center" label="报警描述" prop="remark" />
<el-table-column align="center" label="报警时间" prop="CreatedAt" />
</el-table>
</div>
<!-- 报警趋势 -->
<div class="alarm-trend">
<div class="list-header">
<div class="list-title">
<span class="dot"></span>
报警趋势
</div>
</div>
<v-chart :option="alarmTrendOption" autoresize class="alarm-trend-canvas" />
</div>
<el-dialog v-model="projectDialogVisible" destroy-on-close title="更换项目" width="480px">
<el-radio-group v-model="selectedProjectId" class="project-radio-group">
<el-radio v-for="item in projectList" :key="item.id" :value="item.id" class="project-radio-item">
@@ -190,15 +187,23 @@
<script setup>
import * as serve from '@/api/masterStation/project'
import * as equipmentServe from '@/api/masterStation/equipment'
import { useProjectStore } from '@/pinia/modules/project'
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { FullScreen, Monitor, Connection, Bell, OfficeBuilding, Location } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { LineChart } from 'echarts/charts'
import { TooltipComponent, GridComponent } from 'echarts/components'
import VChart from 'vue-echarts'
use([CanvasRenderer, LineChart, TooltipComponent, GridComponent])
defineOptions({
name: 'MasterStationProject'
})
const PROJECT_STORAGE_KEY = 'masterStation_current_project_id'
const projectStore = useProjectStore()
const MAP_ZOOM = 13
const MAP_ZOOM_OUT = 9
const MAP_STEP_DURATION = 350
@@ -276,12 +281,13 @@
if (!project) return
currentProject.value = project
selectedProjectId.value = project.id
projectStore.setCurrentProject(project)
updateProjectMarker(project)
moveMapToProject(project)
fetchAlarmSituationSummary()
refreshAlarmData()
}
const fetchAlarmSituationSummary = () => {
const getAlarmSituationSummary = () => {
if (!currentProject.value.id) return
serve.getAlarmSituationSummary({ projectId: currentProject.value.id }).then((res) => {
if (res.code !== 0 || !res.data) return
@@ -300,9 +306,88 @@
})
}
const getAlarmRecordListByPage = () => {
if (!currentProject.value.id) return
equipmentServe.getAlarmRecordListByPage({ page: 1, pageSize: 10, projectId: currentProject.value.id }).then((res) => {
if (res.code !== 0 || !res.data) return
alarmTableData.value = res.data.list || []
})
}
const buildAlarmTrendOption = (dates = [], alarmCounts = []) => ({
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#e4e7ed',
textStyle: { color: '#303133' }
},
grid: {
left: 48,
right: 24,
top: 24,
bottom: 32
},
xAxis: {
type: 'category',
data: dates,
boundaryGap: false,
axisLine: { lineStyle: { color: '#e4e7ed' } },
axisLabel: { color: '#909399', fontSize: 11 }
},
yAxis: {
type: 'value',
minInterval: 1,
axisLine: { show: false },
axisTick: { show: false },
splitLine: { lineStyle: { color: '#f0f2f5' } },
axisLabel: { color: '#909399', fontSize: 11 }
},
series: [
{
name: '报警次数',
type: 'line',
data: alarmCounts,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: '#f56c6c', width: 2 },
itemStyle: { color: '#f56c6c' },
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(245, 108, 108, 0.25)' },
{ offset: 1, color: 'rgba(245, 108, 108, 0)' }
]
}
}
}
]
})
const alarmTrendOption = ref(buildAlarmTrendOption())
const getAlarmTrendProcessingRate = () => {
if (!currentProject.value.id) return
serve.getAlarmTrendProcessingRate({ projectId: currentProject.value.id }).then((res) => {
if (res.code !== 0 || !res.data) return
alarmTrendOption.value = buildAlarmTrendOption(res.data.dates || [], res.data.alarmCounts || [])
})
}
const refreshAlarmData = () => {
if (!currentProject.value.id) return
getAlarmSituationSummary()
getAlarmRecordListByPage()
getAlarmTrendProcessingRate()
}
onMounted(async () => {
await getProjectList()
getAlarmRecordListByPage()
nextTick(() => {
initMap()
if (mapWrapperRef.value) {
@@ -313,17 +398,6 @@
window.addEventListener('resize', handleResize)
})
// 获取警情情况
const getAlarmRecordListByPage = () => {
console.log('currentProject.value', currentProject.value)
if (!currentProject.value.id) return
equipmentServe
.getAlarmRecordListByPage({ page: 1, pageSize: 10, projectId: currentProject.value.id })
.then((res) => {
if (res.code !== 0 || !res.data) return
alarmTableData.value = res.data.list
})
}
// 获取项目列表
const getProjectList = () => {
return serve.getProjectList().then((res) => {
@@ -338,8 +412,7 @@
})
.map(normalizeProject)
const savedId = Number(localStorage.getItem(PROJECT_STORAGE_KEY))
// console.log('savedId', savedId)
const savedId = projectStore.getSavedProjectId()
const project = projectList.value.find((item) => item.id === savedId) || projectList.value[0]
// console.log('project', project)
applyCurrentProject(project)
@@ -363,10 +436,10 @@
const prevProject = { ...currentProject.value }
currentProject.value = project
selectedProjectId.value = project.id
localStorage.setItem(PROJECT_STORAGE_KEY, String(project.id))
projectStore.setCurrentProject(project)
projectDialogVisible.value = false
ElMessage.success(`已切换至:${project.name}`)
fetchAlarmSituationSummary()
refreshAlarmData()
nextTick(() => {
animateMapSwitch(prevProject, project)
})
@@ -379,73 +452,7 @@
let mapResizeObserver = null
let resizeTimer = null
const alarmTableData = ref([
{
index: 1,
eventId: '634949976',
deviceAlias: 'DEV-98CC4D11AA3C',
deviceNum: '98CC4D11AA3C',
line: '-',
alarmType: '上线提醒',
alarmValue: '',
threshold: '',
duration: '-',
status: '已处理',
alarmTime: '2026-06-10 14:52:02'
},
{
index: 2,
eventId: '634924606',
deviceAlias: 'DEV-98CC4D11AA3C',
deviceNum: '98CC4D11AA3C',
line: '线路03',
alarmType: '异常分闸',
alarmValue: '0',
threshold: '100',
duration: '2h',
status: '已处理',
alarmTime: '2026-06-10 14:17:33'
},
{
index: 3,
eventId: '634924607',
deviceAlias: 'DEV-98CC4D11AA3C',
deviceNum: '98CC4D11AA3C',
line: '-',
alarmType: '上线提醒',
alarmValue: '',
threshold: '',
duration: '-',
status: '已处理',
alarmTime: '2026-06-10 14:17:19'
},
{
index: 4,
eventId: '634906602',
deviceAlias: 'DEV-98CC4D11AA3C',
deviceNum: '98CC4D11AA3C',
line: '-',
alarmType: '上线提醒',
alarmValue: '',
threshold: '',
duration: '-',
status: '未处理',
alarmTime: '2026-06-10 13:54:02'
},
{
index: 5,
eventId: '634898301',
deviceAlias: 'DEV-98CC4D2052AE',
deviceNum: '98CC4D2052AE',
line: '线路01',
alarmType: '异常分闸',
alarmValue: '120',
threshold: '100',
duration: '35m',
status: '未处理',
alarmTime: '2026-06-10 13:20:15'
}
])
const alarmTableData = ref([])
const createProjectMarkerContent = (name) => {
return `
@@ -572,6 +579,7 @@
.overview-card,
.alarm-list,
.alarm-trend,
.alarm-card {
background: #ffffff;
border: 1px solid #e4e7ed;
@@ -979,7 +987,8 @@
}
/* 警情列表 */
.alarm-list {
.alarm-list,
.alarm-trend {
padding: 12px;
position: relative;
}
@@ -1017,6 +1026,11 @@
font-weight: 500;
}
}
.alarm-trend-canvas {
width: 100%;
height: 280px;
}
</style>
<style lang="scss">

View File

@@ -1,17 +1,32 @@
<template>
<div>
<!-- <div class="p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2">
<el-radio-group v-model="radio" size="large" fill="#409eff">
<el-radio-button label="报警事件" value="New York" />
<el-radio-button label="预警事件" value="Washington" />
<el-radio-button label="二级报警事件" value="Los Angeles" />
</el-radio-group>
</div> -->
<div class="gva-search-box">
<el-form ref="searchForm" :inline="true" :model="searchInfo">
<el-form-item label="设备号">
<el-input v-model="searchInfo.deviceId" placeholder="设备号" />
</el-form-item>
<el-form-item label="日期">
<el-select v-model="dateType" class="date-type-select" @change="handleDateTypeChange">
<el-option label="月" value="month" />
<el-option label="日" value="day" />
</el-select>
<el-date-picker
v-if="dateType === 'month'"
v-model="dateValue"
type="month"
value-format="YYYY-MM"
placeholder="选择月份"
class="date-picker"
/>
<el-date-picker
v-else
v-model="dateValue"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
class="date-picker"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="onSubmit"> 查询 </el-button>
<el-button icon="refresh" @click="onReset"> 重置 </el-button>
@@ -32,8 +47,28 @@
<v-chart :option="alarmCountOption" autoresize class="alarm-count-chart" />
</div>
</div>
<el-table :data="tableData">
<el-table-column align="left" label="网关ID" prop="gatewayId" width="200" />
</div>
<!-- 报警列表 -->
<div class="alarm-table-box">
<el-table :data="tableData" border stripe>
<el-table-column align="center" label="序号" prop="index" width="60" />
<el-table-column align="left" label="设备别名" prop="mac" />
<el-table-column align="left" label="设备号" prop="mac" />
<el-table-column align="left" label="线路" prop="nodeNumber">
<template #default="{ row }">
<span v-if="row.nodeNumber == 0">总路</span>
<span v-else>线路{{ row.nodeNumber }}</span>
</template>
</el-table-column>
<el-table-column align="left" label="报警类型" prop="alarmType">
<template #default="{ row }">
<span v-if="row.alarmType == '45'">设备事件</span>
<span v-else>操作事件</span>
</template>
</el-table-column>
<el-table-column align="center" label="报警描述" prop="remark" />
<el-table-column align="center" label="报警时间" prop="CreatedAt" />
</el-table>
<div class="gva-pagination">
<el-pagination
@@ -61,20 +96,35 @@
import { ref, watch, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// import { id } from 'element-plus/es/locale'
import { useAppStore } from '@/pinia'
import { useProjectStore } from '@/pinia'
// 按需注册 ECharts 模块
use([CanvasRenderer, PieChart, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
const appStore = useAppStore()
const projectStore = useProjectStore()
const searchInfo = ref({
username: '',
nickname: '',
phone: '',
email: ''
deviceId: ''
})
const radio = ref('New York')
const getCurrentMonth = () => {
const now = new Date()
const y = now.getFullYear()
const m = String(now.getMonth() + 1).padStart(2, '0')
return `${y}-${m}`
}
const dateType = ref('month')
const dateValue = ref(getCurrentMonth())
const handleDateTypeChange = (type) => {
dateValue.value = type === 'month' ? getCurrentMonth() : formatDateKey(new Date())
}
const buildDateParams = () => {
if (!dateValue.value) return {}
return dateType.value === 'month' ? { month: dateValue.value } : { day: dateValue.value }
}
const page = ref(1)
const total = ref(0)
@@ -420,8 +470,25 @@
// loadChartData()
getAlarmCategorySummary()
getAlarmTrend()
getAlarmRecordListByPage()
})
const getAlarmRecordListByPage = async () => {
const res = await serve.getAlarmRecordListByPage({
page: page.value,
pageSize: pageSize.value,
projectId: projectStore.currentProject?.id,
...searchInfo.value,
...buildDateParams()
})
if (res.code === 0) {
tableData.value = res.data.list
total.value = res.data.total
page.value = res.data.page
pageSize.value = res.data.pageSize
}
}
// 分页
const handleSizeChange = (val) => {
pageSize.value = val
@@ -452,7 +519,9 @@
const table = await serve.getAlarmRecordListByPage({
page: page.value,
pageSize: pageSize.value,
...searchInfo.value
projectId: projectStore.currentProject?.id,
...searchInfo.value,
...buildDateParams()
})
if (table.code === 0) {
tableData.value = table.data.list
@@ -471,6 +540,8 @@
searchInfo.value = {
deviceId: ''
}
dateType.value = 'month'
dateValue.value = getCurrentMonth()
getTableData()
}
</script>
@@ -508,4 +579,22 @@
width: 100%;
height: calc(100% - 30px);
}
.date-type-select {
width: 72px;
margin-right: 8px;
}
.date-picker {
width: 160px;
}
.alarm-table-box {
padding: 12px;
background: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 6px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
margin-top: 12px;
}
</style>

View File

@@ -1,17 +1,32 @@
<template>
<div>
<!-- <div class="p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2">
<el-radio-group v-model="radio" size="large" fill="#409eff">
<el-radio-button label="报警事件" value="New York" />
<el-radio-button label="预警事件" value="Washington" />
<el-radio-button label="二级报警事件" value="Los Angeles" />
</el-radio-group>
</div> -->
<div class="gva-search-box">
<el-form ref="searchForm" :inline="true" :model="searchInfo">
<el-form-item label="设备号">
<el-input v-model="searchInfo.deviceId" placeholder="设备号" />
</el-form-item>
<el-form-item label="日期">
<el-select v-model="dateType" class="date-type-select" @change="handleDateTypeChange">
<el-option label="月" value="month" />
<el-option label="日" value="day" />
</el-select>
<el-date-picker
v-if="dateType === 'month'"
v-model="dateValue"
type="month"
value-format="YYYY-MM"
placeholder="选择月份"
class="date-picker"
/>
<el-date-picker
v-else
v-model="dateValue"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
class="date-picker"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="onSubmit"> 查询 </el-button>
<el-button icon="refresh" @click="onReset"> 重置 </el-button>
@@ -28,8 +43,28 @@
<v-chart :option="alarmCountOption" autoresize class="alarm-count-chart" />
</div>
</div>
<el-table :data="tableData">
<el-table-column align="left" label="网关ID" prop="gatewayId" width="200" />
</div>
<!-- 报警列表 -->
<div class="alarm-table-box">
<el-table :data="tableData" border stripe>
<el-table-column align="center" label="序号" prop="index" width="60" />
<el-table-column align="left" label="设备别名" prop="mac" />
<el-table-column align="left" label="设备号" prop="mac" />
<el-table-column align="left" label="线路" prop="nodeNumber">
<template #default="{ row }">
<span v-if="row.nodeNumber == 0">总路</span>
<span v-else>线路{{ row.nodeNumber }}</span>
</template>
</el-table-column>
<el-table-column align="left" label="报警类型" prop="alarmType">
<template #default="{ row }">
<span v-if="row.alarmType == '45'">设备事件</span>
<span v-else>操作事件</span>
</template>
</el-table-column>
<el-table-column align="center" label="报警描述" prop="remark" />
<el-table-column align="center" label="报警时间" prop="CreatedAt" />
</el-table>
<div class="gva-pagination">
<el-pagination
@@ -58,20 +93,35 @@
import { ref, watch, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// import { id } from 'element-plus/es/locale'
import { useAppStore } from '@/pinia'
import { useProjectStore } from '@/pinia'
// 按需注册 ECharts 模块
use([CanvasRenderer, PieChart, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
const appStore = useAppStore()
const projectStore = useProjectStore()
const searchInfo = ref({
username: '',
nickname: '',
phone: '',
email: ''
deviceId: ''
})
const radio = ref('New York')
const getCurrentMonth = () => {
const now = new Date()
const y = now.getFullYear()
const m = String(now.getMonth() + 1).padStart(2, '0')
return `${y}-${m}`
}
const dateType = ref('month')
const dateValue = ref(getCurrentMonth())
const handleDateTypeChange = (type) => {
dateValue.value = type === 'month' ? getCurrentMonth() : formatDateKey(new Date())
}
const buildDateParams = () => {
if (!dateValue.value) return {}
return dateType.value === 'month' ? { month: dateValue.value } : { day: dateValue.value }
}
const page = ref(1)
const total = ref(0)
@@ -149,45 +199,21 @@
}
}
// 把后端时间字段格式化成 YYYY-MM-DD
function formatDate(value) {
if (!value) return ''
const d = new Date(value)
if (isNaN(d.getTime())) return ''
return formatDateKey(d)
}
function formatDateKey(d) {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
// X 轴显示用 MM-DD
function formatDateLabel(d) {
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${m}-${day}`
}
onMounted(() => {
// getTableData()
// loadChartData()
getAlarmTrend()
getAlarmRecordListByPage()
})
// 分页
const handleSizeChange = (val) => {
pageSize.value = val
getAlarmRecordListByPage()
}
const handleCurrentChange = (val) => {
page.value = val
getAlarmRecordListByPage()
}
// 折线图
const getAlarmTrend = async () => {
const res = await serve.getAlarmTrend({ category: '剩余电流报警', alarmType: '剩余电流报警' })
const res = await serve.getAlarmTrend({ category: '漏电报警', alarmType: '漏电报警' })
if (res.code === 0) {
const { dates = [], series = [] } = res.data || {}
alarmCountOption.value = buildAlarmTrendOption({ dates, series })
@@ -198,8 +224,10 @@
const table = await equipmentListServe.getAlarmRecordListByPage({
page: page.value,
pageSize: pageSize.value,
alarmType: '剩余电流报警',
...searchInfo.value
alarmType: '漏电报警',
projectId: projectStore.currentProject?.id,
...searchInfo.value,
...buildDateParams()
})
if (table.code === 0) {
tableData.value = table.data.list
@@ -208,6 +236,15 @@
pageSize.value = table.data.pageSize
}
}
// 分页
const handleSizeChange = (val) => {
pageSize.value = val
getAlarmRecordListByPage()
}
const handleCurrentChange = (val) => {
page.value = val
getAlarmRecordListByPage()
}
const onSubmit = () => {
page.value = 1
@@ -218,6 +255,8 @@
searchInfo.value = {
deviceId: ''
}
dateType.value = 'month'
dateValue.value = getCurrentMonth()
getAlarmRecordListByPage()
}
</script>
@@ -248,4 +287,22 @@
width: 100%;
height: calc(100% - 30px);
}
.date-type-select {
width: 72px;
margin-right: 8px;
}
.date-picker {
width: 160px;
}
.alarm-table-box {
padding: 12px;
background: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 6px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
margin-top: 12px;
}
</style>

View File

@@ -1,17 +1,32 @@
<template>
<div>
<!-- <div class="p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2">
<el-radio-group v-model="radio" size="large" fill="#409eff">
<el-radio-button label="报警事件" value="New York" />
<el-radio-button label="预警事件" value="Washington" />
<el-radio-button label="二级报警事件" value="Los Angeles" />
</el-radio-group>
</div> -->
<div class="gva-search-box">
<el-form ref="searchForm" :inline="true" :model="searchInfo">
<el-form-item label="设备号">
<el-input v-model="searchInfo.deviceId" placeholder="设备号" />
</el-form-item>
<el-form-item label="日期">
<el-select v-model="dateType" class="date-type-select" @change="handleDateTypeChange">
<el-option label="月" value="month" />
<el-option label="日" value="day" />
</el-select>
<el-date-picker
v-if="dateType === 'month'"
v-model="dateValue"
type="month"
value-format="YYYY-MM"
placeholder="选择月份"
class="date-picker"
/>
<el-date-picker
v-else
v-model="dateValue"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
class="date-picker"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="onSubmit"> 查询 </el-button>
<el-button icon="refresh" @click="onReset"> 重置 </el-button>
@@ -28,8 +43,28 @@
<v-chart :option="alarmCountOption" autoresize class="alarm-count-chart" />
</div>
</div>
<el-table :data="tableData">
<el-table-column align="left" label="网关ID" prop="gatewayId" width="200" />
</div>
<!-- 报警列表 -->
<div class="alarm-table-box">
<el-table :data="tableData" border stripe>
<el-table-column align="center" label="序号" prop="index" width="60" />
<el-table-column align="left" label="设备别名" prop="mac" />
<el-table-column align="left" label="设备号" prop="mac" />
<el-table-column align="left" label="线路" prop="nodeNumber">
<template #default="{ row }">
<span v-if="row.nodeNumber == 0">总路</span>
<span v-else>线路{{ row.nodeNumber }}</span>
</template>
</el-table-column>
<el-table-column align="left" label="报警类型" prop="alarmType">
<template #default="{ row }">
<span v-if="row.alarmType == '45'">设备事件</span>
<span v-else>操作事件</span>
</template>
</el-table-column>
<el-table-column align="center" label="报警描述" prop="remark" />
<el-table-column align="center" label="报警时间" prop="CreatedAt" />
</el-table>
<div class="gva-pagination">
<el-pagination
@@ -48,6 +83,7 @@
<script setup>
import * as serve from '@/api/securityControl/alarmList'
import * as equipmentListServe from '@/api/equipment/list.js'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart, LineChart } from 'echarts/charts'
@@ -57,20 +93,35 @@
import { ref, watch, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// import { id } from 'element-plus/es/locale'
import { useAppStore } from '@/pinia'
import { useProjectStore } from '@/pinia'
// ECharts
use([CanvasRenderer, PieChart, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
const appStore = useAppStore()
const projectStore = useProjectStore()
const searchInfo = ref({
username: '',
nickname: '',
phone: '',
email: ''
deviceId: ''
})
const radio = ref('New York')
const getCurrentMonth = () => {
const now = new Date()
const y = now.getFullYear()
const m = String(now.getMonth() + 1).padStart(2, '0')
return `${y}-${m}`
}
const dateType = ref('month')
const dateValue = ref(getCurrentMonth())
const handleDateTypeChange = (type) => {
dateValue.value = type === 'month' ? getCurrentMonth() : formatDateKey(new Date())
}
const buildDateParams = () => {
if (!dateValue.value) return {}
return dateType.value === 'month' ? { month: dateValue.value } : { day: dateValue.value }
}
const page = ref(1)
const total = ref(0)
@@ -81,7 +132,7 @@
const alarmCountOption = ref(buildAlarmTrendOption({ dates: [], series: [] }))
//
const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#1ABC9C', '#A0CFFF', '#B37000']
const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C']
// 线 option dates/series
function buildAlarmTrendOption({ dates = [], series = [] }) {
@@ -148,135 +199,35 @@
}
}
// 线 option 30
function buildAlarmCountOption(list) {
// YYYY-MM-DD
const countMap = {}
list.forEach((item) => {
const date = formatDate(item.CreatedAt || item.createdAt || item.time)
if (!date) return
countMap[date] = (countMap[date] || 0) + 1
})
// 30 X 0
const xAxisData = []
const seriesData = []
const today = new Date()
for (let i = 29; i >= 0; i--) {
const d = new Date(today)
d.setDate(today.getDate() - i)
const key = formatDateKey(d)
xAxisData.push(formatDateLabel(d))
seriesData.push(countMap[key] || 0)
}
return {
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(15, 23, 42, 0.9)',
borderColor: 'transparent',
textStyle: { color: '#fff' }
},
grid: {
left: 36,
right: 16,
top: 16,
bottom: 28
},
xAxis: {
type: 'category',
data: xAxisData,
boundaryGap: false,
axisLine: { lineStyle: { color: '#e4e7ed' } },
axisLabel: { color: '#909399', fontSize: 11 }
},
yAxis: {
type: 'value',
minInterval: 1,
axisLine: { show: false },
axisTick: { show: false },
splitLine: { lineStyle: { color: '#f0f2f5' } },
axisLabel: { color: '#909399', fontSize: 11 }
},
series: [
{
name: '报警数量',
type: 'line',
data: seriesData,
symbol: 'none', // 线
smooth: true,
lineStyle: {
color: '#409EFF',
width: 2
},
// 线
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(64, 158, 255, 0.35)' },
{ offset: 1, color: 'rgba(64, 158, 255, 0.02)' }
]
}
}
}
]
}
}
// YYYY-MM-DD
function formatDate(value) {
if (!value) return ''
const d = new Date(value)
if (isNaN(d.getTime())) return ''
return formatDateKey(d)
}
function formatDateKey(d) {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
// X MM-DD
function formatDateLabel(d) {
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${m}-${day}`
}
onMounted(() => {
// getTableData()
// loadChartData()
getAlarmTrend()
getAlarmRecordListByPage()
})
//
const handleSizeChange = (val) => {
pageSize.value = val
getTableData()
}
const handleCurrentChange = (val) => {
page.value = val
getTableData()
}
// 线
const getAlarmTrend = async () => {
const res = await serve.getAlarmTrend({ alarmType: '温度报警' })
const res = await serve.getAlarmTrend({ category: '过载报警', alarmType: '过载报警' })
if (res.code === 0) {
const { dates = [], series = [] } = res.data || {}
alarmCountOption.value = buildAlarmTrendOption({ dates, series })
}
}
//
const getTableData = async () => {
const table = await serve.getAlarmRecordListByPage({
const getAlarmRecordListByPage = async () => {
const table = await equipmentListServe.getAlarmRecordListByPage({
page: page.value,
pageSize: pageSize.value,
...searchInfo.value
alarmType: '过载报警',
projectId: projectStore.currentProject?.id,
...searchInfo.value,
...buildDateParams()
})
if (table.code === 0) {
tableData.value = table.data.list
@@ -285,17 +236,28 @@
pageSize.value = table.data.pageSize
}
}
//
const handleSizeChange = (val) => {
pageSize.value = val
getAlarmRecordListByPage()
}
const handleCurrentChange = (val) => {
page.value = val
getAlarmRecordListByPage()
}
const onSubmit = () => {
page.value = 1
getTableData()
getAlarmRecordListByPage()
}
const onReset = () => {
searchInfo.value = {
deviceId: ''
}
getTableData()
dateType.value = 'month'
dateValue.value = getCurrentMonth()
getAlarmRecordListByPage()
}
</script>
@@ -325,4 +287,22 @@
width: 100%;
height: calc(100% - 30px);
}
.date-type-select {
width: 72px;
margin-right: 8px;
}
.date-picker {
width: 160px;
}
.alarm-table-box {
padding: 12px;
background: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 6px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
margin-top: 12px;
}
</style>

View File

View File

@@ -0,0 +1,308 @@
<template>
<div>
<div class="gva-search-box">
<el-form ref="searchForm" :inline="true" :model="searchInfo">
<el-form-item label="设备号">
<el-input v-model="searchInfo.deviceId" placeholder="设备号" />
</el-form-item>
<el-form-item label="日期">
<el-select v-model="dateType" class="date-type-select" @change="handleDateTypeChange">
<el-option label="月" value="month" />
<el-option label="日" value="day" />
</el-select>
<el-date-picker
v-if="dateType === 'month'"
v-model="dateValue"
type="month"
value-format="YYYY-MM"
placeholder="选择月份"
class="date-picker"
/>
<el-date-picker
v-else
v-model="dateValue"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
class="date-picker"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="onSubmit"> 查询 </el-button>
<el-button icon="refresh" @click="onReset"> 重置 </el-button>
</el-form-item>
</el-form>
</div>
<div class="gva-table-box">
<div class="gva-btn-list">
<!-- <el-button type="primary" icon="plus" @click="addUser">新增用户</el-button> -->
</div>
<div class="echarts-box">
<div class="item broken-line">
<p class="title">报警数量</p>
<v-chart :option="alarmCountOption" autoresize class="alarm-count-chart" />
</div>
</div>
</div>
<!-- 报警列表 -->
<div class="alarm-table-box">
<el-table :data="tableData" border stripe>
<el-table-column align="center" label="序号" prop="index" width="60" />
<el-table-column align="left" label="设备别名" prop="mac" />
<el-table-column align="left" label="设备号" prop="mac" />
<el-table-column align="left" label="线路" prop="nodeNumber">
<template #default="{ row }">
<span v-if="row.nodeNumber == 0">总路</span>
<span v-else>线路{{ row.nodeNumber }}</span>
</template>
</el-table-column>
<el-table-column align="left" label="报警类型" prop="alarmType">
<template #default="{ row }">
<span v-if="row.alarmType == '45'">设备事件</span>
<span v-else>操作事件</span>
</template>
</el-table-column>
<el-table-column align="center" label="报警描述" prop="remark" />
<el-table-column align="center" label="报警时间" prop="CreatedAt" />
</el-table>
<div class="gva-pagination">
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
/>
</div>
</div>
</div>
</template>
<script setup>
import * as serve from '@/api/securityControl/alarmList'
import * as equipmentListServe from '@/api/equipment/list.js'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart, LineChart } from 'echarts/charts'
import { TitleComponent, TooltipComponent, LegendComponent, GridComponent } from 'echarts/components'
import VChart from 'vue-echarts'
import { ref, watch, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// import { id } from 'element-plus/es/locale'
import { useProjectStore } from '@/pinia'
// 按需注册 ECharts 模块
use([CanvasRenderer, PieChart, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
const projectStore = useProjectStore()
const searchInfo = ref({
deviceId: ''
})
const getCurrentMonth = () => {
const now = new Date()
const y = now.getFullYear()
const m = String(now.getMonth() + 1).padStart(2, '0')
return `${y}-${m}`
}
const dateType = ref('month')
const dateValue = ref(getCurrentMonth())
const handleDateTypeChange = (type) => {
dateValue.value = type === 'month' ? getCurrentMonth() : formatDateKey(new Date())
}
const buildDateParams = () => {
if (!dateValue.value) return {}
return dateType.value === 'month' ? { month: dateValue.value } : { day: dateValue.value }
}
const page = ref(1)
const total = ref(0)
const pageSize = ref(10)
const tableData = ref([])
// 报警趋势折线图配置
const alarmCountOption = ref(buildAlarmTrendOption({ dates: [], series: [] }))
// 颜色数组
const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C']
// 构建报警趋势折线图 option基于 dates/series
function buildAlarmTrendOption({ dates = [], series = [] }) {
const seriesData = series.map((item, index) => ({
name: item.category,
type: 'line',
data: item.data || [],
smooth: true,
symbol: 'none',
lineStyle: {
color: colorList[index % colorList.length],
width: 2
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: colorList[index % colorList.length] + '40' },
{ offset: 1, color: colorList[index % colorList.length] + '00' }
]
}
}
}))
return {
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(15, 23, 42, 0.9)',
borderColor: 'transparent',
textStyle: { color: '#fff' }
},
legend: {
orient: 'horizontal',
top: 0,
left: 'center',
textStyle: { color: '#606266', fontSize: 12 }
},
grid: {
left: 36,
right: 16,
top: 40,
bottom: 28
},
xAxis: {
type: 'category',
data: dates,
boundaryGap: false,
axisLine: { lineStyle: { color: '#e4e7ed' } },
axisLabel: { color: '#909399', fontSize: 11 }
},
yAxis: {
type: 'value',
minInterval: 1,
axisLine: { show: false },
axisTick: { show: false },
splitLine: { lineStyle: { color: '#f0f2f5' } },
axisLabel: { color: '#909399', fontSize: 11 }
},
series: seriesData
}
}
function formatDateKey(d) {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
onMounted(() => {
getAlarmTrend()
getAlarmRecordListByPage()
})
// 折线图
const getAlarmTrend = async () => {
const res = await serve.getAlarmTrend({ category: '过欠压报警', alarmType: '过欠压报警' })
if (res.code === 0) {
const { dates = [], series = [] } = res.data || {}
alarmCountOption.value = buildAlarmTrendOption({ dates, series })
}
}
// 查询
const getAlarmRecordListByPage = async () => {
const table = await equipmentListServe.getAlarmRecordListByPage({
page: page.value,
pageSize: pageSize.value,
alarmType: '过欠压报警',
projectId: projectStore.currentProject?.id,
...searchInfo.value,
...buildDateParams()
})
if (table.code === 0) {
tableData.value = table.data.list
total.value = table.data.total
page.value = table.data.page
pageSize.value = table.data.pageSize
}
}
// 分页
const handleSizeChange = (val) => {
pageSize.value = val
getAlarmRecordListByPage()
}
const handleCurrentChange = (val) => {
page.value = val
getAlarmRecordListByPage()
}
const onSubmit = () => {
page.value = 1
getAlarmRecordListByPage()
}
const onReset = () => {
searchInfo.value = {
deviceId: ''
}
dateType.value = 'month'
dateValue.value = getCurrentMonth()
getAlarmRecordListByPage()
}
</script>
<style lang="scss">
.header-img-box {
@apply w-52 h-52 border border-solid border-gray-300 rounded-xl flex justify-center items-center cursor-pointer;
}
.gva-table-box {
padding-top: 0 !important;
}
.echarts-box {
display: flex;
> .item {
height: 251px;
&.broken-line {
flex: 1;
}
.title {
font-size: 14px;
font-weight: bold;
}
}
}
.alarm-count-chart {
width: 100%;
height: calc(100% - 30px);
}
.date-type-select {
width: 72px;
margin-right: 8px;
}
.date-picker {
width: 160px;
}
.alarm-table-box {
padding: 12px;
background: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 6px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
margin-top: 12px;
}
</style>

View File

@@ -65,6 +65,7 @@ export default ({ mode }) => {
}
}
},
server: {
// 如果使用docker-compose开发模式设置为false
open: true,
@@ -105,7 +106,10 @@ export default ({ mode }) => {
svgBuilder(['./src/plugin/', './src/assets/icons/'], base, outDir, 'assets', NODE_ENV),
[Banner(`\n Build based on gin-vue-admin \n Time : ${timestamp}`)],
VueFilePathPlugin('./src/pathInfo.json'),
UnoCSS()
UnoCSS(),
vueDevTools({
launchEditor: 'cursor' // 关键配置:指定 Cursor
})
]
}
return config