0b37aa4a67
Signed-off-by: TIANHE <TIANHE@GMAIL.COM>
425 lines
14 KiB
Python
425 lines
14 KiB
Python
"""
|
|
Community APIs - 指标社区接口
|
|
|
|
提供指标市场、购买、评论等功能的 REST API。
|
|
"""
|
|
|
|
from flask import Blueprint, jsonify, request, g
|
|
|
|
from app.utils.auth import login_required
|
|
from app.utils.logger import get_logger
|
|
from app.services.community_service import get_community_service
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
community_bp = Blueprint("community", __name__)
|
|
|
|
|
|
# ==========================================
|
|
# 指标市场
|
|
# ==========================================
|
|
|
|
@community_bp.route("/indicators", methods=["GET"])
|
|
@login_required
|
|
def get_market_indicators():
|
|
"""
|
|
获取市场指标列表
|
|
|
|
Query params:
|
|
page: 页码 (default 1)
|
|
page_size: 每页数量 (default 12)
|
|
keyword: 搜索关键词
|
|
pricing_type: 'free' / 'paid' / 空(全部)
|
|
sort_by: 'newest' / 'hot' / 'price_asc' / 'price_desc' / 'rating'
|
|
"""
|
|
try:
|
|
page = int(request.args.get('page', 1))
|
|
page_size = int(request.args.get('page_size', 12))
|
|
keyword = request.args.get('keyword', '').strip()
|
|
pricing_type = request.args.get('pricing_type', '').strip() or None
|
|
sort_by = request.args.get('sort_by', 'newest').strip()
|
|
|
|
# 限制每页数量
|
|
page_size = min(max(page_size, 1), 50)
|
|
|
|
service = get_community_service()
|
|
result = service.get_market_indicators(
|
|
page=page,
|
|
page_size=page_size,
|
|
keyword=keyword if keyword else None,
|
|
pricing_type=pricing_type,
|
|
sort_by=sort_by,
|
|
user_id=g.user_id
|
|
)
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_market_indicators failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/indicators/<int:indicator_id>", methods=["GET"])
|
|
@login_required
|
|
def get_indicator_detail(indicator_id: int):
|
|
"""获取指标详情"""
|
|
try:
|
|
service = get_community_service()
|
|
result = service.get_indicator_detail(indicator_id, user_id=g.user_id)
|
|
|
|
if not result:
|
|
return jsonify({'code': 0, 'msg': 'indicator_not_found', 'data': None}), 404
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_indicator_detail failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
# ==========================================
|
|
# 购买功能
|
|
# ==========================================
|
|
|
|
@community_bp.route("/indicators/<int:indicator_id>/purchase", methods=["POST"])
|
|
@login_required
|
|
def purchase_indicator(indicator_id: int):
|
|
"""
|
|
购买指标
|
|
|
|
会自动:
|
|
1. 检查积分是否充足
|
|
2. 扣除买家积分,增加卖家积分
|
|
3. 创建购买记录
|
|
4. 复制指标到买家账户
|
|
"""
|
|
try:
|
|
service = get_community_service()
|
|
success, message, data = service.purchase_indicator(
|
|
buyer_id=g.user_id,
|
|
indicator_id=indicator_id
|
|
)
|
|
|
|
if success:
|
|
return jsonify({'code': 1, 'msg': message, 'data': data})
|
|
else:
|
|
return jsonify({'code': 0, 'msg': message, 'data': data}), 400
|
|
|
|
except Exception as e:
|
|
logger.error(f"purchase_indicator failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/my-purchases", methods=["GET"])
|
|
@login_required
|
|
def get_my_purchases():
|
|
"""获取我购买的指标列表"""
|
|
try:
|
|
page = int(request.args.get('page', 1))
|
|
page_size = int(request.args.get('page_size', 20))
|
|
page_size = min(max(page_size, 1), 50)
|
|
|
|
service = get_community_service()
|
|
result = service.get_my_purchases(
|
|
user_id=g.user_id,
|
|
page=page,
|
|
page_size=page_size
|
|
)
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_my_purchases failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
# ==========================================
|
|
# 评论功能
|
|
# ==========================================
|
|
|
|
@community_bp.route("/indicators/<int:indicator_id>/comments", methods=["GET"])
|
|
@login_required
|
|
def get_comments(indicator_id: int):
|
|
"""获取指标评论列表"""
|
|
try:
|
|
page = int(request.args.get('page', 1))
|
|
page_size = int(request.args.get('page_size', 20))
|
|
page_size = min(max(page_size, 1), 50)
|
|
|
|
service = get_community_service()
|
|
result = service.get_comments(
|
|
indicator_id=indicator_id,
|
|
page=page,
|
|
page_size=page_size
|
|
)
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_comments failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/indicators/<int:indicator_id>/comments", methods=["POST"])
|
|
@login_required
|
|
def add_comment(indicator_id: int):
|
|
"""
|
|
添加评论
|
|
|
|
Request body:
|
|
rating: 1-5 星评分
|
|
content: 评论内容(可选,最多500字)
|
|
|
|
注意:只有购买过的用户可以评论,且只能评论一次
|
|
"""
|
|
try:
|
|
data = request.get_json() or {}
|
|
rating = int(data.get('rating', 5))
|
|
content = (data.get('content') or '').strip()
|
|
|
|
service = get_community_service()
|
|
success, message, result = service.add_comment(
|
|
user_id=g.user_id,
|
|
indicator_id=indicator_id,
|
|
rating=rating,
|
|
content=content
|
|
)
|
|
|
|
if success:
|
|
return jsonify({'code': 1, 'msg': message, 'data': result})
|
|
else:
|
|
return jsonify({'code': 0, 'msg': message, 'data': result}), 400
|
|
|
|
except Exception as e:
|
|
logger.error(f"add_comment failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/indicators/<int:indicator_id>/comments/<int:comment_id>", methods=["PUT"])
|
|
@login_required
|
|
def update_comment(indicator_id: int, comment_id: int):
|
|
"""
|
|
更新评论(只能修改自己的评论)
|
|
|
|
Request body:
|
|
rating: 1-5 星评分
|
|
content: 评论内容(最多500字)
|
|
"""
|
|
try:
|
|
data = request.get_json() or {}
|
|
rating = int(data.get('rating', 5))
|
|
content = (data.get('content') or '').strip()
|
|
|
|
service = get_community_service()
|
|
success, message, result = service.update_comment(
|
|
user_id=g.user_id,
|
|
comment_id=comment_id,
|
|
indicator_id=indicator_id,
|
|
rating=rating,
|
|
content=content
|
|
)
|
|
|
|
if success:
|
|
return jsonify({'code': 1, 'msg': message, 'data': result})
|
|
else:
|
|
return jsonify({'code': 0, 'msg': message, 'data': result}), 400
|
|
|
|
except Exception as e:
|
|
logger.error(f"update_comment failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/indicators/<int:indicator_id>/my-comment", methods=["GET"])
|
|
@login_required
|
|
def get_my_comment(indicator_id: int):
|
|
"""获取当前用户对指定指标的评论(用于编辑)"""
|
|
try:
|
|
service = get_community_service()
|
|
result = service.get_user_comment(
|
|
user_id=g.user_id,
|
|
indicator_id=indicator_id
|
|
)
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_my_comment failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
# ==========================================
|
|
# 实盘表现
|
|
# ==========================================
|
|
|
|
@community_bp.route("/indicators/<int:indicator_id>/performance", methods=["GET"])
|
|
@login_required
|
|
def get_indicator_performance(indicator_id: int):
|
|
"""获取指标的实盘表现统计"""
|
|
try:
|
|
service = get_community_service()
|
|
result = service.get_indicator_performance(indicator_id)
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_indicator_performance failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
# ==========================================
|
|
# 管理员审核功能
|
|
# ==========================================
|
|
|
|
def _is_admin():
|
|
"""检查当前用户是否是管理员"""
|
|
role = getattr(g, 'user_role', None)
|
|
return role == 'admin'
|
|
|
|
|
|
@community_bp.route("/admin/pending-indicators", methods=["GET"])
|
|
@login_required
|
|
def get_pending_indicators():
|
|
"""
|
|
获取待审核的指标列表(管理员专用)
|
|
|
|
Query params:
|
|
page: 页码 (default 1)
|
|
page_size: 每页数量 (default 20)
|
|
review_status: 'pending' / 'approved' / 'rejected' / 'all'
|
|
"""
|
|
try:
|
|
if not _is_admin():
|
|
return jsonify({'code': 0, 'msg': 'admin_required', 'data': None}), 403
|
|
|
|
page = int(request.args.get('page', 1))
|
|
page_size = int(request.args.get('page_size', 20))
|
|
review_status = request.args.get('review_status', 'pending').strip() or 'pending'
|
|
page_size = min(max(page_size, 1), 100)
|
|
|
|
service = get_community_service()
|
|
result = service.get_pending_indicators(
|
|
page=page,
|
|
page_size=page_size,
|
|
review_status=review_status
|
|
)
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_pending_indicators failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/admin/review-stats", methods=["GET"])
|
|
@login_required
|
|
def get_review_stats():
|
|
"""获取审核统计数据(管理员专用)"""
|
|
try:
|
|
if not _is_admin():
|
|
return jsonify({'code': 0, 'msg': 'admin_required', 'data': None}), 403
|
|
|
|
service = get_community_service()
|
|
result = service.get_review_stats()
|
|
|
|
return jsonify({'code': 1, 'msg': 'success', 'data': result})
|
|
|
|
except Exception as e:
|
|
logger.error(f"get_review_stats failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/admin/indicators/<int:indicator_id>/review", methods=["POST"])
|
|
@login_required
|
|
def review_indicator(indicator_id: int):
|
|
"""
|
|
审核指标(管理员专用)
|
|
|
|
Request body:
|
|
action: 'approve' / 'reject'
|
|
note: 审核备注(可选)
|
|
"""
|
|
try:
|
|
if not _is_admin():
|
|
return jsonify({'code': 0, 'msg': 'admin_required', 'data': None}), 403
|
|
|
|
data = request.get_json() or {}
|
|
action = data.get('action', '').strip()
|
|
note = data.get('note', '').strip()
|
|
|
|
if action not in ('approve', 'reject'):
|
|
return jsonify({'code': 0, 'msg': 'invalid_action', 'data': None}), 400
|
|
|
|
service = get_community_service()
|
|
success, message = service.review_indicator(
|
|
admin_id=g.user_id,
|
|
indicator_id=indicator_id,
|
|
action=action,
|
|
note=note
|
|
)
|
|
|
|
if success:
|
|
return jsonify({'code': 1, 'msg': message, 'data': None})
|
|
else:
|
|
return jsonify({'code': 0, 'msg': message, 'data': None}), 400
|
|
|
|
except Exception as e:
|
|
logger.error(f"review_indicator failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/admin/indicators/<int:indicator_id>/unpublish", methods=["POST"])
|
|
@login_required
|
|
def unpublish_indicator(indicator_id: int):
|
|
"""
|
|
下架指标(管理员专用)
|
|
|
|
Request body:
|
|
note: 下架原因(可选)
|
|
"""
|
|
try:
|
|
if not _is_admin():
|
|
return jsonify({'code': 0, 'msg': 'admin_required', 'data': None}), 403
|
|
|
|
data = request.get_json() or {}
|
|
note = data.get('note', '').strip()
|
|
|
|
service = get_community_service()
|
|
success, message = service.unpublish_indicator(
|
|
admin_id=g.user_id,
|
|
indicator_id=indicator_id,
|
|
note=note
|
|
)
|
|
|
|
if success:
|
|
return jsonify({'code': 1, 'msg': message, 'data': None})
|
|
else:
|
|
return jsonify({'code': 0, 'msg': message, 'data': None}), 400
|
|
|
|
except Exception as e:
|
|
logger.error(f"unpublish_indicator failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
|
|
|
|
|
@community_bp.route("/admin/indicators/<int:indicator_id>", methods=["DELETE"])
|
|
@login_required
|
|
def admin_delete_indicator(indicator_id: int):
|
|
"""删除指标(管理员专用)"""
|
|
try:
|
|
if not _is_admin():
|
|
return jsonify({'code': 0, 'msg': 'admin_required', 'data': None}), 403
|
|
|
|
service = get_community_service()
|
|
success, message = service.admin_delete_indicator(
|
|
admin_id=g.user_id,
|
|
indicator_id=indicator_id
|
|
)
|
|
|
|
if success:
|
|
return jsonify({'code': 1, 'msg': message, 'data': None})
|
|
else:
|
|
return jsonify({'code': 0, 'msg': message, 'data': None}), 400
|
|
|
|
except Exception as e:
|
|
logger.error(f"admin_delete_indicator failed: {e}")
|
|
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|