功能模块: - 仪表盘: 用户统计、帖子统计、帖子类型分布、热门标签、最新帖子 - 用户管理: 查看用户列表、删除用户 - 帖子管理: 查看/删除帖子、置顶功能、帖子详情预览 - 主题管理: 查看/删除主题、主题详情预览 端口: 19005
329 lines
9.5 KiB
Python
329 lines
9.5 KiB
Python
"""
|
|
技术论坛 - 后台管理系统
|
|
"""
|
|
|
|
from flask import Flask, render_template, jsonify, request
|
|
from flask_cors import CORS
|
|
import json
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
app = Flask(__name__)
|
|
CORS(app)
|
|
|
|
# 数据目录
|
|
DATA_DIR = Path(__file__).parent.parent / 'data'
|
|
USERS_FILE = DATA_DIR / 'users.json'
|
|
POSTS_FILE = DATA_DIR / 'posts.json'
|
|
TOPICS_FILE = DATA_DIR / 'topics.json'
|
|
|
|
def load_users():
|
|
if USERS_FILE.exists():
|
|
return json.loads(USERS_FILE.read_text(encoding='utf-8'))
|
|
return {}
|
|
|
|
def load_posts():
|
|
if POSTS_FILE.exists():
|
|
return json.loads(POSTS_FILE.read_text(encoding='utf-8'))
|
|
return {}
|
|
|
|
def load_topics():
|
|
if TOPICS_FILE.exists():
|
|
return json.loads(TOPICS_FILE.read_text(encoding='utf-8'))
|
|
return {}
|
|
|
|
def save_users(users):
|
|
USERS_FILE.write_text(json.dumps(users, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
|
|
def save_posts(posts):
|
|
POSTS_FILE.write_text(json.dumps(posts, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
|
|
def save_topics(topics):
|
|
TOPICS_FILE.write_text(json.dumps(topics, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
|
|
# ============ 页面路由 ============
|
|
|
|
@app.route('/')
|
|
def index():
|
|
return render_template('index.html')
|
|
|
|
@app.route('/users')
|
|
def users_page():
|
|
return render_template('users.html')
|
|
|
|
@app.route('/posts')
|
|
def posts_page():
|
|
return render_template('posts.html')
|
|
|
|
@app.route('/topics')
|
|
def topics_page():
|
|
return render_template('topics.html')
|
|
|
|
# ============ API路由 ============
|
|
|
|
@app.route('/api/stats')
|
|
def api_stats():
|
|
users = load_users()
|
|
posts = load_posts()
|
|
topics = load_topics()
|
|
|
|
# 统计
|
|
total_messages = 0
|
|
for post in posts.values():
|
|
total_messages += len(post.get('replies', []))
|
|
|
|
today = datetime.now().strftime('%Y-%m-%d')
|
|
today_posts = sum(1 for p in posts.values() if p.get('created_at', '').startswith(today))
|
|
today_users = sum(1 for u in users.values() if u.get('created_at', '').startswith(today))
|
|
|
|
# 帖子类型统计
|
|
discussion_count = sum(1 for p in posts.values() if p.get('type') == 'discussion')
|
|
share_count = sum(1 for p in posts.values() if p.get('type') == 'share')
|
|
|
|
return jsonify({
|
|
'users_count': len(users),
|
|
'posts_count': len(posts),
|
|
'topics_count': len(topics),
|
|
'messages_count': total_messages,
|
|
'today_posts': today_posts,
|
|
'today_users': today_users,
|
|
'discussion_count': discussion_count,
|
|
'share_count': share_count,
|
|
})
|
|
|
|
@app.route('/api/users')
|
|
def api_users():
|
|
users = load_users()
|
|
posts = load_posts()
|
|
|
|
user_list = []
|
|
for uid, user in users.items():
|
|
# 统计用户帖子和回复数
|
|
posts_count = len(user.get('posts', []))
|
|
replies_count = 0
|
|
for post in posts.values():
|
|
for reply in post.get('replies', []):
|
|
if reply.get('author_id') == uid:
|
|
replies_count += 1
|
|
|
|
user_list.append({
|
|
'id': uid,
|
|
'username': user.get('username', ''),
|
|
'email': user.get('email', ''),
|
|
'phone': user.get('phone', ''),
|
|
'posts_count': posts_count,
|
|
'replies_count': replies_count,
|
|
'created_at': user.get('created_at', ''),
|
|
})
|
|
|
|
user_list.sort(key=lambda x: x['created_at'], reverse=True)
|
|
return jsonify(user_list)
|
|
|
|
@app.route('/api/users/<user_id>', methods=['DELETE'])
|
|
def api_delete_user(user_id):
|
|
users = load_users()
|
|
posts = load_posts()
|
|
topics = load_topics()
|
|
|
|
if user_id not in users:
|
|
return jsonify({'error': '用户不存在'}), 404
|
|
|
|
# 删除用户的帖子
|
|
for post_id in users[user_id].get('posts', []):
|
|
if post_id in posts:
|
|
del posts[post_id]
|
|
|
|
# 从主题关注中移除
|
|
for topic in topics.values():
|
|
if user_id in topic.get('followers', []):
|
|
topic['followers'].remove(user_id)
|
|
|
|
# 删除用户
|
|
del users[user_id]
|
|
|
|
save_users(users)
|
|
save_posts(posts)
|
|
save_topics(topics)
|
|
|
|
return jsonify({'success': True})
|
|
|
|
@app.route('/api/posts')
|
|
def api_posts():
|
|
posts = load_posts()
|
|
users = load_users()
|
|
|
|
post_type = request.args.get('type')
|
|
|
|
post_list = []
|
|
for pid, post in posts.items():
|
|
if post_type and post['type'] != post_type:
|
|
continue
|
|
|
|
author = users.get(post['author_id'], {})
|
|
post_list.append({
|
|
'id': pid,
|
|
'title': post['title'],
|
|
'type': post['type'],
|
|
'author': author.get('username', '未知'),
|
|
'author_id': post['author_id'],
|
|
'likes': len(post.get('likes', [])),
|
|
'replies': len(post.get('replies', [])),
|
|
'views': post.get('views', 0),
|
|
'is_pinned': post.get('is_pinned', False),
|
|
'created_at': post['created_at'],
|
|
})
|
|
|
|
post_list.sort(key=lambda x: x['created_at'], reverse=True)
|
|
return jsonify(post_list)
|
|
|
|
@app.route('/api/posts/<post_id>')
|
|
def api_post_detail(post_id):
|
|
posts = load_posts()
|
|
users = load_users()
|
|
|
|
post = posts.get(post_id)
|
|
if not post:
|
|
return jsonify({'error': '帖子不存在'}), 404
|
|
|
|
author = users.get(post['author_id'], {})
|
|
|
|
# 获取回复
|
|
replies = []
|
|
for reply in post.get('replies', []):
|
|
reply_author = users.get(reply['author_id'], {})
|
|
replies.append({
|
|
'id': reply['id'],
|
|
'content': reply['content'][:100] + '...' if len(reply['content']) > 100 else reply['content'],
|
|
'author': reply_author.get('username', '未知'),
|
|
'likes': len(reply.get('likes', [])),
|
|
'created_at': reply['created_at'],
|
|
})
|
|
|
|
return jsonify({
|
|
'id': post_id,
|
|
'title': post['title'],
|
|
'content': post['content'],
|
|
'type': post['type'],
|
|
'author': author.get('username', '未知'),
|
|
'tags': post.get('tags', []),
|
|
'likes': len(post.get('likes', [])),
|
|
'replies': replies,
|
|
'views': post.get('views', 0),
|
|
'is_pinned': post.get('is_pinned', False),
|
|
'created_at': post['created_at'],
|
|
})
|
|
|
|
@app.route('/api/posts/<post_id>', methods=['DELETE'])
|
|
def api_delete_post(post_id):
|
|
posts = load_posts()
|
|
users = load_users()
|
|
|
|
if post_id not in posts:
|
|
return jsonify({'error': '帖子不存在'}), 404
|
|
|
|
author_id = posts[post_id].get('author_id')
|
|
|
|
del posts[post_id]
|
|
|
|
# 从用户列表中移除
|
|
if author_id and author_id in users:
|
|
if post_id in users[author_id].get('posts', []):
|
|
users[author_id]['posts'].remove(post_id)
|
|
|
|
save_posts(posts)
|
|
save_users(users)
|
|
|
|
return jsonify({'success': True})
|
|
|
|
@app.route('/api/posts/<post_id>/pin', methods=['POST'])
|
|
def api_pin_post(post_id):
|
|
posts = load_posts()
|
|
|
|
if post_id not in posts:
|
|
return jsonify({'error': '帖子不存在'}), 404
|
|
|
|
posts[post_id]['is_pinned'] = not posts[post_id].get('is_pinned', False)
|
|
save_posts(posts)
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'is_pinned': posts[post_id]['is_pinned']
|
|
})
|
|
|
|
@app.route('/api/topics')
|
|
def api_topics():
|
|
topics = load_topics()
|
|
users = load_users()
|
|
|
|
topic_list = []
|
|
for tid, topic in topics.items():
|
|
author = users.get(topic['author_id'], {})
|
|
topic_list.append({
|
|
'id': tid,
|
|
'name': topic['name'],
|
|
'icon': topic.get('icon', '🔧'),
|
|
'author': author.get('username', '未知'),
|
|
'sub_topics_count': len(topic.get('sub_topics', [])),
|
|
'questions_count': len(topic.get('questions', [])),
|
|
'followers_count': len(topic.get('followers', [])),
|
|
'created_at': topic['created_at'],
|
|
})
|
|
|
|
topic_list.sort(key=lambda x: x['followers_count'], reverse=True)
|
|
return jsonify(topic_list)
|
|
|
|
@app.route('/api/topics/<topic_id>')
|
|
def api_topic_detail(topic_id):
|
|
topics = load_topics()
|
|
users = load_users()
|
|
|
|
topic = topics.get(topic_id)
|
|
if not topic:
|
|
return jsonify({'error': '主题不存在'}), 404
|
|
|
|
author = users.get(topic['author_id'], {})
|
|
|
|
return jsonify({
|
|
'id': topic_id,
|
|
'name': topic['name'],
|
|
'description': topic.get('description', ''),
|
|
'icon': topic.get('icon', '🔧'),
|
|
'author': author.get('username', '未知'),
|
|
'sub_topics': topic.get('sub_topics', []),
|
|
'questions': topic.get('questions', []),
|
|
'followers_count': len(topic.get('followers', [])),
|
|
'created_at': topic['created_at'],
|
|
})
|
|
|
|
@app.route('/api/topics/<topic_id>', methods=['DELETE'])
|
|
def api_delete_topic(topic_id):
|
|
topics = load_topics()
|
|
|
|
if topic_id not in topics:
|
|
return jsonify({'error': '主题不存在'}), 404
|
|
|
|
del topics[topic_id]
|
|
save_topics(topics)
|
|
|
|
return jsonify({'success': True})
|
|
|
|
@app.route('/api/tags')
|
|
def api_tags():
|
|
posts = load_posts()
|
|
|
|
tag_counts = {}
|
|
for post in posts.values():
|
|
for tag in post.get('tags', []):
|
|
tag_counts[tag] = tag_counts.get(tag, 0) + 1
|
|
|
|
tags = sorted(tag_counts.items(), key=lambda x: x[1], reverse=True)
|
|
return jsonify([{'name': t[0], 'count': t[1]} for t in tags[:20]])
|
|
|
|
if __name__ == '__main__':
|
|
print("=" * 50)
|
|
print("技术论坛 - 后台管理系统")
|
|
print("=" * 50)
|
|
print(f"访问地址: http://localhost:19005")
|
|
print("=" * 50)
|
|
|
|
app.run(host='0.0.0.0', port=19005, debug=True) |