<!DOCTYPE html>
|
<html lang="zh-CN">
|
|
<head>
|
<meta charset="utf-8">
|
<title>WebSocket连接监控</title>
|
<meta name="renderer" content="webkit">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<link rel="stylesheet" href="../../static/vue/element/element.css">
|
<style>
|
* {
|
margin: 0;
|
padding: 0;
|
box-sizing: border-box;
|
}
|
|
body {
|
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
|
background: #f5f7fa;
|
padding: 15px;
|
}
|
|
.app-container {
|
background: #fff;
|
border-radius: 8px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
padding: 20px;
|
}
|
|
.stats-cards {
|
display: flex;
|
gap: 15px;
|
margin-bottom: 20px;
|
flex-wrap: wrap;
|
}
|
|
.stat-card {
|
background: linear-gradient(135deg, #409eff, #66b1ff);
|
border-radius: 8px;
|
padding: 20px 30px;
|
color: #fff;
|
min-width: 200px;
|
flex: 1;
|
max-width: 300px;
|
}
|
|
.stat-card .label {
|
font-size: 14px;
|
opacity: 0.9;
|
margin-bottom: 8px;
|
}
|
|
.stat-card .value {
|
font-size: 36px;
|
font-weight: bold;
|
}
|
|
.header-section {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 15px;
|
}
|
|
.header-section .title {
|
font-size: 16px;
|
font-weight: bold;
|
color: #303133;
|
}
|
|
.status-dot {
|
display: inline-block;
|
width: 8px;
|
height: 8px;
|
border-radius: 50%;
|
margin-right: 6px;
|
}
|
|
.status-online {
|
background: #67c23a;
|
}
|
|
.pagination-section {
|
margin-top: 20px;
|
display: flex;
|
justify-content: flex-end;
|
}
|
|
.auto-refresh-bar {
|
display: flex;
|
align-items: center;
|
gap: 10px;
|
margin-bottom: 15px;
|
font-size: 13px;
|
color: #909399;
|
}
|
</style>
|
</head>
|
|
<body>
|
<div id="app">
|
<div class="app-container">
|
<!-- 统计卡片 -->
|
<div class="stats-cards">
|
<div class="stat-card">
|
<div class="label">WebSocket连接总数</div>
|
<div class="value">{{ total }}</div>
|
</div>
|
</div>
|
|
<!-- 自动刷新控制 -->
|
<div class="auto-refresh-bar">
|
<el-switch v-model="autoRefresh" active-text="自动刷新" inactive-text="关闭"></el-switch>
|
<span>每5秒刷新一次</span>
|
<el-button size="mini" type="primary" icon="el-icon-refresh" @click="loadData"
|
:loading="loading">手动刷新</el-button>
|
</div>
|
|
<!-- 表格区域 -->
|
<div class="header-section">
|
<span class="title">连接列表</span>
|
<span style="color: #909399; font-size: 13px;">最后刷新: {{ lastRefreshTime || '-' }}</span>
|
</div>
|
|
<el-table :data="pagedData" border stripe v-loading="loading"
|
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }" style="width: 100%;">
|
<el-table-column type="index" label="序号" width="60" align="center"
|
:index="indexMethod"></el-table-column>
|
<el-table-column prop="ip" label="客户端IP" min-width="140" align="center"></el-table-column>
|
<el-table-column prop="deviceName" label="设备名称" min-width="180">
|
<template slot-scope="scope">
|
{{ scope.row.deviceName || '-' }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="sessionId" label="会话ID" min-width="200" show-overflow-tooltip>
|
<template slot-scope="scope">
|
{{ scope.row.sessionId || '-' }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="open" label="状态" width="100" align="center">
|
<template slot-scope="scope">
|
<span>
|
<span class="status-dot" :class="scope.row.open ? 'status-online' : ''"></span>
|
{{ scope.row.open ? '活跃' : '已关闭' }}
|
</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<!-- 分页 -->
|
<div class="pagination-section" v-if="connections.length > pageSize">
|
<el-pagination background layout="total, prev, pager, next" :total="connections.length"
|
:page-size="pageSize" :current-page="currentPage" @current-change="handlePageChange">
|
</el-pagination>
|
</div>
|
|
<!-- 空状态 -->
|
<div v-if="!loading && connections.length === 0"
|
style="text-align: center; padding: 60px; color: #909399;">
|
<i class="el-icon-warning-outline" style="font-size: 48px; margin-bottom: 15px;"></i>
|
<div>暂无WebSocket连接</div>
|
</div>
|
</div>
|
</div>
|
|
<script src="../../static/vue/js/vue.min.js"></script>
|
<script src="../../static/vue/element/element.js"></script>
|
<script src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
|
<script src="../../static/js/common.js"></script>
|
<script>
|
new Vue({
|
el: '#app',
|
data: {
|
connections: [],
|
total: 0,
|
loading: false,
|
autoRefresh: true,
|
refreshTimer: null,
|
lastRefreshTime: '',
|
currentPage: 1,
|
pageSize: 10
|
},
|
|
computed: {
|
pagedData() {
|
var start = (this.currentPage - 1) * this.pageSize;
|
return this.connections.slice(start, start + this.pageSize);
|
}
|
},
|
|
created() {
|
this.loadData();
|
this.startAutoRefresh();
|
},
|
|
watch: {
|
autoRefresh: function (val) {
|
if (val) {
|
this.startAutoRefresh();
|
} else {
|
this.stopAutoRefresh();
|
}
|
}
|
},
|
|
methods: {
|
getHeaders() {
|
return { 'token': localStorage.getItem('token') };
|
},
|
|
loadData() {
|
this.loading = true;
|
var self = this;
|
$.ajax({
|
url: baseUrl + '/tvDevice/tvWebSocket/status/auth',
|
headers: this.getHeaders(),
|
success: function (res) {
|
self.loading = false;
|
if (res.code === 200) {
|
self.connections = res.data.connections || [];
|
self.total = res.data.total || 0;
|
self.lastRefreshTime = self.formatTime(new Date());
|
} else if (res.code === 403) {
|
top.location.href = baseUrl + '/';
|
} else {
|
self.$message.error(res.msg || '加载失败');
|
}
|
},
|
error: function () {
|
self.loading = false;
|
self.$message.error('请求失败');
|
}
|
});
|
},
|
|
startAutoRefresh() {
|
this.stopAutoRefresh();
|
this.refreshTimer = setInterval(this.loadData, 5000);
|
},
|
|
stopAutoRefresh() {
|
if (this.refreshTimer) {
|
clearInterval(this.refreshTimer);
|
this.refreshTimer = null;
|
}
|
},
|
|
handlePageChange(page) {
|
this.currentPage = page;
|
},
|
|
indexMethod(index) {
|
return (this.currentPage - 1) * this.pageSize + index + 1;
|
},
|
|
formatTime(date) {
|
var h = String(date.getHours()).padStart(2, '0');
|
var m = String(date.getMinutes()).padStart(2, '0');
|
var s = String(date.getSeconds()).padStart(2, '0');
|
return h + ':' + m + ':' + s;
|
}
|
},
|
|
beforeDestroy() {
|
this.stopAutoRefresh();
|
}
|
});
|
</script>
|
</body>
|
|
</html>
|