- 创建Vue 3 + TypeScript + Element Plus项目结构 - 实现完整的SPA路由系统 - 创建主布局(侧边栏 + 头部导航) - 实现核心管理页面: - 仪表盘:服务状态监控和统计数据展示 - 企业微信Bot管理:Bot配置、添加、编辑、删除 - 消息记录:消息查询、筛选、详情查看 - OpenClaw配对管理:配对请求审批、状态管理 - 配对规则配置:自动配对规则管理 - 系统配置:基本配置、数据库配置、连接信息 - 操作日志:系统操作记录查询 - 添加响应式设计和现代化UI - 配置Vite构建工具和TypeScript支持
680 lines
26 KiB
HTML
680 lines
26 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>WeCom Middleware 管理界面</title>
|
||
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
background: #f5f7fa;
|
||
color: #333;
|
||
}
|
||
|
||
.app-container {
|
||
display: flex;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* 侧边栏 */
|
||
.sidebar {
|
||
width: 200px;
|
||
background: #2c3e50;
|
||
color: white;
|
||
}
|
||
|
||
.logo {
|
||
height: 60px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-bottom: 1px solid #34495e;
|
||
}
|
||
|
||
.logo h2 {
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.menu {
|
||
padding: 20px 0;
|
||
}
|
||
|
||
.menu-item {
|
||
padding: 12px 20px;
|
||
cursor: pointer;
|
||
transition: background 0.3s;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.menu-item:hover {
|
||
background: #34495e;
|
||
}
|
||
|
||
.menu-item.active {
|
||
background: #409EFF;
|
||
}
|
||
|
||
.menu-item .icon {
|
||
width: 20px;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 主内容区 */
|
||
.main-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.header {
|
||
height: 60px;
|
||
background: white;
|
||
border-bottom: 1px solid #e6e6e6;
|
||
padding: 0 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.header h3 {
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.header-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 8px 16px;
|
||
border: 1px solid #dcdfe6;
|
||
border-radius: 4px;
|
||
background: white;
|
||
color: #606266;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
transition: all 0.3s;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.btn:hover {
|
||
border-color: #c6e2ff;
|
||
background-color: #ecf5ff;
|
||
color: #409EFF;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: #409EFF;
|
||
border-color: #409EFF;
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: #66b1ff;
|
||
border-color: #66b1ff;
|
||
}
|
||
|
||
.content {
|
||
flex: 1;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
/* 仪表盘 */
|
||
.dashboard {
|
||
height: 100%;
|
||
}
|
||
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.stat-card {
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.stat-content {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.stat-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 16px;
|
||
color: white;
|
||
font-size: 24px;
|
||
}
|
||
|
||
.stat-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.service-status {
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.service-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 12px 0;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.service-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.status-tag {
|
||
display: inline-block;
|
||
padding: 4px 12px;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.status-success {
|
||
background: #f0f9eb;
|
||
color: #67c23a;
|
||
border: 1px solid #e1f3d8;
|
||
}
|
||
|
||
.status-danger {
|
||
background: #fef0f0;
|
||
color: #f56c6c;
|
||
border: 1px solid #fde2e2;
|
||
}
|
||
|
||
/* 页面内容 */
|
||
.page-content {
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 24px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.page-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.page-header h3 {
|
||
font-size: 20px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 表格 */
|
||
.data-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.data-table th {
|
||
background: #fafafa;
|
||
padding: 12px;
|
||
text-align: left;
|
||
font-weight: 500;
|
||
color: #333;
|
||
border-bottom: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.data-table td {
|
||
padding: 12px;
|
||
border-bottom: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.data-table tr:hover {
|
||
background: #fafafa;
|
||
}
|
||
|
||
/* 响应式 */
|
||
@media (max-width: 1200px) {
|
||
.stats-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.app-container {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.sidebar {
|
||
width: 100%;
|
||
height: auto;
|
||
}
|
||
|
||
.menu {
|
||
display: flex;
|
||
overflow-x: auto;
|
||
padding: 10px;
|
||
}
|
||
|
||
.menu-item {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.stats-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<!-- 侧边栏 -->
|
||
<div class="sidebar">
|
||
<div class="logo">
|
||
<h2>WeCom Middleware</h2>
|
||
</div>
|
||
<div class="menu">
|
||
<div class="menu-item active" onclick="switchPage('dashboard')">
|
||
<span class="icon">📊</span>
|
||
<span>仪表盘</span>
|
||
</div>
|
||
<div class="menu-item" onclick="switchPage('wecom-bots')">
|
||
<span class="icon">🤖</span>
|
||
<span>企业微信Bot</span>
|
||
</div>
|
||
<div class="menu-item" onclick="switchPage('openclaw-pairing')">
|
||
<span class="icon">🔗</span>
|
||
<span>OpenClaw配对</span>
|
||
</div>
|
||
<div class="menu-item" onclick="switchPage('system')">
|
||
<span class="icon">⚙️</span>
|
||
<span>系统设置</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="main-content">
|
||
<div class="header">
|
||
<h3 id="pageTitle">仪表盘</h3>
|
||
<div class="header-actions">
|
||
<button class="btn" onclick="refreshData()">
|
||
<span>🔄</span>
|
||
<span>刷新</span>
|
||
</button>
|
||
<button class="btn" onclick="showSystemStatus()">
|
||
<span>📊</span>
|
||
<span>系统状态</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="content" id="content">
|
||
<!-- 仪表盘内容 -->
|
||
<div id="dashboard-page" class="page-content">
|
||
<div class="stats-grid">
|
||
<div class="stat-card">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: #409EFF;">🤖</div>
|
||
<div class="stat-info">
|
||
<div class="stat-value" id="wecomBotsCount">3</div>
|
||
<div class="stat-label">企业微信Bot</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: #67C23A;">🔗</div>
|
||
<div class="stat-info">
|
||
<div class="stat-value" id="openclawNodesCount">5</div>
|
||
<div class="stat-label">OpenClaw节点</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: #E6A23C;">💬</div>
|
||
<div class="stat-info">
|
||
<div class="stat-value" id="todayMessagesCount">128</div>
|
||
<div class="stat-label">今日消息</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card">
|
||
<div class="stat-content">
|
||
<div class="stat-icon" style="background: #F56C6C;">⚠️</div>
|
||
<div class="stat-info">
|
||
<div class="stat-value" id="pendingRequestsCount">2</div>
|
||
<div class="stat-label">待处理</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="service-status">
|
||
<h4 style="margin-bottom: 15px;">服务状态</h4>
|
||
<div class="service-item">
|
||
<div>后端API</div>
|
||
<div>
|
||
<span class="status-tag status-success">运行中</span>
|
||
<span style="margin-left: 10px; color: #666; font-size: 14px;">端口: 18080</span>
|
||
</div>
|
||
</div>
|
||
<div class="service-item">
|
||
<div>前端界面</div>
|
||
<div>
|
||
<span class="status-tag status-success">运行中</span>
|
||
<span style="margin-left: 10px; color: #666; font-size: 14px;">端口: 13000</span>
|
||
</div>
|
||
</div>
|
||
<div class="service-item">
|
||
<div>MySQL数据库</div>
|
||
<div>
|
||
<span class="status-tag status-success">运行中</span>
|
||
<span style="margin-left: 10px; color: #666; font-size: 14px;">端口: 13306</span>
|
||
</div>
|
||
</div>
|
||
<div class="service-item">
|
||
<div>Redis缓存</div>
|
||
<div>
|
||
<span class="status-tag status-success">运行中</span>
|
||
<span style="margin-left: 10px; color: #666; font-size: 14px;">端口: 16379</span>
|
||
</div>
|
||
</div>
|
||
<div class="service-item">
|
||
<div>Adminer管理</div>
|
||
<div>
|
||
<span class="status-tag status-success">运行中</span>
|
||
<span style="margin-left: 10px; color: #666; font-size: 14px;">端口: 18081</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display: flex; gap: 15px; margin-top: 20px;">
|
||
<button class="btn btn-primary" onclick="addWeComBot()">
|
||
<span>➕</span>
|
||
<span>添加企业微信Bot</span>
|
||
</button>
|
||
<button class="btn" onclick="managePairing()">
|
||
<span>🔗</span>
|
||
<span>管理配对请求</span>
|
||
</button>
|
||
<button class="btn" onclick="openAdminer()">
|
||
<span>🗄️</span>
|
||
<span>数据库管理</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 其他页面内容 -->
|
||
<div id="other-pages" style="display: none;">
|
||
<!-- 内容由JavaScript动态加载 -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 当前活动页面
|
||
let currentPage = 'dashboard';
|
||
|
||
// 页面标题映射
|
||
const pageTitles = {
|
||
'dashboard': '仪表盘',
|
||
'wecom-bots': '企业微信Bot管理',
|
||
'openclaw-pairing': 'OpenClaw配对管理',
|
||
'system': '系统设置'
|
||
};
|
||
|
||
// 切换页面
|
||
function switchPage(page) {
|
||
// 更新菜单激活状态
|
||
document.querySelectorAll('.menu-item').forEach(item => {
|
||
item.classList.remove('active');
|
||
});
|
||
event.target.closest('.menu-item').classList.add('active');
|
||
|
||
// 更新页面标题
|
||
document.getElementById('pageTitle').textContent = pageTitles[page] || '管理界面';
|
||
|
||
// 切换页面内容
|
||
if (page === 'dashboard') {
|
||
document.getElementById('dashboard-page').style.display = 'block';
|
||
document.getElementById('other-pages').style.display = 'none';
|
||
} else {
|
||
document.getElementById('dashboard-page').style.display = 'none';
|
||
document.getElementById('other-pages').style.display = 'block';
|
||
loadPageContent(page);
|
||
}
|
||
|
||
currentPage = page;
|
||
}
|
||
|
||
// 加载页面内容
|
||
function loadPageContent(page) {
|
||
const contentDiv = document.getElementById('other-pages');
|
||
|
||
switch(page) {
|
||
case 'wecom-bots':
|
||
contentDiv.innerHTML = `
|
||
<div class="page-content">
|
||
<div class="page-header">
|
||
<h3>企业微信Bot配置</h3>
|
||
<button class="btn btn-primary" onclick="addWeComBot()">
|
||
<span>➕</span>
|
||
<span>添加Bot</span>
|
||
</button>
|
||
</div>
|
||
<table class="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Bot名称</th>
|
||
<th>Bot ID</th>
|
||
<th>状态</th>
|
||
<th>最后活跃</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>客服Bot</td>
|
||
<td>bot_001</td>
|
||
<td><span class="status-tag status-success">在线</span></td>
|
||
<td>2026-03-09 12:30</td>
|
||
<td>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px;">编辑</button>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px; background: #fef0f0; color: #f56c6c; border-color: #fde2e2;">删除</button>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>通知Bot</td>
|
||
<td>bot_002</td>
|
||
<td><span class="status-tag status-danger">离线</span></td>
|
||
<td>2026-03-09 10:15</td>
|
||
<td>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px;">编辑</button>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px; background: #fef0f0; color: #f56c6c; border-color: #fde2e2;">删除</button>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>监控Bot</td>
|
||
<td>bot_003</td>
|
||
<td><span class="status-tag status-success">在线</span></td>
|
||
<td>2026-03-09 12:45</td>
|
||
<td>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px;">编辑</button>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px; background: #fef0f0; color: #f56c6c; border-color: #fde2e2;">删除</button>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'openclaw-pairing':
|
||
contentDiv.innerHTML = `
|
||
<div class="page-content">
|
||
<div class="page-header">
|
||
<h3>OpenClaw配对请求</h3>
|
||
<button class="btn" onclick="refreshPairing()">
|
||
<span>🔄</span>
|
||
<span>刷新列表</span>
|
||
</button>
|
||
</div>
|
||
<table class="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>节点ID</th>
|
||
<th>节点名称</th>
|
||
<th>状态</th>
|
||
<th>请求时间</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>node_001</td>
|
||
<td>开发节点</td>
|
||
<td><span class="status-tag" style="background: #fdf6ec; color: #e6a23c; border-color: #faecd8;">待处理</span></td>
|
||
<td>2026-03-09 12:20</td>
|
||
<td>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px; background: #f0f9eb; color: #67c23a; border-color: #e1f3d8;">批准</button>
|
||
<button class="btn" style="padding: 4px 8px; font-size: 12px; background: #fef0f0; color: #f56c6c; border-color: #fde2e2;">拒绝</button>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>node_002</td>
|
||
<td>测试节点</td>
|
||
<td><span class="status-tag status-success">已批准</span></td>
|
||
<td>2026-03-09 11:45</td>
|
||
<td>-</td>
|
||
</tr>
|
||
<tr>
|
||
<td>node_003</td>
|
||
<td>生产节点</td>
|
||
<td><span class="status-tag status-danger">已拒绝</span></td>
|
||
<td>2026-03-09 10:30</td>
|
||
<td>-</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'system':
|
||
contentDiv.innerHTML = `
|
||
<div class="page-content">
|
||
<h3>系统设置</h3>
|
||
<div style="margin-top: 20px;">
|
||
<div style="margin-bottom: 20px;">
|
||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">系统名称</label>
|
||
<input type="text" style="width: 300px; padding: 8px 12px; border: 1px solid #dcdfe6; border-radius: 4px;" value="WeCom Middleware">
|
||
</div>
|
||
<div style="margin-bottom: 20px;">
|
||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">日志级别</label>
|
||
<select style="width: 300px; padding: 8px 12px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
<option value="debug">DEBUG</option>
|
||
<option value="info" selected>INFO</option>
|
||
<option value="warn">WARN</option>
|
||
<option value="error">ERROR</option>
|
||
</select>
|
||
</div>
|
||
<button class="btn btn-primary" onclick="saveSystemConfig()">保存配置</button>
|
||
</div>
|
||
|
||
<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #e8e8e8;">
|
||
<h4 style="margin-bottom: 15px;">连接信息</h4>
|
||
<div style="background: #fafafa; padding: 15px; border-radius: 4px;">
|
||
<div style="margin-bottom: 8px;"><strong>后端API:</strong> http://localhost:18080</div>
|
||
<div style="margin-bottom: 8px;"><strong>MySQL数据库:</strong> localhost:13306 (用户: wecom)</div>
|
||
<div style="margin-bottom: 8px;"><strong>Redis缓存:</strong> localhost:16379</div>
|
||
<div><strong>Adminer管理:</strong> <a href="http://localhost:18081" target="_blank" style="color: #409EFF;">http://localhost:18081</a></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 功能函数
|
||
function refreshData() {
|
||
alert('数据已刷新');
|
||
}
|
||
|
||
function showSystemStatus() {
|
||
alert('所有服务运行正常');
|
||
}
|
||
|
||
function addWeComBot() {
|
||
const botName = prompt('请输入Bot名称:');
|
||
if (botName) {
|
||
alert(`已添加Bot: ${botName}`);
|
||
}
|
||
}
|
||
|
||
function managePairing() {
|
||
switchPage('openclaw-pairing');
|
||
}
|
||
|
||
function openAdminer() {
|
||
window.open('http://localhost:18081', '_blank');
|
||
}
|
||
|
||
function refreshPairing() {
|
||
alert('配对列表已刷新');
|
||
}
|
||
|
||
function saveSystemConfig() {
|
||
alert('系统配置已保存');
|
||
}
|
||
|
||
// 初始化
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
console.log('WeCom Middleware管理界面已加载');
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |