182 lines
9.4 KiB
HTML
182 lines
9.4 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>PPT智能管理系统</title>
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<style>
|
||
@keyframes spin {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
.animate-spin {
|
||
animation: spin 1s linear infinite;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body class="bg-gradient-to-br from-blue-50 to-indigo-100 min-h-screen">
|
||
<div class="container mx-auto px-4 py-8 max-w-5xl">
|
||
<div class="text-center mb-10">
|
||
<h1 class="text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-purple-600 mb-3">
|
||
📊 PPT智能管理系统
|
||
</h1>
|
||
<p class="text-gray-600 text-lg">静态模板 + 动态数据 = 一键生成最新报告</p>
|
||
</div>
|
||
|
||
<div class="grid md:grid-cols-2 gap-6 mb-8">
|
||
<div class="bg-white rounded-2xl shadow-xl p-6">
|
||
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
||
<span class="mr-2">📁</span> 可用项目
|
||
</h2>
|
||
|
||
<div id="projects-list" class="space-y-3">
|
||
{% for project in projects %}
|
||
<div class="project-card border-2 border-gray-200 hover:border-blue-400 rounded-xl p-4 transition-all duration-300 hover:shadow-md cursor-pointer" data-project="{{ project.id }}">
|
||
<div class="flex justify-between items-center">
|
||
<div>
|
||
<h3 class="font-bold text-gray-800">{{ project.name }}</h3>
|
||
<p class="text-sm text-gray-500">共 {{ project.total_slides }} 页</p>
|
||
</div>
|
||
<button onclick="generatePPT('{{ project.id }}')"
|
||
class="bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white px-5 py-2.5 rounded-lg font-medium transition-all duration-300 transform hover:scale-105 shadow-md hover:shadow-lg">
|
||
🚀 开始生成
|
||
</button>
|
||
</div>
|
||
<div class="mt-3 text-xs text-gray-500">
|
||
<span class="bg-green-100 text-green-700 px-2 py-1 rounded-full mr-1">
|
||
{% set static_pages = project.slide_mapping.values() | list %}
|
||
静态: {{ static_pages | count_item('static') }} 页
|
||
</span>
|
||
<span class="bg-orange-100 text-orange-700 px-2 py-1 rounded-full">
|
||
{% set static_count = static_pages | count_item('static') %}
|
||
动态: {{ project.total_slides - static_count }} 页
|
||
</span>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
|
||
<div id="status" class="mt-4 hidden">
|
||
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||
<div class="flex items-center">
|
||
<svg class="animate-spin h-5 w-5 mr-3 text-blue-500" viewBox="0 0 24 24">
|
||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle>
|
||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||
</svg>
|
||
<span id="status-text" class="text-blue-700 font-medium">正在生成PPT,请稍候...</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="result" class="mt-4 hidden">
|
||
<div class="bg-green-50 border border-green-200 rounded-lg p-4">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<p class="text-green-700 font-bold">✅ PPT生成成功!</p>
|
||
<p id="result-filename" class="text-green-600 text-sm mt-1"></p>
|
||
</div>
|
||
<a id="download-btn" href="#" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg font-medium transition-colors">
|
||
📥 下载文件
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="error" class="mt-4 hidden">
|
||
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
|
||
<p class="text-red-700 font-bold">❌ 生成失败</p>
|
||
<p id="error-message" class="text-red-600 text-sm mt-1"></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-2xl shadow-xl p-6">
|
||
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
||
<span class="mr-2">📋</span> 已生成文件
|
||
</h2>
|
||
<div id="files-list" class="space-y-2 max-h-96 overflow-y-auto">
|
||
<p class="text-gray-500 text-sm">加载中...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-2xl shadow-xl p-6">
|
||
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
||
<span class="mr-2">📖</span> 使用说明
|
||
</h2>
|
||
<div class="grid md:grid-cols-3 gap-4 text-sm">
|
||
<div class="bg-gray-50 rounded-xl p-4">
|
||
<h3 class="font-bold text-gray-700 mb-2">1️⃣ 准备静态模板</h3>
|
||
<p class="text-gray-600">将固定不变的PPT模板放入 static_ppt 目录</p>
|
||
</div>
|
||
<div class="bg-gray-50 rounded-xl p-4">
|
||
<h3 class="font-bold text-gray-700 mb-2">2️⃣ 配置页面映射</h3>
|
||
<p class="text-gray-600">在 config/project_config.yaml 中配置每页是静态或动态</p>
|
||
</div>
|
||
<div class="bg-gray-50 rounded-xl p-4">
|
||
<h3 class="font-bold text-gray-700 mb-2">3️⃣ 编写动态脚本</h3>
|
||
<p class="text-gray-600">在 scripts 目录编写数据爬取和图表生成脚本</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function generatePPT(projectName) {
|
||
const statusEl = document.getElementById('status');
|
||
const resultEl = document.getElementById('result');
|
||
const errorEl = document.getElementById('error');
|
||
|
||
statusEl.classList.remove('hidden');
|
||
resultEl.classList.add('hidden');
|
||
errorEl.classList.add('hidden');
|
||
|
||
fetch(`/api/generate/${projectName}`, { method: 'POST' })
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
statusEl.classList.add('hidden');
|
||
if (data.success) {
|
||
resultEl.classList.remove('hidden');
|
||
document.getElementById('result-filename').textContent = data.filename;
|
||
document.getElementById('download-btn').href = data.download_url;
|
||
loadFiles();
|
||
} else {
|
||
errorEl.classList.remove('hidden');
|
||
document.getElementById('error-message').textContent = data.message;
|
||
}
|
||
})
|
||
.catch(err => {
|
||
statusEl.classList.add('hidden');
|
||
errorEl.classList.remove('hidden');
|
||
document.getElementById('error-message').textContent = err.message;
|
||
});
|
||
}
|
||
|
||
function loadFiles() {
|
||
fetch('/api/files')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
const filesList = document.getElementById('files-list');
|
||
if (data.files.length === 0) {
|
||
filesList.innerHTML = '<p class="text-gray-500 text-sm">暂无生成的文件</p>';
|
||
} else {
|
||
filesList.innerHTML = data.files.map(f => `
|
||
<div class="flex justify-between items-center bg-gray-50 rounded-lg p-3 hover:bg-gray-100 transition-colors">
|
||
<div>
|
||
<p class="font-medium text-gray-700 text-sm">${f.name}</p>
|
||
<p class="text-xs text-gray-500">${f.size} MB</p>
|
||
</div>
|
||
<a href="/download/${f.name}" class="text-blue-500 hover:text-blue-700 text-sm font-medium">
|
||
下载
|
||
</a>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
});
|
||
}
|
||
|
||
loadFiles();
|
||
</script>
|
||
</body>
|
||
</html>
|