更新
This commit is contained in:
@@ -3,9 +3,9 @@ VITE_CLI_PORT = 8080
|
||||
VITE_SERVER_PORT = 8888
|
||||
VITE_BASE_API = /api
|
||||
VITE_FILE_API = /api
|
||||
# VITE_BASE_PATH = http://192.168.1.9:8888
|
||||
VITE_BASE_PATH = http://192.168.1.9:8888
|
||||
# VITE_BASE_PATH = http://192.168.110.98:8888
|
||||
VITE_BASE_PATH = https://www.xingoil.com/api
|
||||
# VITE_BASE_PATH = https://www.xingoil.com/api
|
||||
VITE_POSITION = open
|
||||
VITE_EDITOR = code
|
||||
// VITE_EDITOR = webstorm 如果使用webstorm开发且要使用dom定位到代码行功能 请先自定添加 webstorm到环境变量 再将VITE_EDITOR值修改为webstorm
|
||||
|
||||
@@ -11,15 +11,14 @@
|
||||
"/src/view/dashboard/components/table.vue": "Table",
|
||||
"/src/view/dashboard/components/wiki.vue": "Wiki",
|
||||
"/src/view/dashboard/index.vue": "Dashboard",
|
||||
"/src/view/equipment/alarmRecord/index.vue": "Index",
|
||||
"/src/view/equipment/gateway/index.vue": "Index",
|
||||
"/src/view/equipment/index.vue": "Equipment",
|
||||
"/src/view/equipment/list/components/detail/components/alarm/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/detail/components/info/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/detail/components/trend/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/detail/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/list/index.vue": "Index",
|
||||
"/src/view/equipment/list/index.vue": "Index",
|
||||
"/src/view/equipment/particulars/index.vue": "Index",
|
||||
"/src/view/error/index.vue": "Error",
|
||||
"/src/view/error/reload.vue": "Reload",
|
||||
"/src/view/example/breakpoint/breakpoint.vue": "BreakPoint",
|
||||
@@ -56,6 +55,8 @@
|
||||
"/src/view/login/index.vue": "Login",
|
||||
"/src/view/person/person.vue": "Person",
|
||||
"/src/view/routerHolder.vue": "RouterHolder",
|
||||
"/src/view/securityControl/alarmList/index.vue": "Index",
|
||||
"/src/view/securityControl/index.vue": "SecurityControl",
|
||||
"/src/view/superAdmin/api/api.vue": "Api",
|
||||
"/src/view/superAdmin/authority/authority.vue": "Authority",
|
||||
"/src/view/superAdmin/authority/components/apis.vue": "Apis",
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- <warning-bar title="注:右上角头像下拉可切换角色" /> -->
|
||||
<div class="gva-search-box">
|
||||
<el-form ref="searchForm" :inline="true" :model="searchInfo">
|
||||
<el-form-item label="设备ID">
|
||||
<el-input v-model="searchInfo.deviceId" placeholder="设备ID" />
|
||||
</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>
|
||||
<el-table :data="tableData">
|
||||
<el-table-column align="left" label="网关ID" prop="gatewayId" width="200" />
|
||||
<el-table-column align="left" label="设备号" prop="imei" width="200" />
|
||||
<el-table-column align="left" label="网关mac" prop="gatewayMac" width="200" />
|
||||
<el-table-column align="left" label="网关地址" prop="gatewayAddress" />
|
||||
<el-table-column align="left" label="经纬度" width="250">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.gatewayLong }}</span>
|
||||
<el-divider direction="vertical" />
|
||||
<span>{{ scope.row.gatewayLat }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</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/equipment/alarmRecord'
|
||||
|
||||
import { nextTick, ref, watch, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
// import { id } from 'element-plus/es/locale'
|
||||
import { useAppStore } from '@/pinia'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const searchInfo = ref({
|
||||
username: '',
|
||||
nickname: '',
|
||||
phone: '',
|
||||
email: ''
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const total = ref(0)
|
||||
const pageSize = ref(10)
|
||||
const tableData = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
})
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
getTableData()
|
||||
}
|
||||
const handleCurrentChange = (val) => {
|
||||
page.value = val
|
||||
getTableData()
|
||||
}
|
||||
// 查询
|
||||
const getTableData = async () => {
|
||||
const table = await serve.getAlarmRecordListByPage({
|
||||
page: page.value,
|
||||
pageSize: pageSize.value,
|
||||
...searchInfo.value
|
||||
})
|
||||
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 onSubmit = () => {
|
||||
page.value = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
const onReset = () => {
|
||||
searchInfo.value = {
|
||||
deviceId: ''
|
||||
}
|
||||
getTableData()
|
||||
}
|
||||
</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;
|
||||
}
|
||||
</style>
|
||||
20
src/view/equipment/index.vue
Normal file
20
src/view/equipment/index.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition mode="out-in" name="el-fade-in-linear">
|
||||
<keep-alive :include="routerStore.keepAliveRouters">
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouterStore } from '@/pinia/modules/router'
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
defineOptions({
|
||||
name: 'Equipment'
|
||||
})
|
||||
</script>
|
||||
@@ -1,156 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- <warning-bar title="注:右上角头像下拉可切换角色" /> -->
|
||||
<div class="gva-search-box">
|
||||
<el-form ref="searchForm" :inline="true" :model="searchInfo">
|
||||
<el-form-item label="设备状态">
|
||||
<!-- <el-select v-model="searchInfo.deviceStatus" placeholder="请选择">
|
||||
<el-option label="合闸" :value="1" />
|
||||
<el-option label="分闸" :value="0" />
|
||||
</el-select> -->
|
||||
</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>
|
||||
<el-table :data="tableData" row-key="ID">
|
||||
<el-table-column align="left" label="设备ID" prop="deviceId"> </el-table-column>
|
||||
<el-table-column align="left" label="运行时长" prop="runtime">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.runtime || '' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="信号质量" prop="signalQuality">
|
||||
<template #default="{ row }">
|
||||
{{ row.signalQuality || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="电压(V)" prop="leakageCurrent">
|
||||
<template #default="{ row }">
|
||||
{{ row.leakageCurrent || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="漏电流值(mA)" prop="leakageCurrent">
|
||||
<template #default="{ row }">
|
||||
{{ row.leakageCurrent || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="累计用电量" prop="cumulativeElectricity">
|
||||
<template #default="{ row }">
|
||||
{{ row.cumulativeElectricity || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="电流值(A)" prop="current">
|
||||
<template #default="{ row }">
|
||||
{{ row.current || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="内部温度(℃)" prop="internalTemperature">
|
||||
<template #default="{ row }">
|
||||
{{ row.internalTemperature || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="N相下端温度(℃)" prop="nLowerTemperature">
|
||||
<template #default="{ row }">
|
||||
{{ row.nLowerTemperature || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="功率因数(%)" prop="powerFactor">
|
||||
<template #default="{ row }">
|
||||
{{ row.powerFactor || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<!-- <el-button type="primary" link icon="delete" @click="deleteUserFunc(scope.row)">删除</el-button> -->
|
||||
<!-- <el-button type="primary" link icon="Tickets" @click="openDetails(row)">查看</el-button> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</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/equipment/particulars'
|
||||
|
||||
import { nextTick, ref, watch, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
// import { id } from 'element-plus/es/locale'
|
||||
import { useAppStore } from '@/pinia'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const searchInfo = ref({
|
||||
deviceStatus: ''
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const total = ref(0)
|
||||
const pageSize = ref(10)
|
||||
const tableData = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
})
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
getTableData()
|
||||
}
|
||||
const handleCurrentChange = (val) => {
|
||||
page.value = val
|
||||
getTableData()
|
||||
}
|
||||
// 查询
|
||||
const getTableData = async () => {
|
||||
const table = await serve.getDeviceDetailsListByPage({
|
||||
page: page.value,
|
||||
pageSize: pageSize.value,
|
||||
...searchInfo.value
|
||||
})
|
||||
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 onSubmit = () => {
|
||||
page.value = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
const onReset = () => {
|
||||
searchInfo.value = {
|
||||
deviceStatus: ''
|
||||
}
|
||||
getTableData()
|
||||
}
|
||||
</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;
|
||||
}
|
||||
</style>
|
||||
370
src/view/securityControl/alarmList/index.vue
Normal file
370
src/view/securityControl/alarmList/index.vue
Normal file
@@ -0,0 +1,370 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- <warning-bar title="注:右上角头像下拉可切换角色" /> -->
|
||||
<div class="p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2">
|
||||
<!-- <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="报警事件" name="first"></el-tab-pane>
|
||||
<el-tab-pane label="预警事件" name="second"></el-tab-pane>
|
||||
<el-tab-pane label="二级报警事件" name="third"></el-tab-pane>
|
||||
</el-tabs> -->
|
||||
<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="设备ID">
|
||||
<el-input v-model="searchInfo.deviceId" placeholder="设备ID" />
|
||||
</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 pie">
|
||||
<p class="title">报警类型</p>
|
||||
<v-chart :option="alarmTypeOption" autoresize class="alarm-type-chart" />
|
||||
</div>
|
||||
<div class="item broken-line">
|
||||
<p class="title">报警数量</p>
|
||||
<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" />
|
||||
</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 { 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 * as serve from '@/api/equipment/alarmRecord'
|
||||
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
// import { id } from 'element-plus/es/locale'
|
||||
import { useAppStore } from '@/pinia'
|
||||
|
||||
// 按需注册 ECharts 模块
|
||||
use([CanvasRenderer, PieChart, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const searchInfo = ref({
|
||||
username: '',
|
||||
nickname: '',
|
||||
phone: '',
|
||||
email: ''
|
||||
})
|
||||
const radio = ref('New York')
|
||||
|
||||
const page = ref(1)
|
||||
const total = ref(0)
|
||||
const pageSize = ref(10)
|
||||
const tableData = ref([])
|
||||
|
||||
// 报警类型映射(与 alarm/index.vue 中的 typeMap 保持一致)
|
||||
const alarmTypeMap = {
|
||||
45: { label: '设备事件', color: '#409EFF' },
|
||||
'4f': { label: '操作事件', color: '#67C23A' }
|
||||
}
|
||||
|
||||
// 报警类型环形图配置(响应式 option 交给 v-chart 渲染)
|
||||
const alarmTypeOption = ref(buildAlarmTypeOption([]))
|
||||
|
||||
// 报警数量折线图配置
|
||||
const alarmCountOption = ref(buildAlarmCountOption([]))
|
||||
|
||||
// 构建报警类型环形图 option
|
||||
function buildAlarmTypeOption(list) {
|
||||
// 按 warnType 分组统计
|
||||
const countMap = {}
|
||||
list.forEach((item) => {
|
||||
const key = String(item.warnType ?? 'unknown')
|
||||
countMap[key] = (countMap[key] || 0) + 1
|
||||
})
|
||||
// 转成 ECharts 数据
|
||||
const chartData = Object.keys(countMap).map((key) => {
|
||||
// key 已经是 String,alarmTypeMap 的键也是字符串
|
||||
const meta = alarmTypeMap[key] || { label: key || '未知', color: '#909399' }
|
||||
return {
|
||||
name: meta.label,
|
||||
value: countMap[key],
|
||||
itemStyle: { color: meta.color }
|
||||
}
|
||||
})
|
||||
const totalCount = chartData.reduce((sum, d) => sum + d.value, 0)
|
||||
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: (params) => `${params.name}<br/>数量:${params.value}(${params.percent}%)`
|
||||
},
|
||||
// 图例放右侧
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 8,
|
||||
top: 'middle',
|
||||
textStyle: { color: '#606266', fontSize: 12 },
|
||||
itemWidth: 10,
|
||||
itemHeight: 10
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '报警类型',
|
||||
type: 'pie',
|
||||
radius: ['52%', '78%'],
|
||||
center: ['38%', '52%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: { show: false },
|
||||
labelLine: { show: false },
|
||||
itemStyle: {
|
||||
borderRadius: 6,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
},
|
||||
// 中心文字
|
||||
graphic: [
|
||||
{
|
||||
type: 'text',
|
||||
left: '38%',
|
||||
top: '46%',
|
||||
style: {
|
||||
text: totalCount,
|
||||
textAlign: 'center',
|
||||
fill: '#303133',
|
||||
fontSize: 22,
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
left: '38%',
|
||||
top: '58%',
|
||||
style: {
|
||||
text: '总数',
|
||||
textAlign: 'center',
|
||||
fill: '#909399',
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
],
|
||||
data: chartData
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// 拉取全部报警数据用于统计(不分页拿全量),同时刷新两个图表
|
||||
const loadChartData = async () => {
|
||||
const res = await serve.getAlarmRecordListByPage({
|
||||
page: 1,
|
||||
pageSize: 9999
|
||||
})
|
||||
if (res.code === 0) {
|
||||
const list = res.data.list || []
|
||||
alarmTypeOption.value = buildAlarmTypeOption(list)
|
||||
alarmCountOption.value = buildAlarmCountOption(list)
|
||||
}
|
||||
}
|
||||
|
||||
// 构建报警数量折线图 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()
|
||||
})
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
getTableData()
|
||||
}
|
||||
const handleCurrentChange = (val) => {
|
||||
page.value = val
|
||||
getTableData()
|
||||
}
|
||||
// 查询
|
||||
const getTableData = async () => {
|
||||
const table = await serve.getAlarmRecordListByPage({
|
||||
page: page.value,
|
||||
pageSize: pageSize.value,
|
||||
...searchInfo.value
|
||||
})
|
||||
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 onSubmit = () => {
|
||||
page.value = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
const onReset = () => {
|
||||
searchInfo.value = {
|
||||
deviceId: ''
|
||||
}
|
||||
getTableData()
|
||||
}
|
||||
</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;
|
||||
|
||||
&.pie {
|
||||
width: 370px;
|
||||
}
|
||||
&.broken-line {
|
||||
flex: 1;
|
||||
}
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
.alarm-type-chart {
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
}
|
||||
.alarm-count-chart {
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
}
|
||||
</style>
|
||||
20
src/view/securityControl/index.vue
Normal file
20
src/view/securityControl/index.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition mode="out-in" name="el-fade-in-linear">
|
||||
<keep-alive :include="routerStore.keepAliveRouters">
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouterStore } from '@/pinia/modules/router'
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
defineOptions({
|
||||
name: 'SecurityControl'
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user