update pay ui
This commit is contained in:
167
app_vx.py
167
app_vx.py
@@ -1433,6 +1433,25 @@ class Comment(db.Model):
|
||||
replies = db.relationship('Comment', backref=db.backref('parent', remote_side=[id]))
|
||||
|
||||
|
||||
class Feedback(db.Model):
|
||||
"""用户反馈"""
|
||||
__tablename__ = 'user_feedback'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) # 可匿名反馈
|
||||
feedback_type = db.Column(db.String(50), default='general') # 反馈类型: general/bug/suggestion/complaint
|
||||
title = db.Column(db.String(200)) # 反馈标题
|
||||
content = db.Column(db.Text, nullable=False) # 反馈内容
|
||||
contact = db.Column(db.String(100)) # 联系方式(可选)
|
||||
images = db.Column(db.JSON) # 附带图片URL列表
|
||||
status = db.Column(db.String(20), default='pending') # pending/processing/resolved/closed
|
||||
admin_reply = db.Column(db.Text) # 管理员回复
|
||||
created_at = db.Column(db.DateTime, default=beijing_now)
|
||||
updated_at = db.Column(db.DateTime, default=beijing_now, onupdate=beijing_now)
|
||||
|
||||
user = db.relationship('User', backref='feedbacks')
|
||||
|
||||
|
||||
class StockBasicInfo(db.Model):
|
||||
__tablename__ = 'ea_stocklist'
|
||||
|
||||
@@ -4300,7 +4319,19 @@ def api_bindphone_wechat():
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
# 4. 检查手机号是否已被其他用户绑定
|
||||
# 4. 检查当前用户是否已绑定此手机号
|
||||
if user.phone == phone_number and user.phone_confirmed:
|
||||
# 已经绑定过了,直接返回成功
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'message': '手机号已绑定',
|
||||
'data': {
|
||||
'phone': phone_number,
|
||||
'bindcd': True
|
||||
}
|
||||
})
|
||||
|
||||
# 5. 检查手机号是否已被其他用户绑定(只查确认绑定的)
|
||||
existing_user = User.query.filter(
|
||||
User.phone == phone_number,
|
||||
User.phone_confirmed == True,
|
||||
@@ -4308,13 +4339,14 @@ def api_bindphone_wechat():
|
||||
).first()
|
||||
|
||||
if existing_user:
|
||||
logger.warning(f"手机号 {phone_number[:3]}****{phone_number[-4:]} 已被用户 {existing_user.id} 绑定,当前用户 {user.id} 尝试绑定失败")
|
||||
return jsonify({
|
||||
'code': 400,
|
||||
'message': '该手机号已被其他账号绑定',
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
# 5. 更新用户手机号
|
||||
# 6. 更新用户手机号
|
||||
user.phone = phone_number
|
||||
user.phone_confirmed = True
|
||||
user.phone_confirm_time = beijing_now()
|
||||
@@ -5752,11 +5784,15 @@ def parse_best_matches(best_matches_value):
|
||||
for item in data:
|
||||
if isinstance(item, dict):
|
||||
# 新结构:包含研报信息的字典
|
||||
# 将相关度转为整数百分比 (0.928 -> 93)
|
||||
raw_score = item.get('best_report_match_ratio', 0)
|
||||
int_score = int(round(raw_score * 100)) if raw_score and raw_score <= 1 else int(round(raw_score)) if raw_score else 0
|
||||
|
||||
stock_info = {
|
||||
'code': item.get('stock_code', ''),
|
||||
'name': item.get('company_name', ''),
|
||||
'description': item.get('original_description', ''),
|
||||
'score': item.get('best_report_match_ratio', 0),
|
||||
'score': int_score,
|
||||
# 研报引用信息
|
||||
'report': {
|
||||
'title': item.get('best_report_title', ''),
|
||||
@@ -6010,11 +6046,14 @@ def api_calendar_events():
|
||||
if stock_data:
|
||||
for stock_info in stock_data:
|
||||
if isinstance(stock_info, list) and len(stock_info) >= 2:
|
||||
# 将相关度转为整数百分比
|
||||
raw_score = stock_info[3] if len(stock_info) > 3 else 0
|
||||
int_score = int(round(raw_score * 100)) if raw_score and raw_score <= 1 else int(round(raw_score)) if raw_score else 0
|
||||
parsed_stocks.append({
|
||||
'code': stock_info[0],
|
||||
'name': stock_info[1],
|
||||
'description': stock_info[2] if len(stock_info) > 2 else '',
|
||||
'score': stock_info[3] if len(stock_info) > 3 else 0,
|
||||
'score': int_score,
|
||||
'report': None
|
||||
})
|
||||
except Exception as e:
|
||||
@@ -6741,12 +6780,16 @@ def api_user_profile():
|
||||
|
||||
# 总评论数(发出的评论 + 收到的评论和回复)
|
||||
total_comments = comments_made + comments_received + replies_received
|
||||
# 判断手机号绑定状态
|
||||
phone_bindcd = bool(user.phone and user.phone_confirmed)
|
||||
|
||||
profile_data = {
|
||||
'basic_info': {
|
||||
'user_id': user.id,
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'phone': user.phone,
|
||||
'phone': user.phone if phone_bindcd else None,
|
||||
'phone_bindcd': phone_bindcd,
|
||||
'nickname': user.nickname,
|
||||
'avatar_url': get_full_avatar_url(user.avatar_url), # 修改这里
|
||||
'bio': user.bio,
|
||||
@@ -6809,6 +6852,116 @@ def api_user_profile():
|
||||
}), 500
|
||||
|
||||
|
||||
@app.route('/api/user/feedback', methods=['POST'])
|
||||
@token_required
|
||||
def api_user_feedback():
|
||||
"""用户反馈接口"""
|
||||
try:
|
||||
user = request.user
|
||||
|
||||
# 获取请求数据(兼容多种格式)
|
||||
data = request.get_json(force=True, silent=True)
|
||||
if not data:
|
||||
data = request.form.to_dict()
|
||||
|
||||
content = data.get('content', '').strip()
|
||||
if not content:
|
||||
return jsonify({
|
||||
'code': 400,
|
||||
'message': '反馈内容不能为空',
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
feedback_type = data.get('type', 'general')
|
||||
title = data.get('title', '').strip()
|
||||
contact = data.get('contact', '').strip()
|
||||
images = data.get('images', [])
|
||||
|
||||
# 确保images是列表
|
||||
if isinstance(images, str):
|
||||
images = [images] if images else []
|
||||
|
||||
# 创建反馈记录
|
||||
feedback = Feedback(
|
||||
user_id=user.id,
|
||||
feedback_type=feedback_type,
|
||||
title=title if title else None,
|
||||
content=content,
|
||||
contact=contact if contact else user.phone or user.email,
|
||||
images=images if images else None,
|
||||
status='pending'
|
||||
)
|
||||
|
||||
db.session.add(feedback)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'message': '反馈提交成功,感谢您的宝贵意见!',
|
||||
'data': {
|
||||
'feedback_id': feedback.id,
|
||||
'status': feedback.status,
|
||||
'created_at': feedback.created_at.isoformat() if feedback.created_at else None
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({
|
||||
'code': 500,
|
||||
'message': f'反馈提交失败: {str(e)}',
|
||||
'data': None
|
||||
}), 500
|
||||
|
||||
|
||||
@app.route('/api/user/feedback', methods=['GET'])
|
||||
@token_required
|
||||
def api_user_feedback_list():
|
||||
"""获取用户反馈列表"""
|
||||
try:
|
||||
user = request.user
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 10, type=int)
|
||||
|
||||
feedbacks = Feedback.query.filter_by(user_id=user.id) \
|
||||
.order_by(Feedback.created_at.desc()) \
|
||||
.paginate(page=page, per_page=per_page, error_out=False)
|
||||
|
||||
feedback_list = []
|
||||
for fb in feedbacks.items:
|
||||
feedback_list.append({
|
||||
'id': fb.id,
|
||||
'type': fb.feedback_type,
|
||||
'title': fb.title,
|
||||
'content': fb.content,
|
||||
'status': fb.status,
|
||||
'admin_reply': fb.admin_reply,
|
||||
'created_at': fb.created_at.isoformat() if fb.created_at else None,
|
||||
'updated_at': fb.updated_at.isoformat() if fb.updated_at else None
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'message': 'success',
|
||||
'data': {
|
||||
'feedbacks': feedback_list,
|
||||
'pagination': {
|
||||
'page': page,
|
||||
'per_page': per_page,
|
||||
'total': feedbacks.total,
|
||||
'pages': feedbacks.pages
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'code': 500,
|
||||
'message': str(e),
|
||||
'data': None
|
||||
}), 500
|
||||
|
||||
|
||||
# 在文件开头添加缓存变量
|
||||
_agreements_cache = {}
|
||||
_cache_loaded = False
|
||||
@@ -7262,8 +7415,8 @@ if __name__ == '__main__':
|
||||
# SSL 配置
|
||||
ssl_context = None
|
||||
if not args.no_ssl:
|
||||
cert_file = '/etc/letsencrypt/live/api.valuefrontier.cn/fullchain.pem'
|
||||
key_file = '/etc/letsencrypt/live/api.valuefrontier.cn/privkey.pem'
|
||||
cert_file = '/etc/nginx/ssl/api.valuefrontier.cn/fullchain.pem'
|
||||
key_file = '/etc/nginx/ssl/api.valuefrontier.cn/privkey.pem'
|
||||
if os.path.exists(cert_file) and os.path.exists(key_file):
|
||||
ssl_context = (cert_file, key_file)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user