Files
article-writer/templates/index.html
hubian d2ce8f54d4 v1.0 - 文章编写系统初始版本
功能:
- 主题管理(创建/编辑/删除)
- 素材收集(文本/图片)
- Prompt编辑
- 大模型生成文章
- 文章管理(查看/编辑/删除)

技术栈:Flask + SQLite + LLM API
2026-05-21 17:20:13 +08:00

137 lines
7.4 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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文章编写系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet">
<style>
:root { --bg-dark: #0d1117; --bg-card: #161b22; --bg-hover: #1c2333; --border: #30363d; --text: #c9d1d9; --text-muted: #8b949e; --accent: #58a6ff; --accent-hover: #79c0ff; --danger: #f85149; --success: #3fb950; }
* { box-sizing: border-box; }
body { background: var(--bg-dark); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; min-height: 100vh; }
.navbar { background: var(--bg-card); border-bottom: 1px solid var(--border); }
.navbar-brand { color: var(--accent) !important; font-weight: 700; font-size: 1.3rem; }
.topic-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 20px; transition: all 0.2s; cursor: pointer; }
.topic-card:hover { border-color: var(--accent); background: var(--bg-hover); transform: translateY(-2px); }
.topic-card h5 { color: var(--text); margin-bottom: 8px; }
.topic-card .meta { color: var(--text-muted); font-size: 0.85rem; }
.topic-card .desc { color: var(--text-muted); font-size: 0.9rem; margin-top: 8px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.btn-accent { background: var(--accent); color: #fff; border: none; }
.btn-accent:hover { background: var(--accent-hover); color: #fff; }
.btn-outline-accent { border-color: var(--accent); color: var(--accent); }
.btn-outline-accent:hover { background: var(--accent); color: #fff; }
.modal-content { background: var(--bg-card); border: 1px solid var(--border); }
.modal-header { border-bottom: 1px solid var(--border); }
.modal-footer { border-top: 1px solid var(--border); }
.form-control, .form-select { background: var(--bg-dark); border-color: var(--border); color: var(--text); }
.form-control:focus, .form-select:focus { background: var(--bg-dark); border-color: var(--accent); color: var(--text); box-shadow: 0 0 0 2px rgba(88,166,255,0.2); }
.form-label { color: var(--text-muted); font-size: 0.9rem; }
.btn-close { filter: invert(1); }
.empty-state { text-align: center; padding: 80px 20px; color: var(--text-muted); }
.empty-state i { font-size: 4rem; margin-bottom: 16px; display: block; }
.badge-mat { background: rgba(88,166,255,0.15); color: var(--accent); }
</style>
</head>
<body>
<nav class="navbar navbar-expand">
<div class="container">
<a class="navbar-brand" href="/"><i class="bi bi-pencil-square me-2"></i>文章编写系统</a>
<div class="ms-auto">
<button class="btn btn-accent" onclick="showCreateModal()">
<i class="bi bi-plus-lg me-1"></i>新建主题
</button>
</div>
</div>
</nav>
<div class="container py-4">
{% if topics %}
<div class="row g-3">
{% for t in topics %}
<div class="col-md-6 col-lg-4">
<div class="topic-card" onclick="location.href='/topic/{{t.id}}'">
<div class="d-flex justify-content-between align-items-start">
<h5 class="mb-0"><i class="bi bi-folder2-open me-2 text-warning"></i>{{t.name}}</h5>
<button class="btn btn-sm btn-link text-danger p-0" onclick="event.stopPropagation();deleteTopic('{{t.id}}','{{t.name}}')" title="删除">
<i class="bi bi-trash3"></i>
</button>
</div>
{% if t.description %}<div class="desc">{{t.description}}</div>{% endif %}
<div class="meta mt-2">
<span class="badge badge-mat me-1"><i class="bi bi-file-earmark-text me-1"></i>{{t.mat_count}} 素材</span>
<span class="ms-2"><i class="bi bi-clock me-1"></i>{{t.updated_at}}</span>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<i class="bi bi-journal-text"></i>
<h5>还没有主题</h5>
<p>点击右上角「新建主题」开始吧</p>
</div>
{% endif %}
</div>
<!-- 新建主题模态框 -->
<div class="modal fade" id="createModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">新建主题</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">主题名称 *</label>
<input type="text" class="form-control" id="topicName" placeholder="如AI技术趋势">
</div>
<div class="mb-3">
<label class="form-label">主题说明</label>
<textarea class="form-control" id="topicDesc" rows="2" placeholder="简要描述这个主题的方向"></textarea>
</div>
<div class="mb-3">
<label class="form-label">默认Prompt</label>
<textarea class="form-control" id="topicPrompt" rows="4" placeholder="请根据以下素材撰写一篇结构清晰、内容丰富的文章:"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-accent" onclick="createTopic()">创建</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
const modal = new bootstrap.Modal(document.getElementById('createModal'));
function showCreateModal() { modal.show(); }
async function createTopic() {
const name = document.getElementById('topicName').value.trim();
if (!name) return alert('请输入主题名称');
const res = await fetch('/api/topics', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name,
description: document.getElementById('topicDesc').value,
prompt: document.getElementById('topicPrompt').value
})
});
if (res.ok) location.reload();
else { const d = await res.json(); alert(d.error || '创建失败'); }
}
async function deleteTopic(id, name) {
if (!confirm(`确定删除主题「${name}」?所有素材和文章将被清除!`)) return;
const res = await fetch(`/api/topics/${id}`, {method: 'DELETE'});
if (res.ok) location.reload();
}
</script>
</body>
</html>