Files
tech-forum/frontend/create.html
hubian 7f8fbc9605 初始化技术论坛与技术分享网站
功能模块:
- 技术交流: 发帖、评论回复、点赞收藏、标签分类
- 工具分享: 创建主题、子主题分支、问题追问、关注功能
- 用户系统: 用户名+邮箱(必填)+手机(可选)+密码确认

页面:
- 首页: 帖子列表、热门标签、工具分享主题
- 登录/注册页
- 发帖页
- 帖子详情页
- 主题详情页
- 用户主页

技术栈:
- Flask + Tailwind CSS
- JSON文件存储
- JWT认证
- 响应式设计

端口: 19004
2026-04-08 12:35:09 +08:00

156 lines
6.8 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>发布帖子 - 技术论坛</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>
.gradient-bg { background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%); }
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<!-- 导航栏 -->
<nav class="bg-white border-b border-gray-100">
<div class="max-w-4xl mx-auto px-4 py-4">
<a href="/" class="text-gray-600 hover:text-gray-800 flex items-center gap-1">
<i class="ri-arrow-left-line"></i> 返回首页
</a>
</div>
</nav>
<main class="max-w-4xl mx-auto px-4 py-8">
<h1 class="text-2xl font-bold text-gray-800 mb-6">发布新帖子</h1>
<form id="postForm" class="bg-white rounded-lg border border-gray-100 p-6">
<!-- 帖子类型 -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">帖子类型</label>
<div class="flex gap-4">
<label class="flex items-center gap-2 cursor-pointer">
<input type="radio" name="type" value="discussion" checked class="text-blue-600">
<span class="flex items-center gap-1">
<i class="ri-discuss-line text-blue-500"></i> 技术交流
</span>
</label>
<label class="flex items-center gap-2 cursor-pointer">
<input type="radio" name="type" value="share" class="text-purple-600">
<span class="flex items-center gap-1">
<i class="ri-tools-line text-purple-500"></i> 工具分享
</span>
</label>
</div>
</div>
<!-- 标题 -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">标题</label>
<input type="text" id="title" placeholder="请输入帖子标题"
class="w-full px-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
<!-- 内容 -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">内容</label>
<textarea id="content" rows="12" placeholder="请输入帖子内容支持Markdown格式..."
class="w-full px-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"></textarea>
</div>
<!-- 标签 -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">
标签 <span class="text-gray-400">(用逗号分隔)</span>
</label>
<input type="text" id="tags" placeholder="如Python, Django, Web开发"
class="w-full px-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
<!-- 提交按钮 -->
<div class="flex gap-3">
<button type="submit" class="px-6 py-3 gradient-bg text-white rounded-lg font-medium hover:opacity-90">
发布帖子
</button>
<button type="button" onclick="saveDraft()" class="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50">
保存草稿
</button>
</div>
</form>
<div id="errorMsg" class="mt-4 p-3 bg-red-50 text-red-500 rounded-lg text-sm hidden"></div>
</main>
<script>
// 检查登录
if (!localStorage.getItem('token')) {
window.location.href = '/login';
}
document.getElementById('postForm').addEventListener('submit', async (e) => {
e.preventDefault();
const title = document.getElementById('title').value.trim();
const content = document.getElementById('content').value.trim();
const type = document.querySelector('input[name="type"]:checked').value;
const tagsInput = document.getElementById('tags').value.trim();
const tags = tagsInput ? tagsInput.split(',').map(t => t.trim()).filter(t => t) : [];
if (!title || title.length < 5) {
showError('标题至少5个字符');
return;
}
if (!content || content.length < 10) {
showError('内容至少10个字符');
return;
}
try {
const res = await fetch('/api/posts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title, content, type, tags })
});
const data = await res.json();
if (data.success) {
window.location.href = `/post/${data.post_id}`;
} else {
showError(data.error || '发布失败');
}
} catch (err) {
showError('网络错误,请重试');
}
});
function saveDraft() {
const draft = {
title: document.getElementById('title').value,
content: document.getElementById('content').value,
type: document.querySelector('input[name="type"]:checked').value,
tags: document.getElementById('tags').value
};
localStorage.setItem('post_draft', JSON.stringify(draft));
alert('草稿已保存');
}
// 恢复草稿
const savedDraft = localStorage.getItem('post_draft');
if (savedDraft) {
const draft = JSON.parse(savedDraft);
if (draft.title) document.getElementById('title').value = draft.title;
if (draft.content) document.getElementById('content').value = draft.content;
if (draft.type) document.querySelector(`input[value="${draft.type}"]`).checked = true;
if (draft.tags) document.getElementById('tags').value = draft.tags;
}
function showError(msg) {
const el = document.getElementById('errorMsg');
el.textContent = msg;
el.classList.remove('hidden');
}
</script>
</body>
</html>