Files
wecome-middleware/frontend/index.html
xudw dd6dee45a1 feat: 创建完整的Vue + Element UI前端管理界面
- 创建Vue 3 + TypeScript + Element Plus项目结构
- 实现完整的SPA路由系统
- 创建主布局(侧边栏 + 头部导航)
- 实现核心管理页面:
  - 仪表盘:服务状态监控和统计数据展示
  - 企业微信Bot管理:Bot配置、添加、编辑、删除
  - 消息记录:消息查询、筛选、详情查看
  - OpenClaw配对管理:配对请求审批、状态管理
  - 配对规则配置:自动配对规则管理
  - 系统配置:基本配置、数据库配置、连接信息
  - 操作日志:系统操作记录查询
- 添加响应式设计和现代化UI
- 配置Vite构建工具和TypeScript支持
2026-03-09 14:03:05 +08:00

680 lines
26 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>