feat: 更细一次
This commit is contained in:
32
src/api/dataMonitor.js
Normal file
32
src/api/dataMonitor.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
const api = "/mosty-api/mosty-gsxt";
|
||||
/**
|
||||
* 数据监控相关API接口
|
||||
*/
|
||||
|
||||
/**
|
||||
* 获取数据监测统计数据
|
||||
* 接口地址:api+ /gsxt/sjjc/jrsjtj
|
||||
* @returns {Promise} 统计数据
|
||||
*/
|
||||
export function getStatisticsData() {
|
||||
return request({
|
||||
url: api + '/gsxt/sjjc/jrsjtj',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据接入状态列表
|
||||
* 接口地址:api+ /gsxt/sjjc/selectList
|
||||
* @param {string} jklx 监控类型:01 公安内网数据、02 政务数据、03 社会数据、04 非结构化数据
|
||||
* @returns {Promise} 监控数据列表
|
||||
*/
|
||||
export function getMonitorList(params) {
|
||||
return request({
|
||||
url: api + '/gsxt/sjjc/selectList',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
@ -485,6 +485,31 @@ export const publicRoutes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "/dataMonitor",
|
||||
name: "dataMonitor",
|
||||
meta: { title: "数据监控", icon: "article" },
|
||||
children: [
|
||||
{
|
||||
path: "/resourceMonitoring",
|
||||
name: "resourceMonitoring",
|
||||
component: () => import("@/views/backOfficeSystem/dataMonitor/resourceMonitoring/index.vue"),
|
||||
meta: {
|
||||
title: "数据资源检测",
|
||||
icon: "article"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/onlineUserMonitoring",
|
||||
name: "onlineUserMonitoring",
|
||||
component: () => import("@/views/backOfficeSystem/dataMonitor/onlineUserMonitoring/index.vue"),
|
||||
meta: {
|
||||
title: "在线用户监控",
|
||||
icon: "article"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "/IntelligentControl",
|
||||
name: "IntelligentControl",
|
||||
|
||||
@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<div class="data-table-card" :class="`${type}-table`">
|
||||
<div class="table-header">
|
||||
<div class="header-left">
|
||||
<span class="circle-point" :style="{ backgroundColor: color }"></span>
|
||||
<span class="table-title">{{ title }}</span>
|
||||
<!-- <el-tag size="small" type="success">{{ total }} 条</el-tag> -->
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-button type="text" size="small" @click="handleRefresh">
|
||||
<el-icon>
|
||||
<Refresh />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<el-table :data="tableData" style="width: 100%" :loading="loading" height="280" :row-class-name="getRowClassName">
|
||||
<el-table-column prop="jklx" label="监控类型">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small" type="info">{{ jklxCname[row.jklx] }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sjly" label="数据来源" show-overflow-tooltip />
|
||||
<el-table-column prop="gxsj" label="最近更新时间">
|
||||
<template #default="{ row }">
|
||||
<div class="time-info">
|
||||
<el-icon>
|
||||
<Clock />
|
||||
</el-icon>
|
||||
<span>{{ row.gxsj || '' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="online" label="通道状态" align="center">
|
||||
<template #default="{ row }">
|
||||
<div class="status-badge" :class="{ online: row.online }">
|
||||
<div class="status-dot"></div>
|
||||
<span>{{ row.online ? '在线' : '离线' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { Refresh, Clock } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getMonitorList } from '@/api/dataMonitor'
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: (value) => ['police', 'government', 'social', 'unstructured'].includes(value)
|
||||
},
|
||||
/** 颜色标题数组 */
|
||||
opt: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const color = computed(() => {
|
||||
const opt = props.opt.find(item => item.type === props.type)
|
||||
console.log('opt: ', opt);
|
||||
return opt ? opt.color : '#409EFF'
|
||||
|
||||
})
|
||||
|
||||
// 组件内部状态
|
||||
const loading = ref(false)
|
||||
const data = ref([])
|
||||
|
||||
// 类型到监控类型的映射
|
||||
const typeToJklx = {
|
||||
/** 01 公安内网数据 */
|
||||
police: '01',
|
||||
/** 02 政务数据 */
|
||||
government: '02',
|
||||
/** 03 社会数据 */
|
||||
social: '03',
|
||||
/** 04 非结构化数据 */
|
||||
unstructured: '04'
|
||||
}
|
||||
|
||||
const jklxCname = {
|
||||
'01': '公安内网数据',
|
||||
'02': '政务数据',
|
||||
'03': '社会数据',
|
||||
'04': '非结构化数据'
|
||||
}
|
||||
// 获取数据
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const jklx = typeToJklx[props.type]
|
||||
const params = {
|
||||
pageCurrent: 1,
|
||||
pageSize: 40,
|
||||
jklx: jklx || '01'
|
||||
}
|
||||
const res = await getMonitorList(params) || {}
|
||||
// 通道是否在线:0 不在线 、1 在线
|
||||
const onlineStatus = {
|
||||
0: '不在线',
|
||||
1: '在线'
|
||||
}
|
||||
// 处理数据,添加在线状态
|
||||
data.value = (res || []).map(item => ({
|
||||
...item,
|
||||
online: onlineStatus[item.sfzx]
|
||||
}))
|
||||
} catch (error) {
|
||||
ElMessage.error(`获取${props.title}数据失败`)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 计算属性:表格数据
|
||||
const tableData = computed(() => data.value)
|
||||
// 总数
|
||||
const total = ref(0)
|
||||
|
||||
|
||||
// 获取表格行类名
|
||||
const getRowClassName = ({ row }) => {
|
||||
return row.online == 1 ? 'online-row' : 'offline-row'
|
||||
}
|
||||
|
||||
// 刷新处理
|
||||
const handleRefresh = async() => {
|
||||
await fetchData()
|
||||
ElMessage.success(`数据刷新成功`)
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.data-table-card {
|
||||
background: white;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
background: #f5f7fa;
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
.circle-point {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
border-radius: 50%;
|
||||
background: inherit;
|
||||
opacity: 0.3;
|
||||
animation: pulse-light 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
.table-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
.el-button {
|
||||
color: #909399;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 状态徽章样式
|
||||
.status-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
// padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
|
||||
&.online {
|
||||
color: #67c23a;
|
||||
background: #f0f9ff;
|
||||
}
|
||||
|
||||
&:not(.online) {
|
||||
color: #f56c6c;
|
||||
background: #fef0f0;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
// 时间信息样式
|
||||
.time-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #606266;
|
||||
font-size: 12px;
|
||||
|
||||
.el-icon {
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
// 光圈动画
|
||||
@keyframes pulse-light {
|
||||
0% {
|
||||
opacity: 0.3;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.1;
|
||||
transform: scale(1.3);
|
||||
}
|
||||
100% {
|
||||
opacity: 0.3;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 表格行状态
|
||||
:deep(.el-table) {
|
||||
.online-row {
|
||||
background-color: #f0f9ff;
|
||||
}
|
||||
|
||||
.offline-row {
|
||||
background-color: #fef0f0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
开发中。。
|
||||
</div>
|
||||
</template>
|
||||
@ -0,0 +1,336 @@
|
||||
<template>
|
||||
<div class="data-monitor-container">
|
||||
<!-- 第一行:统计数据展示 -->
|
||||
<div class="statistics-section">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="6" v-for="item in statisticsData" :key="item.type">
|
||||
<div class="statistics-card" :class="item.type" :style="{ backgroundColor: item.color }">
|
||||
<div class="card-background">
|
||||
<div class="bg-pattern"></div>
|
||||
</div>
|
||||
<div class="statistics-content">
|
||||
<div class="statistics-icon">
|
||||
<el-icon size="48">
|
||||
<component :is="item.icon" />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="statistics-info">
|
||||
<div class="statistics-title">{{ item.title }}</div>
|
||||
<div class="statistics-value">{{ item.value }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 第二行:公安内网数据和政务数据 -->
|
||||
<div class="table-section">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<DataTableCard :opt="statisticsData" title="公安内网数据" type="police" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<DataTableCard :opt="statisticsData" title="政务数据" type="government" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 第三行:社会数据和非结构化数据 -->
|
||||
<div class="table-section">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<DataTableCard :opt="statisticsData" title="社会数据" type="social" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<DataTableCard :opt="statisticsData" title="非结构化数据" type="unstructured" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Monitor, DataLine, User, Document } from '@element-plus/icons-vue'
|
||||
import { getStatisticsData } from '@/api/dataMonitor'
|
||||
import DataTableCard from '../components/DataTableCard.vue'
|
||||
|
||||
// 统计数据
|
||||
const statisticsData = ref([
|
||||
{
|
||||
type: 'police',
|
||||
title: '公安内网数据',
|
||||
value: 0,
|
||||
icon: Monitor,
|
||||
color: '#409EFF',
|
||||
},
|
||||
{
|
||||
type: 'government',
|
||||
title: '政务数据',
|
||||
value: 0,
|
||||
icon: DataLine,
|
||||
color: '#67C23A',
|
||||
},
|
||||
{
|
||||
type: 'social',
|
||||
title: '社会数据',
|
||||
value: 0,
|
||||
icon: User,
|
||||
color: '#E6A23C',
|
||||
},
|
||||
{
|
||||
type: 'unstructured',
|
||||
title: '非结构化数据',
|
||||
value: 0,
|
||||
icon: Document,
|
||||
color: '#F56C6C',
|
||||
}
|
||||
])
|
||||
|
||||
// 获取统计数据
|
||||
const fetchStatisticsData = async () => {
|
||||
try {
|
||||
const res = await getStatisticsData()
|
||||
console.log('res: ', res)
|
||||
if (res) {
|
||||
statisticsData.value[0].value = res.ganwsj || 0 // 公安内网数据
|
||||
statisticsData.value[1].value = res.zwsj || 0 // 政务数据
|
||||
statisticsData.value[2].value = res.shsj || 0 // 社会数据
|
||||
statisticsData.value[3].value = res.fjghsj || 0 // 非结构化数据
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取统计数据失败:', error)
|
||||
ElMessage.error('获取统计数据失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 处理表格刷新事件
|
||||
const handleTableRefresh = (type) => {
|
||||
ElMessage.success('数据已刷新')
|
||||
}
|
||||
|
||||
// 页面加载时获取统计数据
|
||||
onMounted(() => {
|
||||
fetchStatisticsData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.data-monitor-container {
|
||||
height: calc(100vh - 125px);
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// 页面头部
|
||||
.page-header {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
|
||||
.title-icon {
|
||||
margin-right: 12px;
|
||||
font-size: 32px;
|
||||
color: #667eea;
|
||||
}
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片样式
|
||||
.statistics-section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.statistics-card {
|
||||
position: relative;
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
// cursor: pointer;
|
||||
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
// overflow: hidden;
|
||||
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
|
||||
backdrop-filter: blur(4px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-8px) scale(1.02);
|
||||
box-shadow: 0 16px 48px rgba(31, 38, 135, 0.25);
|
||||
}
|
||||
|
||||
&.police {
|
||||
.statistics-icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.government {
|
||||
.statistics-icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.social {
|
||||
.statistics-icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.unstructured {
|
||||
.statistics-icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0.1;
|
||||
|
||||
.bg-pattern {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: radial-gradient(circle, white 1px, transparent 1px);
|
||||
background-size: 20px 20px;
|
||||
border-radius: 50%;
|
||||
top: -100px;
|
||||
right: -100px;
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.statistics-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.statistics-icon {
|
||||
margin-right: 20px;
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.statistics-info {
|
||||
flex: 1;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.statistics-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.statistics-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 表格区域样式
|
||||
.table-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 1200px) {
|
||||
.statistics-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.data-monitor-container {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
padding: 16px;
|
||||
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.statistics-card {
|
||||
padding: 16px;
|
||||
|
||||
.statistics-content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.statistics-icon {
|
||||
margin-right: 0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.statistics-value {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-header {
|
||||
padding: 12px 16px;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user