2025-11-19 22:49:24 +08:00
|
|
|
|
from flask import request, jsonify, current_app
|
|
|
|
|
|
from app import db
|
|
|
|
|
|
from app.models import Product, License, Ticket, Version
|
|
|
|
|
|
from . import api_bp
|
|
|
|
|
|
from app.utils.logger import log_operation
|
2025-11-22 16:48:45 +08:00
|
|
|
|
from app.utils.cors_middleware import handle_preflight, cors_after
|
2025-11-19 22:49:24 +08:00
|
|
|
|
import re
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
# 注册请求和响应处理器
|
|
|
|
|
|
@api_bp.before_request
|
|
|
|
|
|
def before_request():
|
|
|
|
|
|
"""在每个请求前处理"""
|
|
|
|
|
|
# 处理预检请求
|
|
|
|
|
|
preflight_response = handle_preflight()
|
|
|
|
|
|
if preflight_response:
|
|
|
|
|
|
return preflight_response
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.after_request
|
|
|
|
|
|
def after_request(response):
|
|
|
|
|
|
"""在每个请求后添加CORS头部"""
|
|
|
|
|
|
return cors_after(response)
|
2025-11-19 22:49:24 +08:00
|
|
|
|
|
|
|
|
|
|
# ==================== 产品相关接口 ====================
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/products', methods=['GET'])
|
|
|
|
|
|
def get_user_products():
|
|
|
|
|
|
"""用户端获取产品列表(无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
page = request.args.get('page', 1, type=int)
|
|
|
|
|
|
per_page = min(request.args.get('per_page', 20, type=int), 100)
|
|
|
|
|
|
keyword = request.args.get('keyword', '').strip()
|
|
|
|
|
|
product_type = request.args.get('type') # 产品类型筛选
|
|
|
|
|
|
is_paid = request.args.get('is_paid', type=int) # 付费筛选:1=付费,0=免费
|
|
|
|
|
|
|
|
|
|
|
|
query = Product.query.filter_by(status=1) # 只显示启用的产品
|
|
|
|
|
|
|
|
|
|
|
|
# 关键词搜索
|
|
|
|
|
|
if keyword:
|
|
|
|
|
|
query = query.filter(
|
|
|
|
|
|
db.or_(
|
|
|
|
|
|
Product.product_name.like(f'%{keyword}%'),
|
|
|
|
|
|
Product.description.like(f'%{keyword}%')
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 产品类型筛选
|
|
|
|
|
|
if product_type:
|
|
|
|
|
|
query = query.filter(Product.product_type == product_type)
|
|
|
|
|
|
|
|
|
|
|
|
query = query.order_by(Product.create_time.desc())
|
|
|
|
|
|
pagination = query.paginate(page=page, per_page=per_page, error_out=False)
|
|
|
|
|
|
|
|
|
|
|
|
products = []
|
|
|
|
|
|
for product in pagination.items:
|
|
|
|
|
|
product_dict = product.to_dict()
|
|
|
|
|
|
# 获取最新版本信息
|
|
|
|
|
|
latest_version = Version.query.filter_by(
|
|
|
|
|
|
product_id=product.product_id,
|
|
|
|
|
|
publish_status=1
|
|
|
|
|
|
).order_by(Version.create_time.desc()).first()
|
|
|
|
|
|
|
|
|
|
|
|
product_dict['latest_version'] = latest_version.version_num if latest_version else None
|
|
|
|
|
|
# 移除不存在的is_paid字段
|
|
|
|
|
|
products.append(product_dict)
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': {
|
|
|
|
|
|
'products': products,
|
|
|
|
|
|
'pagination': {
|
|
|
|
|
|
'page': page,
|
|
|
|
|
|
'per_page': per_page,
|
|
|
|
|
|
'total': pagination.total,
|
|
|
|
|
|
'pages': pagination.pages,
|
|
|
|
|
|
'has_prev': pagination.has_prev,
|
|
|
|
|
|
'has_next': pagination.has_next
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"获取产品列表失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误,请稍后重试'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/products/<product_id>', methods=['GET'])
|
|
|
|
|
|
def get_user_product(product_id):
|
|
|
|
|
|
"""用户端获取产品详情(无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
product = Product.query.filter_by(product_id=product_id, status=1).first()
|
|
|
|
|
|
if not product:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '产品不存在或已下架'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
|
|
|
|
|
product_dict = product.to_dict(include_stats=True)
|
|
|
|
|
|
|
|
|
|
|
|
# 获取最新版本信息
|
|
|
|
|
|
latest_version = Version.query.filter_by(
|
|
|
|
|
|
product_id=product_id,
|
|
|
|
|
|
publish_status=1
|
|
|
|
|
|
).order_by(Version.create_time.desc()).first()
|
|
|
|
|
|
|
|
|
|
|
|
if latest_version:
|
2025-11-22 16:48:45 +08:00
|
|
|
|
product_dict['latest_version'] = latest_version.version_num
|
2025-11-19 22:49:24 +08:00
|
|
|
|
|
|
|
|
|
|
# 获取最近3条更新日志
|
|
|
|
|
|
recent_versions = Version.query.filter_by(
|
|
|
|
|
|
product_id=product_id,
|
|
|
|
|
|
publish_status=1
|
|
|
|
|
|
).order_by(Version.create_time.desc()).limit(3).all()
|
|
|
|
|
|
|
|
|
|
|
|
product_dict['recent_updates'] = [
|
|
|
|
|
|
{
|
|
|
|
|
|
'version_num': v.version_num,
|
|
|
|
|
|
'update_time': v.create_time.isoformat(),
|
|
|
|
|
|
'update_log': v.update_log
|
|
|
|
|
|
} for v in recent_versions
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# 移除不存在的is_paid字段
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': product_dict
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"获取产品详情失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 卡密相关接口 ====================
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/licenses/packages', methods=['GET'])
|
|
|
|
|
|
def get_license_packages():
|
|
|
|
|
|
"""用户端获取卡密套餐(按产品筛选,无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
product_id = request.args.get('product_id')
|
|
|
|
|
|
if not product_id:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '缺少产品ID参数'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证产品是否存在且启用
|
|
|
|
|
|
product = Product.query.filter_by(product_id=product_id, status=1).first()
|
|
|
|
|
|
if not product:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '产品不存在或已下架'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
# 从套餐表获取该产品的套餐信息
|
|
|
|
|
|
from app.models.package import Package
|
2025-11-19 22:49:24 +08:00
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
# 获取启用的套餐
|
|
|
|
|
|
packages = Package.query.filter_by(
|
|
|
|
|
|
product_id=product_id,
|
|
|
|
|
|
status=1
|
|
|
|
|
|
).order_by(Package.sort_order).all()
|
2025-11-19 22:49:24 +08:00
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
# 转换为字典格式
|
|
|
|
|
|
package_list = [pkg.to_dict() for pkg in packages]
|
2025-11-19 22:49:24 +08:00
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': {
|
|
|
|
|
|
'product': product.to_dict(),
|
2025-11-22 16:48:45 +08:00
|
|
|
|
'packages': package_list
|
2025-11-19 22:49:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"获取卡密套餐失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/licenses/verify', methods=['GET'])
|
|
|
|
|
|
def user_verify_license():
|
|
|
|
|
|
"""用户端验证卡密(下载用,无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
license_key = request.args.get('license_key')
|
|
|
|
|
|
product_id = request.args.get('product_id')
|
|
|
|
|
|
|
|
|
|
|
|
if not all([license_key, product_id]):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '缺少必要参数'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 查找卡密
|
|
|
|
|
|
license_obj = License.query.filter_by(
|
|
|
|
|
|
license_key=license_key,
|
|
|
|
|
|
product_id=product_id
|
|
|
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
|
|
if not license_obj:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '卡密不存在'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
|
|
|
|
|
# 检查卡密状态
|
|
|
|
|
|
if license_obj.status != 1:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '卡密未激活或已失效'
|
|
|
|
|
|
}), 403
|
|
|
|
|
|
|
|
|
|
|
|
# 检查是否过期
|
|
|
|
|
|
if license_obj.is_expired():
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '卡密已过期'
|
|
|
|
|
|
}), 403
|
|
|
|
|
|
|
|
|
|
|
|
# 获取产品信息
|
|
|
|
|
|
product = Product.query.filter_by(product_id=product_id, status=1).first()
|
|
|
|
|
|
if not product:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '产品不存在或已下架'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
|
|
|
|
|
# 获取下载链接(从最新版本获取)
|
|
|
|
|
|
latest_version = Version.query.filter_by(
|
|
|
|
|
|
product_id=product_id,
|
|
|
|
|
|
publish_status=1
|
|
|
|
|
|
).order_by(Version.create_time.desc()).first()
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'message': '卡密验证成功',
|
|
|
|
|
|
'data': {
|
|
|
|
|
|
'license_key': license_obj.license_key,
|
|
|
|
|
|
'product_name': product.product_name,
|
|
|
|
|
|
'expire_time': license_obj.expire_time.isoformat() if license_obj.expire_time else None,
|
|
|
|
|
|
'download_url': latest_version.download_url if latest_version else None,
|
|
|
|
|
|
'can_download': True
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"卡密验证失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 工单相关接口 ====================
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/tickets', methods=['POST'])
|
|
|
|
|
|
def create_user_ticket():
|
|
|
|
|
|
"""用户端创建工单(无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
data = request.get_json()
|
|
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({'success': False, 'message': '请求数据为空'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
product_id = data.get('product_id')
|
|
|
|
|
|
contact_person = data.get('contact_person', '').strip()
|
|
|
|
|
|
phone = data.get('phone', '').strip()
|
|
|
|
|
|
title = data.get('title', '').strip()
|
|
|
|
|
|
description = data.get('description', '').strip()
|
|
|
|
|
|
attachment = data.get('attachment') # 附件信息
|
|
|
|
|
|
|
|
|
|
|
|
# 验证必填字段
|
|
|
|
|
|
if not all([product_id, contact_person, phone, title, description]):
|
|
|
|
|
|
return jsonify({'success': False, 'message': '缺少必要参数'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证手机号格式
|
|
|
|
|
|
if not phone or not re.match(r'^1[3-9]\d{9}$', phone):
|
|
|
|
|
|
return jsonify({'success': False, 'message': '手机号格式不正确'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证产品存在且启用
|
|
|
|
|
|
product = Product.query.filter_by(product_id=product_id, status=1).first()
|
|
|
|
|
|
if not product:
|
|
|
|
|
|
return jsonify({'success': False, 'message': '产品不存在或已下架'}), 404
|
|
|
|
|
|
|
|
|
|
|
|
ticket = Ticket(
|
|
|
|
|
|
title=title,
|
|
|
|
|
|
product_id=product_id,
|
|
|
|
|
|
description=description,
|
|
|
|
|
|
contact_person=contact_person,
|
|
|
|
|
|
phone=phone,
|
|
|
|
|
|
attachment=attachment,
|
|
|
|
|
|
priority=data.get('priority', 1),
|
|
|
|
|
|
source=1 # 用户提交的工单
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
db.session.add(ticket)
|
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
|
|
|
|
# 记录操作日志
|
|
|
|
|
|
log_operation('CREATE_USER_TICKET', 'TICKET', ticket.ticket_id, {
|
|
|
|
|
|
'title': ticket.title,
|
|
|
|
|
|
'product_id': ticket.product_id,
|
|
|
|
|
|
'contact_person': contact_person,
|
|
|
|
|
|
'phone': phone
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'message': '工单提交成功',
|
|
|
|
|
|
'data': {
|
|
|
|
|
|
'ticket_id': ticket.ticket_id,
|
|
|
|
|
|
'ticket_number': ticket.ticket_number
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
db.session.rollback()
|
|
|
|
|
|
current_app.logger.error(f"创建工单失败: {str(e)}")
|
|
|
|
|
|
return jsonify({'success': False, 'message': '服务器内部错误'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/tickets', methods=['GET'])
|
|
|
|
|
|
def get_user_tickets():
|
|
|
|
|
|
"""用户端获取工单列表(通过手机号查询,无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
phone = request.args.get('phone')
|
|
|
|
|
|
|
|
|
|
|
|
if not phone:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '缺少手机号参数'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证手机号格式
|
|
|
|
|
|
if not re.match(r'^1[3-9]\d{9}$', phone):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '手机号格式不正确'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 查询该手机号提交的工单
|
|
|
|
|
|
tickets = Ticket.query.filter_by(phone=phone).order_by(Ticket.create_time.desc()).all()
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': [ticket.to_dict() for ticket in tickets]
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"获取工单列表失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/tickets/query', methods=['GET'])
|
|
|
|
|
|
def query_user_ticket():
|
|
|
|
|
|
"""用户端查询工单(通过工单编号+手机号,无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
ticket_number = request.args.get('ticket_number')
|
|
|
|
|
|
phone = request.args.get('phone')
|
|
|
|
|
|
|
|
|
|
|
|
if not all([ticket_number, phone]):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '缺少必要参数'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证手机号格式
|
|
|
|
|
|
if not phone or not re.match(r'^1[3-9]\d{9}$', phone):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '手机号格式不正确'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 查找工单
|
|
|
|
|
|
ticket = Ticket.query.filter_by(
|
|
|
|
|
|
ticket_number=ticket_number,
|
|
|
|
|
|
phone=phone
|
|
|
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
|
|
if not ticket:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '工单不存在或手机号不匹配'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': ticket.to_dict()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"查询工单失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 订单相关接口 ====================
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/orders', methods=['POST'])
|
|
|
|
|
|
def create_user_order():
|
|
|
|
|
|
"""用户端创建订单(无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
data = request.get_json()
|
|
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '请求数据为空'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
product_id = data.get('product_id')
|
|
|
|
|
|
package_id = data.get('package_id')
|
|
|
|
|
|
contact_person = data.get('contact_person', '').strip()
|
|
|
|
|
|
phone = data.get('phone', '').strip()
|
|
|
|
|
|
quantity = data.get('quantity', 1)
|
|
|
|
|
|
|
|
|
|
|
|
# 验证必填字段
|
|
|
|
|
|
if not all([product_id, package_id, contact_person, phone]):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '缺少必要参数'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证手机号格式
|
|
|
|
|
|
if not phone or not re.match(r'^1[3-9]\d{9}$', phone):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '手机号格式不正确'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证数量
|
|
|
|
|
|
if not isinstance(quantity, int) or quantity < 1 or quantity > 5:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '购买数量必须在1-5之间'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证产品存在且启用
|
|
|
|
|
|
product = Product.query.filter_by(product_id=product_id, status=1).first()
|
|
|
|
|
|
if not product:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '产品不存在或已下架'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
|
|
|
|
|
# 生成订单号(简化处理,实际应有更复杂的订单号生成规则)
|
|
|
|
|
|
import time
|
|
|
|
|
|
import random
|
|
|
|
|
|
order_number = f"ORD{int(time.time())}{random.randint(100, 999)}"
|
|
|
|
|
|
|
|
|
|
|
|
# 简化处理:直接返回支付链接(实际应对接支付系统)
|
|
|
|
|
|
# 这里模拟支付链接生成
|
|
|
|
|
|
payment_url = f"/payment?order_number={order_number}&amount=0.01" # 示例金额
|
|
|
|
|
|
|
|
|
|
|
|
# 记录操作日志
|
|
|
|
|
|
log_operation('CREATE_USER_ORDER', 'ORDER', None, {
|
|
|
|
|
|
'order_number': order_number,
|
|
|
|
|
|
'product_id': product_id,
|
|
|
|
|
|
'package_id': package_id,
|
|
|
|
|
|
'contact_person': contact_person,
|
|
|
|
|
|
'phone': phone,
|
|
|
|
|
|
'quantity': quantity
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'message': '订单创建成功',
|
|
|
|
|
|
'data': {
|
|
|
|
|
|
'order_number': order_number,
|
|
|
|
|
|
'payment_url': payment_url,
|
|
|
|
|
|
'amount': 0.01 # 示例金额
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"创建订单失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/orders/query', methods=['GET'])
|
|
|
|
|
|
def query_user_order():
|
|
|
|
|
|
"""用户端查询订单(通过手机号+订单号,无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
order_number = request.args.get('order_number')
|
|
|
|
|
|
phone = request.args.get('phone')
|
|
|
|
|
|
|
|
|
|
|
|
if not all([order_number, phone]):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '缺少必要参数'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证手机号格式
|
|
|
|
|
|
if not phone or not re.match(r'^1[3-9]\d{9}$', phone):
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '手机号格式不正确'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 这里简化处理,实际应查询订单表
|
|
|
|
|
|
# 模拟返回订单信息
|
|
|
|
|
|
order_info = {
|
|
|
|
|
|
'order_number': order_number,
|
|
|
|
|
|
'status': 1, # 1=已支付
|
|
|
|
|
|
'status_name': '已支付',
|
|
|
|
|
|
'amount': 0.01,
|
|
|
|
|
|
'created_time': '2023-01-01T00:00:00',
|
|
|
|
|
|
'payment_time': '2023-01-01T00:05:00'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': order_info
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"查询订单失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 下载相关接口 ====================
|
|
|
|
|
|
|
|
|
|
|
|
@api_bp.route('/user/downloads/check', methods=['GET'])
|
|
|
|
|
|
def check_download_permission():
|
|
|
|
|
|
"""用户端检查下载权限(无需认证)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
product_id = request.args.get('product_id')
|
|
|
|
|
|
|
|
|
|
|
|
if not product_id:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '缺少产品ID参数'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 验证产品存在且启用
|
|
|
|
|
|
product = Product.query.filter_by(product_id=product_id, status=1).first()
|
|
|
|
|
|
if not product:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '产品不存在或已下架'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
|
|
|
|
|
# 获取产品是否为付费产品
|
|
|
|
|
|
is_paid = getattr(product, 'is_paid', False)
|
|
|
|
|
|
|
|
|
|
|
|
# 获取最新版本信息
|
|
|
|
|
|
latest_version = Version.query.filter_by(
|
|
|
|
|
|
product_id=product_id,
|
|
|
|
|
|
publish_status=1
|
|
|
|
|
|
).order_by(Version.create_time.desc()).first()
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': {
|
|
|
|
|
|
'product_id': product_id,
|
|
|
|
|
|
'product_name': product.product_name,
|
|
|
|
|
|
'is_paid': is_paid,
|
|
|
|
|
|
'latest_version': latest_version.version_num if latest_version else None,
|
|
|
|
|
|
'download_url': latest_version.download_url if latest_version else None
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
current_app.logger.error(f"检查下载权限失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'message': '服务器内部错误'
|
|
|
|
|
|
}), 500
|