Files
hubian 45b8c70cb9 新增后台管理系统
功能模块:
- 仪表盘: 统计数据概览、快速操作入口
- 资料池管理: 查看、搜索、删除资料
- 文章历史: 查看历史文章列表和主题标签
- 工作流控制: 新建工作流、配置参数、启动流程
- 系统设置: LLM配置、文章类型、数据管理

技术栈:
- Flask Web框架
- Tailwind CSS
- RESTful API
- 实时LLM连接测试
2026-04-08 11:48:39 +08:00

226 lines
11 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>文章撰写工作流系统 - 后台管理</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
<style>
.sidebar { transition: all 0.3s; }
.card { transition: all 0.2s; }
.card:hover { transform: translateY(-2px); box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1); }
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="flex">
<!-- 侧边栏 -->
<aside class="sidebar w-64 bg-slate-800 min-h-screen fixed left-0 top-0">
<div class="p-6">
<h1 class="text-white text-xl font-bold flex items-center gap-2">
<i class="ri-article-line text-2xl text-blue-400"></i>
文章工作流
</h1>
<p class="text-slate-400 text-sm mt-1">后台管理系统</p>
</div>
<nav class="mt-6">
<a href="/" class="nav-link flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white transition-colors">
<i class="ri-dashboard-line text-lg"></i>
<span>仪表盘</span>
</a>
<a href="/resources" class="nav-link flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white transition-colors">
<i class="ri-database-2-line text-lg"></i>
<span>资料池</span>
</a>
<a href="/articles" class="nav-link flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white transition-colors">
<i class="ri-file-list-3-line text-lg"></i>
<span>文章历史</span>
</a>
<a href="/workflow" class="nav-link flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white transition-colors">
<i class="ri-flow-chart text-lg"></i>
<span>工作流</span>
</a>
<a href="/settings" class="nav-link flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white transition-colors">
<i class="ri-settings-3-line text-lg"></i>
<span>系统设置</span>
</a>
</nav>
</aside>
<!-- 主内容区 -->
<main class="ml-64 flex-1 p-8">
<!-- 统计卡片 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div class="card bg-white rounded-xl p-6 shadow-sm border border-gray-100">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">资料总数</p>
<p class="text-3xl font-bold text-gray-800 mt-2" id="stat-resources">-</p>
</div>
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
<i class="ri-database-2-line text-2xl text-blue-600"></i>
</div>
</div>
</div>
<div class="card bg-white rounded-xl p-6 shadow-sm border border-gray-100">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">已分析</p>
<p class="text-3xl font-bold text-gray-800 mt-2" id="stat-analyzed">-</p>
</div>
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center">
<i class="ri-check-double-line text-2xl text-green-600"></i>
</div>
</div>
</div>
<div class="card bg-white rounded-xl p-6 shadow-sm border border-gray-100">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">文章总数</p>
<p class="text-3xl font-bold text-gray-800 mt-2" id="stat-articles">-</p>
</div>
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center">
<i class="ri-article-line text-2xl text-purple-600"></i>
</div>
</div>
</div>
<div class="card bg-white rounded-xl p-6 shadow-sm border border-gray-100">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">关键词数</p>
<p class="text-3xl font-bold text-gray-800 mt-2" id="stat-keywords">-</p>
</div>
<div class="w-12 h-12 bg-orange-100 rounded-lg flex items-center justify-center">
<i class="ri-key-2-line text-2xl text-orange-600"></i>
</div>
</div>
</div>
</div>
<!-- 快速操作 -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
<div class="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
<h2 class="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
<i class="ri-rocket-line text-blue-500"></i>
快速开始
</h2>
<div class="space-y-3">
<a href="/workflow" class="flex items-center gap-3 p-3 bg-blue-50 rounded-lg hover:bg-blue-100 transition-colors">
<i class="ri-add-circle-line text-blue-600 text-xl"></i>
<div>
<p class="font-medium text-gray-800">新建工作流</p>
<p class="text-sm text-gray-500">启动一个完整的文章撰写流程</p>
</div>
</a>
<a href="/resources" class="flex items-center gap-3 p-3 bg-green-50 rounded-lg hover:bg-green-100 transition-colors">
<i class="ri-upload-cloud-line text-green-600 text-xl"></i>
<div>
<p class="font-medium text-gray-800">添加资料</p>
<p class="text-sm text-gray-500">手动添加URL或内容到资料池</p>
</div>
</a>
</div>
</div>
<div class="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
<h2 class="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
<i class="ri-history-line text-purple-500"></i>
最近文章
</h2>
<div class="space-y-3" id="recent-articles">
<p class="text-gray-500 text-sm">加载中...</p>
</div>
</div>
</div>
<!-- 系统状态 -->
<div class="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
<h2 class="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
<i class="ri-server-line text-green-500"></i>
系统状态
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="p-4 bg-gray-50 rounded-lg">
<p class="text-sm text-gray-500">LLM模型</p>
<p class="font-medium text-gray-800" id="llm-model">-</p>
</div>
<div class="p-4 bg-gray-50 rounded-lg">
<p class="text-sm text-gray-500">API地址</p>
<p class="font-medium text-gray-800 text-sm truncate" id="llm-url">-</p>
</div>
<div class="p-4 bg-gray-50 rounded-lg">
<p class="text-sm text-gray-500">连接状态</p>
<p class="font-medium" id="llm-status">
<span class="text-yellow-500">检测中...</span>
</p>
</div>
</div>
</div>
</main>
</div>
<script>
// 加载统计数据
async function loadStats() {
const response = await fetch('/api/stats');
const data = await response.json();
document.getElementById('stat-resources').textContent = data.resources_count || 0;
document.getElementById('stat-analyzed').textContent = data.analyzed_count || 0;
document.getElementById('stat-articles').textContent = data.articles_count || 0;
document.getElementById('stat-keywords').textContent = data.keywords_count || 0;
// 最近文章
const recentDiv = document.getElementById('recent-articles');
if (data.recent_articles && data.recent_articles.length > 0) {
recentDiv.innerHTML = data.recent_articles.map(a => `
<a href="/articles" class="flex items-center justify-between p-2 hover:bg-gray-50 rounded transition-colors">
<div class="truncate">
<p class="font-medium text-gray-800 truncate">${a.topic}</p>
<p class="text-sm text-gray-500">${a.type} · ${new Date(a.date).toLocaleDateString()}</p>
</div>
<i class="ri-arrow-right-s-line text-gray-400"></i>
</a>
`).join('');
} else {
recentDiv.innerHTML = '<p class="text-gray-500 text-sm">暂无文章记录</p>';
}
}
// 加载配置
async function loadConfig() {
const response = await fetch('/api/config');
const data = await response.json();
document.getElementById('llm-model').textContent = data.model || '-';
document.getElementById('llm-url').textContent = data.base_url || '-';
}
// 测试LLM连接
async function testLLM() {
const statusEl = document.getElementById('llm-status');
try {
const response = await fetch('/api/test-llm', { method: 'POST' });
const data = await response.json();
if (data.success) {
statusEl.innerHTML = '<span class="text-green-500"><i class="ri-check-line"></i> 已连接</span>';
} else {
statusEl.innerHTML = '<span class="text-red-500"><i class="ri-close-line"></i> 连接失败</span>';
}
} catch (e) {
statusEl.innerHTML = '<span class="text-red-500"><i class="ri-close-line"></i> 连接错误</span>';
}
}
// 初始化
loadStats();
loadConfig();
testLLM();
</script>
</body>
</html>