前端封装是否点赞的api
Change-Id: I69e915f6c9aa1a8f721ff38a4df58dd8fdfc6e0a
diff --git a/Merge/back_wzy/routes/posts.py b/Merge/back_wzy/routes/posts.py
index 105900c..4d8be1e 100644
--- a/Merge/back_wzy/routes/posts.py
+++ b/Merge/back_wzy/routes/posts.py
@@ -1,10 +1,10 @@
# routes/posts.py
from flask import Blueprint, request, jsonify, abort
-from extensions import db
-from models.post import Post
+from extensions import db
+from models.post import Post
from models.behavior import Behavior
-from utils.Fpost import Fpost
+from utils.Fpost import Fpost
import json
posts_bp = Blueprint('posts', __name__)
@@ -12,25 +12,22 @@
@posts_bp.route('', methods=['POST'])
def create_post():
try:
- # 获取文本字段
- user_id = request.form.get('user_id')
- title = request.form.get('title')
- content = request.form.get('content')
- status = request.form.get('status', 'published')
- topic_id = request.form.get('topic_id')
+ user_id = request.form.get('user_id')
+ title = request.form.get('title')
+ content = request.form.get('content')
+ status = request.form.get('status', 'published')
+ topic_id = request.form.get('topic_id')
media_count = int(request.form.get('media_count', 0))
-
+
if not user_id or not title or not content:
return jsonify({'error': '缺少必要字段'}), 400
-
- # 获取上传的文件
+
files = []
for i in range(media_count):
- file_key = f'media_{i}'
- if file_key in request.files:
- files.append(request.files[file_key])
-
- # 使用 Fpost 创建帖子
+ key = f'media_{i}'
+ if key in request.files:
+ files.append(request.files[key])
+
fpost = Fpost(db.session)
new_post = fpost.create_post_with_files(
user_id=int(user_id),
@@ -40,18 +37,18 @@
status=status,
files=files
)
-
+
return jsonify({'id': new_post.id}), 201
-
+
except Exception as e:
return jsonify({'error': str(e)}), 500
+
@posts_bp.route('', methods=['GET'])
def list_posts():
"""
- 获取帖子列表,支持:
- - GET /posts 返回所有已发布帖子
- - GET /posts?user_id=123 返回指定用户 user_id 的所有帖子
+ GET /posts -> 全部已发布帖子
+ GET /posts?user_id=xx -> 指定用户的所有帖子
"""
user_id = request.args.get('user_id', type=int)
query = Post.query
@@ -61,94 +58,90 @@
query = query.filter_by(status='published')
posts = query.all()
-
return jsonify([{
- 'id': p.id,
- 'title': p.title,
- 'status': p.status, # 新增 status 字段
- 'heat': p.heat,
- 'created_at': p.created_at.isoformat()
+ 'id' : p.id,
+ 'title' : p.title,
+ 'status' : p.status,
+ 'heat' : p.heat,
+ 'created_at' : p.created_at.isoformat()
} for p in posts])
+
@posts_bp.route('/<int:post_id>', methods=['GET'])
def get_post(post_id):
post = Post.query.get_or_404(post_id)
return jsonify({
- 'id': post.id,
- 'user_id': post.user_id,
- 'topic_id': post.topic_id,
- 'title': post.title,
- 'content': post.content,
- 'media_urls': post.media_urls,
- 'status': post.status,
- 'heat': post.heat,
- 'created_at': post.created_at.isoformat(),
- 'updated_at': post.updated_at.isoformat()
+ 'id' : post.id,
+ 'user_id' : post.user_id,
+ 'topic_id' : post.topic_id,
+ 'title' : post.title,
+ 'content' : post.content,
+ 'media_urls' : post.media_urls,
+ 'status' : post.status,
+ 'heat' : post.heat,
+ 'created_at' : post.created_at.isoformat(),
+ 'updated_at' : post.updated_at.isoformat()
})
+
@posts_bp.route('/<int:post_id>', methods=['PUT'])
def update_post(post_id):
"""
- 修改帖子字段(可选字段:title, content, topic_id, media_urls, status)
- 支持FormData和JSON两种格式
+ 支持 FormData 和 JSON 两种格式更新:
+ - multipart/form-data 时可上传新文件并保留 existing_media_urls
+ - application/json 时只修改字段
"""
try:
fpost = Fpost(db.session)
-
- # 检查是否是FormData请求
+
if request.content_type and 'multipart/form-data' in request.content_type:
- # FormData请求
- title = request.form.get('title')
- content = request.form.get('content')
- status = request.form.get('status')
+ title = request.form.get('title')
+ content = request.form.get('content')
+ status = request.form.get('status')
topic_id = request.form.get('topic_id')
- media_count = int(request.form.get('media_count', 0))
- existing_media_urls_str = request.form.get('existing_media_urls')
-
- # 解析现有媒体URLs
+ count = int(request.form.get('media_count', 0))
+ existing = request.form.get('existing_media_urls')
+
existing_media_urls = None
- if existing_media_urls_str:
+ if existing:
try:
- existing_media_urls = json.loads(existing_media_urls_str)
+ existing_media_urls = json.loads(existing)
except:
existing_media_urls = None
-
- # 获取新上传的文件
+
files = []
- for i in range(media_count):
- file_key = f'media_{i}'
- if file_key in request.files:
- files.append(request.files[file_key])
-
- # 更新帖子
- updated_post = fpost.update_post_with_files(
+ for i in range(count):
+ key = f'media_{i}'
+ if key in request.files:
+ files.append(request.files[key])
+
+ updated = fpost.update_post_with_files(
post_id=post_id,
title=title,
content=content,
topic_id=int(topic_id) if topic_id else None,
status=status,
- files=files if files else None,
+ files=files or None,
existing_media_urls=existing_media_urls
)
-
else:
- # JSON请求(保持原有逻辑)
post = Post.query.get_or_404(post_id)
data = request.get_json() or {}
- for key in ('title', 'content', 'topic_id', 'media_urls', 'status'):
- if key in data:
- setattr(post, key, data[key])
+ for field in ('title','content','topic_id','media_urls','status'):
+ if field in data:
+ setattr(post, field, data[field])
db.session.commit()
- updated_post = post
-
- if not updated_post:
+ updated = post
+
+ if not updated:
return jsonify({'error': '帖子不存在'}), 404
-
+
return '', 204
-
+
except Exception as e:
return jsonify({'error': str(e)}), 500
+
@posts_bp.route('/<int:post_id>', methods=['DELETE'])
def delete_post(post_id):
post = Post.query.get_or_404(post_id)
@@ -156,89 +149,14 @@
db.session.commit()
return '', 204
-@posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
-def post_action(post_id, action):
- """
- 支持的 action: like, favorite, view, share
- 对于 like 和 favorite,保证每个用户每帖只做一次。
- """
- if action not in ('like', 'favorite', 'view', 'share'):
- abort(400, 'Invalid action')
- data = request.get_json() or {}
- user_id = data.get('user_id')
- if not user_id:
- abort(400, 'user_id required')
-
- # 对 like/favorite 做去重检查
- if action in ('like', 'favorite'):
- exists = Behavior.query.filter_by(
- user_id=user_id,
- post_id=post_id,
- type=action
- ).first()
- if exists:
- return jsonify({'error': f'already {action}d'}), 400
-
- # 创建行为记录
- beh = Behavior(user_id=user_id, post_id=post_id, type=action)
- db.session.add(beh)
-
- # 更新热度
- post = Post.query.get_or_404(post_id)
- post.heat += 1
-
- db.session.commit()
- return '', 201
-
-@posts_bp.route('/<int:post_id>/like', methods=['DELETE'])
-def unlike(post_id):
- user_id = request.get_json(silent=True) and request.get_json().get('user_id')
- if not user_id:
- abort(400, 'user_id required')
- # 查找已有的 like 行为
- beh = Behavior.query.filter_by(
- user_id=user_id,
- post_id=post_id,
- type='like'
- ).first()
- if not beh:
- return jsonify({'error': 'not liked yet'}), 400
-
- db.session.delete(beh)
- # 更新热度,确保不降到负数
- post = Post.query.get_or_404(post_id)
- post.heat = max(post.heat - 1, 0)
- db.session.commit()
- return '', 204
-
-@posts_bp.route('/<int:post_id>/favorite', methods=['DELETE'])
-def unfavorite(post_id):
- user_id = request.get_json(silent=True) and request.get_json().get('user_id')
- if not user_id:
- abort(400, 'user_id required')
- # 查找已有的 favorite 行为
- beh = Behavior.query.filter_by(
- user_id=user_id,
- post_id=post_id,
- type='favorite'
- ).first()
- if not beh:
- return jsonify({'error': 'not favorited yet'}), 400
-
- db.session.delete(beh)
- # 更新热度
- post = Post.query.get_or_404(post_id)
- post.heat = max(post.heat - 1, 0)
- db.session.commit()
- return '', 204
+# —— 显式的 like/favorite 删除和查询路由,放在泛用 action 路由之前 —— #
@posts_bp.route('/<int:post_id>/like', methods=['GET'])
def has_liked(post_id):
"""
- 检查指定 user_id 是否对 post_id 点过赞。
- GET /posts/<post_id>/like?user_id=123
- 返回 { "liked": true } 或 { "liked": false }
+ GET /posts/<post_id>/like?user_id=xx
+ 返回 { "liked": true/false }
"""
user_id = request.args.get('user_id', type=int)
if not user_id:
@@ -251,3 +169,85 @@
).first() is not None
return jsonify({'liked': exists}), 200
+
+
+@posts_bp.route('/<int:post_id>/like', methods=['DELETE'])
+def unlike(post_id):
+ data = request.get_json(silent=True) or {}
+ user_id = data.get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+
+ beh = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type='like'
+ ).first()
+ if not beh:
+ return jsonify({'error': 'not liked yet'}), 400
+
+ db.session.delete(beh)
+ post = Post.query.get_or_404(post_id)
+ post.heat = max(post.heat - 1, 0)
+ db.session.commit()
+ return '', 204
+
+
+@posts_bp.route('/<int:post_id>/favorite', methods=['DELETE'])
+def unfavorite(post_id):
+ data = request.get_json(silent=True) or {}
+ user_id = data.get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+
+ beh = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type='favorite'
+ ).first()
+ if not beh:
+ return jsonify({'error': 'not favorited yet'}), 400
+
+ db.session.delete(beh)
+ post = Post.query.get_or_404(post_id)
+ post.heat = max(post.heat - 1, 0)
+ db.session.commit()
+ return '', 204
+
+
+# —— 泛用 action 路由,仅处理 POST /posts/<id>/(like|favorite|view|share) —— #
+
+@posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
+def post_action(post_id, action):
+ """
+ 支持 action: like, favorite, view, share,
+ 对 like/favorite 做幂等去重检查。
+ """
+ if action not in ('like','favorite','view','share'):
+ abort(400, 'Invalid action')
+
+ data = request.get_json() or {}
+ user_id = data.get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+
+ # 幂等检查
+ if action in ('like','favorite'):
+ exists = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type=action
+ ).first()
+ if exists:
+ return jsonify({'error': f'already {action}d'}), 400
+
+ # 记录行为
+ beh = Behavior(user_id=user_id, post_id=post_id, type=action)
+ db.session.add(beh)
+
+ # 更新热度
+ post = Post.query.get_or_404(post_id)
+ post.heat += 1
+
+ db.session.commit()
+ return '', 201
diff --git a/Merge/front/src/api/search_jwlll.js b/Merge/front/src/api/search_jwlll.js
index 01b743f..e18efa3 100644
--- a/Merge/front/src/api/search_jwlll.js
+++ b/Merge/front/src/api/search_jwlll.js
@@ -79,6 +79,17 @@
})
},
+ // 查看是否点赞
+ hasLiked: async (postId, userId) => {
+ const res = await request(
+ `${WZY_BASE_URL}/posts/${postId}/like?user_id=${userId}`,
+ {
+ method: 'GET'
+ }
+ )
+ return res.liked
+ },
+
// 添加评论
addComment: async (postId, userId, content) => {
return await request(`${WZY_BASE_URL}/posts/${postId}/comments`, {
diff --git a/WZY/xhs_server/__pycache__/config.cpython-312.pyc b/WZY/xhs_server/__pycache__/config.cpython-312.pyc
index bd10f35..189ac81 100644
--- a/WZY/xhs_server/__pycache__/config.cpython-312.pyc
+++ b/WZY/xhs_server/__pycache__/config.cpython-312.pyc
Binary files differ
diff --git a/WZY/xhs_server/routes/__pycache__/posts.cpython-312.pyc b/WZY/xhs_server/routes/__pycache__/posts.cpython-312.pyc
index f301c84..2e58010 100644
--- a/WZY/xhs_server/routes/__pycache__/posts.cpython-312.pyc
+++ b/WZY/xhs_server/routes/__pycache__/posts.cpython-312.pyc
Binary files differ
diff --git a/WZY/xhs_server/routes/posts.py b/WZY/xhs_server/routes/posts.py
index cb7e266..d4994c1 100644
--- a/WZY/xhs_server/routes/posts.py
+++ b/WZY/xhs_server/routes/posts.py
@@ -1,26 +1,31 @@
# routes/posts.py
from flask import Blueprint, request, jsonify, abort
-from extensions import db
-from models.post import Post
+from extensions import db
+from models.post import Post
from models.behavior import Behavior
posts_bp = Blueprint('posts', __name__)
@posts_bp.route('', methods=['POST'])
def create_post():
+ """
+ POST /posts
+ 接收 application/json 格式:
+ { "user_id": ..., "title": ..., "content": ..., "topic_id": ..., "media_urls": [...], "status": ... }
+ """
data = request.get_json() or {}
post = Post(**data)
db.session.add(post)
db.session.commit()
return jsonify({'id': post.id}), 201
+
@posts_bp.route('', methods=['GET'])
def list_posts():
"""
- 获取帖子列表,支持:
- - GET /posts 返回所有已发布帖子
- - GET /posts?user_id=123 返回指定用户 user_id 的所有帖子
+ GET /posts → 返回所有已发布帖子
+ GET /posts?user_id=xx → 返回指定用户的所有帖子
"""
user_id = request.args.get('user_id', type=int)
query = Post.query
@@ -28,36 +33,43 @@
query = query.filter_by(user_id=user_id)
else:
query = query.filter_by(status='published')
- posts = query.all()
+ posts = query.all()
return jsonify([{
- 'id': p.id,
- 'title': p.title,
- 'heat': p.heat,
- 'status': p.status,
- 'created_at': p.created_at.isoformat()
+ 'id' : p.id,
+ 'title' : p.title,
+ 'status' : p.status,
+ 'heat' : p.heat,
+ 'created_at' : p.created_at.isoformat()
} for p in posts])
+
@posts_bp.route('/<int:post_id>', methods=['GET'])
def get_post(post_id):
+ """
+ GET /posts/<post_id>
+ """
post = Post.query.get_or_404(post_id)
return jsonify({
- 'id': post.id,
- 'user_id': post.user_id,
- 'topic_id': post.topic_id,
- 'title': post.title,
- 'content': post.content,
- 'media_urls': post.media_urls,
- 'status': post.status,
- 'heat': post.heat,
- 'created_at': post.created_at.isoformat(),
- 'updated_at': post.updated_at.isoformat()
+ 'id' : post.id,
+ 'user_id' : post.user_id,
+ 'topic_id' : post.topic_id,
+ 'title' : post.title,
+ 'content' : post.content,
+ 'media_urls' : post.media_urls,
+ 'status' : post.status,
+ 'heat' : post.heat,
+ 'created_at' : post.created_at.isoformat(),
+ 'updated_at' : post.updated_at.isoformat()
})
+
@posts_bp.route('/<int:post_id>', methods=['PUT'])
def update_post(post_id):
"""
- 修改帖子字段(可选字段:title, content, topic_id, media_urls, status)
+ PUT /posts/<post_id>
+ 接收 application/json 格式,可选字段:
+ title, content, topic_id, media_urls, status
"""
post = Post.query.get_or_404(post_id)
data = request.get_json() or {}
@@ -67,28 +79,104 @@
db.session.commit()
return '', 204
+
@posts_bp.route('/<int:post_id>', methods=['DELETE'])
def delete_post(post_id):
+ """
+ DELETE /posts/<post_id>
+ """
post = Post.query.get_or_404(post_id)
db.session.delete(post)
db.session.commit()
return '', 204
-@posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
-def post_action(post_id, action):
- """
- 支持的 action: like, favorite, view, share
- 对于 like 和 favorite,保证每个用户每帖只做一次。
- """
- if action not in ('like', 'favorite', 'view', 'share'):
- abort(400, 'Invalid action')
- data = request.get_json() or {}
+@posts_bp.route('/<int:post_id>/like', methods=['GET'])
+def has_liked(post_id):
+ """
+ GET /posts/<post_id>/like?user_id=xx
+ 返回 { "liked": true/false }
+ """
+ user_id = request.args.get('user_id', type=int)
+ if not user_id:
+ abort(400, 'user_id required')
+
+ exists = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type='like'
+ ).first() is not None
+
+ return jsonify({'liked': exists}), 200
+
+
+@posts_bp.route('/<int:post_id>/like', methods=['DELETE'])
+def unlike(post_id):
+ """
+ DELETE /posts/<post_id>/like
+ body: { "user_id": xx }
+ """
+ data = request.get_json(silent=True) or {}
user_id = data.get('user_id')
if not user_id:
abort(400, 'user_id required')
- # 对 like/favorite 做去重检查
+ beh = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type='like'
+ ).first()
+ if not beh:
+ return jsonify({'error': 'not liked yet'}), 400
+
+ db.session.delete(beh)
+ post = Post.query.get_or_404(post_id)
+ post.heat = max(post.heat - 1, 0)
+ db.session.commit()
+ return '', 204
+
+
+@posts_bp.route('/<int:post_id>/favorite', methods=['DELETE'])
+def unfavorite(post_id):
+ """
+ DELETE /posts/<post_id>/favorite
+ body: { "user_id": xx }
+ """
+ data = request.get_json(silent=True) or {}
+ user_id = data.get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+
+ beh = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type='favorite'
+ ).first()
+ if not beh:
+ return jsonify({'error': 'not favorited yet'}), 400
+
+ db.session.delete(beh)
+ post = Post.query.get_or_404(post_id)
+ post.heat = max(post.heat - 1, 0)
+ db.session.commit()
+ return '', 204
+
+
+@posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
+def post_action(post_id, action):
+ """
+ POST /posts/<post_id>/<action>
+ 支持 action: like, favorite, view, share
+ """
+ if action not in ('like', 'favorite', 'view', 'share'):
+ abort(400, 'Invalid action')
+
+ data = request.get_json() or {}
+ user_id = data.get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+
+ # 幂等检查
if action in ('like', 'favorite'):
exists = Behavior.query.filter_by(
user_id=user_id,
@@ -108,64 +196,3 @@
db.session.commit()
return '', 201
-
-@posts_bp.route('/<int:post_id>/like', methods=['DELETE'])
-def unlike(post_id):
- user_id = request.get_json(silent=True) and request.get_json().get('user_id')
- if not user_id:
- abort(400, 'user_id required')
- # 查找已有的 like 行为
- beh = Behavior.query.filter_by(
- user_id=user_id,
- post_id=post_id,
- type='like'
- ).first()
- if not beh:
- return jsonify({'error': 'not liked yet'}), 400
-
- db.session.delete(beh)
- # 更新热度,确保不降到负数
- post = Post.query.get_or_404(post_id)
- post.heat = max(post.heat - 1, 0)
- db.session.commit()
- return '', 204
-
-@posts_bp.route('/<int:post_id>/favorite', methods=['DELETE'])
-def unfavorite(post_id):
- user_id = request.get_json(silent=True) and request.get_json().get('user_id')
- if not user_id:
- abort(400, 'user_id required')
- # 查找已有的 favorite 行为
- beh = Behavior.query.filter_by(
- user_id=user_id,
- post_id=post_id,
- type='favorite'
- ).first()
- if not beh:
- return jsonify({'error': 'not favorited yet'}), 400
-
- db.session.delete(beh)
- # 更新热度
- post = Post.query.get_or_404(post_id)
- post.heat = max(post.heat - 1, 0)
- db.session.commit()
- return '', 204
-
-@posts_bp.route('/<int:post_id>/like', methods=['GET'])
-def has_liked(post_id):
- """
- 检查指定 user_id 是否对 post_id 点过赞。
- GET /posts/<post_id>/like?user_id=123
- 返回 { "liked": true } 或 { "liked": false }
- """
- user_id = request.args.get('user_id', type=int)
- if not user_id:
- abort(400, 'user_id required')
-
- exists = Behavior.query.filter_by(
- user_id=user_id,
- post_id=post_id,
- type='like'
- ).first() is not None
-
- return jsonify({'liked': exists}), 200