|
@@ -1,10 +1,10 @@
|
|
import sqlite3
|
|
import sqlite3
|
|
|
|
+import uuid
|
|
from io import BytesIO
|
|
from io import BytesIO
|
|
-import pickle
|
|
|
|
|
|
|
|
-from flask import Blueprint, request, jsonify, current_app, send_file
|
|
|
|
|
|
+from flask import Blueprint, request, jsonify, current_app, send_file, session
|
|
from werkzeug.security import check_password_hash, generate_password_hash
|
|
from werkzeug.security import check_password_hash, generate_password_hash
|
|
-from werkzeug.utils import secure_filename
|
|
|
|
|
|
+from werkzeug.utils import secure_filename, send_from_directory
|
|
|
|
|
|
from .model import predict, train_and_save_model, calculate_model_score
|
|
from .model import predict, train_and_save_model, calculate_model_score
|
|
import pandas as pd
|
|
import pandas as pd
|
|
@@ -20,7 +20,6 @@ import logging
|
|
from sqlalchemy import text, select, MetaData, Table, func
|
|
from sqlalchemy import text, select, MetaData, Table, func
|
|
from .tasks import train_model_task
|
|
from .tasks import train_model_task
|
|
from datetime import datetime
|
|
from datetime import datetime
|
|
-from sklearn.metrics import r2_score
|
|
|
|
|
|
|
|
# 配置日志
|
|
# 配置日志
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
@@ -389,41 +388,46 @@ def get_model(model_id):
|
|
session.close()
|
|
session.close()
|
|
|
|
|
|
|
|
|
|
|
|
+# 显示切换模型
|
|
@bp.route('/models', methods=['GET'])
|
|
@bp.route('/models', methods=['GET'])
|
|
-def get_all_models():
|
|
|
|
- """
|
|
|
|
- 获取所有模型信息的API接口
|
|
|
|
-
|
|
|
|
- @return: JSON响应
|
|
|
|
- """
|
|
|
|
- Session = sessionmaker(bind=db.engine)
|
|
|
|
- session = Session()
|
|
|
|
-
|
|
|
|
|
|
+def get_models():
|
|
|
|
+ session = None
|
|
try:
|
|
try:
|
|
|
|
+ # 创建 session
|
|
|
|
+ Session = sessionmaker(bind=db.engine)
|
|
|
|
+ session = Session()
|
|
|
|
+
|
|
|
|
+ # 查询所有模型
|
|
models = session.query(Models).all()
|
|
models = session.query(Models).all()
|
|
- if models:
|
|
|
|
- result = [
|
|
|
|
- {
|
|
|
|
- 'ModelID': model.ModelID,
|
|
|
|
- 'Model_name': model.Model_name,
|
|
|
|
- 'Model_type': model.Model_type,
|
|
|
|
- 'Created_at': model.Created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
|
|
|
- 'Description': model.Description,
|
|
|
|
- 'Performance_score': float(model.Performance_score) if model.Performance_score else None,
|
|
|
|
- 'Data_type': model.Data_type
|
|
|
|
- }
|
|
|
|
- for model in models
|
|
|
|
- ]
|
|
|
|
- return jsonify(result)
|
|
|
|
- else:
|
|
|
|
- return jsonify({'message': '未找到任何模型'}), 404
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ logger.debug(f"Models found: {models}") # 打印查询的模型数据
|
|
|
|
+
|
|
|
|
+ if not models:
|
|
|
|
+ return jsonify({'message': 'No models found'}), 404
|
|
|
|
+
|
|
|
|
+ # 将模型数据转换为字典列表
|
|
|
|
+ models_list = [
|
|
|
|
+ {
|
|
|
|
+ 'ModelID': model.ModelID,
|
|
|
|
+ 'ModelName': model.Model_name,
|
|
|
|
+ 'ModelType': model.Model_type,
|
|
|
|
+ 'CreatedAt': model.Created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
|
|
|
+ 'Description': model.Description,
|
|
|
|
+ 'DatasetID': model.DatasetID,
|
|
|
|
+ 'ModelFilePath': model.ModelFilePath,
|
|
|
|
+ 'DataType': model.Data_type,
|
|
|
|
+ 'PerformanceScore': model.Performance_score
|
|
|
|
+ }
|
|
|
|
+ for model in models
|
|
|
|
+ ]
|
|
|
|
+
|
|
|
|
+ return jsonify(models_list), 200
|
|
|
|
+
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- logger.error(f'获取所有模型信息失败: {str(e)}')
|
|
|
|
- return jsonify({'error': '服务器内部错误', 'message': str(e)}), 500
|
|
|
|
-
|
|
|
|
|
|
+ return jsonify({'error': str(e)}), 400
|
|
finally:
|
|
finally:
|
|
- session.close()
|
|
|
|
|
|
+ if session:
|
|
|
|
+ session.close()
|
|
|
|
|
|
|
|
|
|
@bp.route('/model-parameters', methods=['GET'])
|
|
@bp.route('/model-parameters', methods=['GET'])
|
|
@@ -514,7 +518,7 @@ def add_item():
|
|
duplicate_check_rules = {
|
|
duplicate_check_rules = {
|
|
'users': ['email', 'username'],
|
|
'users': ['email', 'username'],
|
|
'products': ['product_code'],
|
|
'products': ['product_code'],
|
|
- 'current_reduce': [ 'Q_over_b', 'pH', 'OM', 'CL', 'H', 'Al'],
|
|
|
|
|
|
+ 'current_reduce': ['Q_over_b', 'pH', 'OM', 'CL', 'H', 'Al'],
|
|
'current_reflux': ['OM', 'CL', 'CEC', 'H_plus', 'N', 'Al3_plus', 'Delta_pH'],
|
|
'current_reflux': ['OM', 'CL', 'CEC', 'H_plus', 'N', 'Al3_plus', 'Delta_pH'],
|
|
# 其他表和规则
|
|
# 其他表和规则
|
|
}
|
|
}
|
|
@@ -611,6 +615,7 @@ def delete_item():
|
|
"message": f"删除失败: {e}"
|
|
"message": f"删除失败: {e}"
|
|
}), 500
|
|
}), 500
|
|
|
|
|
|
|
|
+
|
|
# 定义修改数据库记录的 API 接口
|
|
# 定义修改数据库记录的 API 接口
|
|
@bp.route('/update_item', methods=['PUT'])
|
|
@bp.route('/update_item', methods=['PUT'])
|
|
def update_record():
|
|
def update_record():
|
|
@@ -875,6 +880,7 @@ def delete_model_route(model_id):
|
|
# 调用原始函数
|
|
# 调用原始函数
|
|
return delete_model(model_id, delete_dataset=delete_dataset_param)
|
|
return delete_model(model_id, delete_dataset=delete_dataset_param)
|
|
|
|
|
|
|
|
+
|
|
def delete_model(model_id, delete_dataset=False):
|
|
def delete_model(model_id, delete_dataset=False):
|
|
"""
|
|
"""
|
|
删除指定模型的API接口
|
|
删除指定模型的API接口
|
|
@@ -899,19 +905,16 @@ def delete_model(model_id, delete_dataset=False):
|
|
session.commit()
|
|
session.commit()
|
|
|
|
|
|
# 2. 删除模型文件
|
|
# 2. 删除模型文件
|
|
- model_path = model.ModelFilePath
|
|
|
|
- try:
|
|
|
|
- if os.path.exists(model_path):
|
|
|
|
|
|
+ model_file = f"rf_model_{model_id}.pkl"
|
|
|
|
+ model_path = os.path.join(current_app.config['MODEL_SAVE_PATH'], model_file)
|
|
|
|
+ if os.path.exists(model_path):
|
|
|
|
+ try:
|
|
os.remove(model_path)
|
|
os.remove(model_path)
|
|
- else:
|
|
|
|
|
|
+ except OSError as e:
|
|
# 如果删除文件失败,回滚数据库操作
|
|
# 如果删除文件失败,回滚数据库操作
|
|
- session.rollback()
|
|
|
|
- logger.warning(f'模型文件不存在: {model_path}')
|
|
|
|
- except OSError as e:
|
|
|
|
- # 如果删除文件失败,回滚数据库操作
|
|
|
|
- session.rollback()
|
|
|
|
- logger.error(f'删除模型文件失败: {str(e)}')
|
|
|
|
- return jsonify({'error': f'删除模型文件失败: {str(e)}'}), 500
|
|
|
|
|
|
+ session.rollback()
|
|
|
|
+ logger.error(f'删除模型文件失败: {str(e)}')
|
|
|
|
+ return jsonify({'error': f'删除模型文件失败: {str(e)}'}), 500
|
|
|
|
|
|
# 3. 如果需要删除关联的数据集
|
|
# 3. 如果需要删除关联的数据集
|
|
if delete_dataset and dataset_id:
|
|
if delete_dataset and dataset_id:
|
|
@@ -931,7 +934,7 @@ def delete_model(model_id, delete_dataset=False):
|
|
|
|
|
|
response_data = {
|
|
response_data = {
|
|
'message': '模型删除成功',
|
|
'message': '模型删除成功',
|
|
- 'deleted_files': [model_path]
|
|
|
|
|
|
+ 'deleted_files': [model_file]
|
|
}
|
|
}
|
|
|
|
|
|
if delete_dataset:
|
|
if delete_dataset:
|
|
@@ -991,54 +994,59 @@ def clear_dataset(data_type):
|
|
session.close()
|
|
session.close()
|
|
|
|
|
|
|
|
|
|
|
|
+# 修改了一下登录·接口
|
|
@bp.route('/login', methods=['POST'])
|
|
@bp.route('/login', methods=['POST'])
|
|
def login_user():
|
|
def login_user():
|
|
- # 获取前端传来的数据
|
|
|
|
data = request.get_json()
|
|
data = request.get_json()
|
|
- name = data.get('name') # 用户名
|
|
|
|
- password = data.get('password') # 密码
|
|
|
|
|
|
+ logger.debug(f"Received login data: {data}") # 增加调试日志
|
|
|
|
+ name = data.get('name')
|
|
|
|
+ password = data.get('password')
|
|
|
|
|
|
- logger.info(f"Login request received: name={name}")
|
|
|
|
|
|
+ logger.info(f"Login request received for user: {name}")
|
|
|
|
+
|
|
|
|
+ if not isinstance(name, str) or not isinstance(password, str):
|
|
|
|
+ logger.warning("Username and password must be strings")
|
|
|
|
+ return jsonify({"success": False, "message": "用户名和密码必须为字符串"}), 400
|
|
|
|
|
|
- # 检查用户名和密码是否为空
|
|
|
|
if not name or not password:
|
|
if not name or not password:
|
|
- logger.warning("用户名和密码不能为空")
|
|
|
|
|
|
+ logger.warning("Username and password cannot be empty")
|
|
return jsonify({"success": False, "message": "用户名和密码不能为空"}), 400
|
|
return jsonify({"success": False, "message": "用户名和密码不能为空"}), 400
|
|
|
|
|
|
- try:
|
|
|
|
- # 查询数据库验证用户名
|
|
|
|
- query = "SELECT * FROM users WHERE name = :name"
|
|
|
|
- conn = get_db()
|
|
|
|
- user = conn.execute(query, {"name": name}).fetchone()
|
|
|
|
-
|
|
|
|
- if not user:
|
|
|
|
- logger.warning(f"用户名 '{name}' 不存在")
|
|
|
|
- return jsonify({"success": False, "message": "用户名不存在"}), 400
|
|
|
|
-
|
|
|
|
- # 获取数据库中存储的密码(假设密码是哈希存储的)
|
|
|
|
- stored_password = user[2] # 假设密码存储在数据库的第三列
|
|
|
|
- user_id = user[0] # 假设 id 存储在数据库的第一列
|
|
|
|
|
|
+ query = "SELECT id, name, password FROM users WHERE name = ?"
|
|
|
|
|
|
- # 校验密码是否正确
|
|
|
|
- if check_password_hash(stored_password, password):
|
|
|
|
- logger.info(f"User '{name}' logged in successfully.")
|
|
|
|
- return jsonify({
|
|
|
|
- "success": True,
|
|
|
|
- "message": "登录成功",
|
|
|
|
- "userId": user_id # 返回用户 ID
|
|
|
|
- })
|
|
|
|
- else:
|
|
|
|
- logger.warning(f"Invalid password for user '{name}'")
|
|
|
|
- return jsonify({"success": False, "message": "用户名或密码错误"}), 400
|
|
|
|
|
|
+ try:
|
|
|
|
+ with get_db() as conn:
|
|
|
|
+ user = conn.execute(query, (name,)).fetchone()
|
|
|
|
+
|
|
|
|
+ if not user:
|
|
|
|
+ logger.warning(f"User '{name}' does not exist")
|
|
|
|
+ return jsonify({"success": False, "message": "用户名不存在"}), 400
|
|
|
|
+
|
|
|
|
+ stored_password = user[2] # 假设 'password' 是第三个字段
|
|
|
|
+ user_id = user[0] # 假设 'id' 是第一个字段
|
|
|
|
+
|
|
|
|
+ if check_password_hash(stored_password, password):
|
|
|
|
+ session['name'] = name
|
|
|
|
+ logger.info(f"User '{name}' logged in successfully.")
|
|
|
|
+ return jsonify({
|
|
|
|
+ "success": True,
|
|
|
|
+ "message": "登录成功",
|
|
|
|
+ "userId": user_id,
|
|
|
|
+ "name": name
|
|
|
|
+ })
|
|
|
|
+ else:
|
|
|
|
+ logger.warning(f"Incorrect password for user '{name}'")
|
|
|
|
+ return jsonify({"success": False, "message": "用户名或密码错误"}), 400
|
|
|
|
|
|
|
|
+ except sqlite3.DatabaseError as db_err:
|
|
|
|
+ logger.error(f"Database error during login process: {db_err}", exc_info=True)
|
|
|
|
+ return jsonify({"success": False, "message": "数据库错误"}), 500
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- # 记录错误日志并返回错误信息
|
|
|
|
- logger.error(f"Error during login: {e}", exc_info=True)
|
|
|
|
|
|
+ logger.error(f"Unexpected error during login process: {e}", exc_info=True)
|
|
return jsonify({"success": False, "message": "登录失败"}), 500
|
|
return jsonify({"success": False, "message": "登录失败"}), 500
|
|
|
|
|
|
-# 更新用户信息接口
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
+# 更新用户信息接口
|
|
@bp.route('/update_user', methods=['POST'])
|
|
@bp.route('/update_user', methods=['POST'])
|
|
def update_user():
|
|
def update_user():
|
|
# 获取前端传来的数据
|
|
# 获取前端传来的数据
|
|
@@ -1339,6 +1347,7 @@ def download_template():
|
|
logger.error(f"Failed to generate template: {e}", exc_info=True)
|
|
logger.error(f"Failed to generate template: {e}", exc_info=True)
|
|
return jsonify({'error': '生成模板文件失败'}), 500
|
|
return jsonify({'error': '生成模板文件失败'}), 500
|
|
|
|
|
|
|
|
+
|
|
@bp.route('/update-threshold', methods=['POST'])
|
|
@bp.route('/update-threshold', methods=['POST'])
|
|
def update_threshold():
|
|
def update_threshold():
|
|
"""
|
|
"""
|
|
@@ -1395,6 +1404,7 @@ def get_threshold():
|
|
'error': f'获取阈值失败: {str(e)}'
|
|
'error': f'获取阈值失败: {str(e)}'
|
|
}), 500
|
|
}), 500
|
|
|
|
|
|
|
|
+
|
|
@bp.route('/set-current-dataset/<string:data_type>/<int:dataset_id>', methods=['POST'])
|
|
@bp.route('/set-current-dataset/<string:data_type>/<int:dataset_id>', methods=['POST'])
|
|
def set_current_dataset(data_type, dataset_id):
|
|
def set_current_dataset(data_type, dataset_id):
|
|
"""
|
|
"""
|
|
@@ -1456,6 +1466,7 @@ def set_current_dataset(data_type, dataset_id):
|
|
finally:
|
|
finally:
|
|
session.close()
|
|
session.close()
|
|
|
|
|
|
|
|
+
|
|
@bp.route('/get-model-history/<string:data_type>', methods=['GET'])
|
|
@bp.route('/get-model-history/<string:data_type>', methods=['GET'])
|
|
def get_model_history(data_type):
|
|
def get_model_history(data_type):
|
|
"""
|
|
"""
|
|
@@ -1481,6 +1492,8 @@ def get_model_history(data_type):
|
|
Models.DatasetID == dataset.Dataset_ID,
|
|
Models.DatasetID == dataset.Dataset_ID,
|
|
Models.Model_name.like(f'auto_trained_{data_type}_%')
|
|
Models.Model_name.like(f'auto_trained_{data_type}_%')
|
|
).first()
|
|
).first()
|
|
|
|
+ print(model)
|
|
|
|
+ print(dataset)
|
|
|
|
|
|
if model and model.Performance_score is not None:
|
|
if model and model.Performance_score is not None:
|
|
# 直接使用数据库中的时间,不进行格式化(保持与created_at相同的时区)
|
|
# 直接使用数据库中的时间,不进行格式化(保持与created_at相同的时区)
|
|
@@ -1506,6 +1519,7 @@ def get_model_history(data_type):
|
|
'performance_scores': [item['performance_score'] for item in history_data],
|
|
'performance_scores': [item['performance_score'] for item in history_data],
|
|
'model_details': history_data # 保留完整数据供前端使用
|
|
'model_details': history_data # 保留完整数据供前端使用
|
|
}
|
|
}
|
|
|
|
+ print(response_data)
|
|
|
|
|
|
return jsonify(response_data), 200
|
|
return jsonify(response_data), 200
|
|
|
|
|
|
@@ -1516,6 +1530,7 @@ def get_model_history(data_type):
|
|
finally:
|
|
finally:
|
|
session.close()
|
|
session.close()
|
|
|
|
|
|
|
|
+
|
|
@bp.route('/batch-delete-datasets', methods=['POST'])
|
|
@bp.route('/batch-delete-datasets', methods=['POST'])
|
|
def batch_delete_datasets():
|
|
def batch_delete_datasets():
|
|
"""
|
|
"""
|
|
@@ -1580,6 +1595,7 @@ def batch_delete_datasets():
|
|
logger.error(f'批量删除数据集失败: {str(e)}')
|
|
logger.error(f'批量删除数据集失败: {str(e)}')
|
|
return jsonify({'error': str(e)}), 500
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
|
|
+
|
|
@bp.route('/batch-delete-models', methods=['POST'])
|
|
@bp.route('/batch-delete-models', methods=['POST'])
|
|
def batch_delete_models():
|
|
def batch_delete_models():
|
|
"""
|
|
"""
|
|
@@ -1645,6 +1661,7 @@ def batch_delete_models():
|
|
logger.error(f'批量删除模型失败: {str(e)}')
|
|
logger.error(f'批量删除模型失败: {str(e)}')
|
|
return jsonify({'error': str(e)}), 500
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
|
|
+
|
|
@bp.route('/kriging_interpolation', methods=['POST'])
|
|
@bp.route('/kriging_interpolation', methods=['POST'])
|
|
def kriging_interpolation():
|
|
def kriging_interpolation():
|
|
try:
|
|
try:
|
|
@@ -1667,64 +1684,122 @@ def kriging_interpolation():
|
|
except Exception as e:
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
-@bp.route('/model-scatter-data/<int:model_id>', methods=['GET'])
|
|
|
|
-def get_model_scatter_data(model_id):
|
|
|
|
- """
|
|
|
|
- 获取指定模型的散点图数据(真实值vs预测值)
|
|
|
|
-
|
|
|
|
- @param model_id: 模型ID
|
|
|
|
- @return: JSON响应,包含散点图数据
|
|
|
|
- """
|
|
|
|
- Session = sessionmaker(bind=db.engine)
|
|
|
|
- session = Session()
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+# 切换模型接口
|
|
|
|
+@bp.route('/switch-model', methods=['POST'])
|
|
|
|
+def switch_model():
|
|
|
|
+ session = None
|
|
try:
|
|
try:
|
|
- # 查询模型信息
|
|
|
|
|
|
+ data = request.get_json()
|
|
|
|
+ model_id = data.get('model_id')
|
|
|
|
+ model_name = data.get('model_name')
|
|
|
|
+
|
|
|
|
+ # 创建 session
|
|
|
|
+ Session = sessionmaker(bind=db.engine)
|
|
|
|
+ session = Session()
|
|
|
|
+
|
|
|
|
+ # 查找模型
|
|
model = session.query(Models).filter_by(ModelID=model_id).first()
|
|
model = session.query(Models).filter_by(ModelID=model_id).first()
|
|
if not model:
|
|
if not model:
|
|
- return jsonify({'error': '未找到指定模型'}), 404
|
|
|
|
-
|
|
|
|
- # 加载模型
|
|
|
|
- with open(model.ModelFilePath, 'rb') as f:
|
|
|
|
- ML_model = pickle.load(f)
|
|
|
|
-
|
|
|
|
- # 根据数据类型加载测试数据
|
|
|
|
- if model.Data_type == 'reflux':
|
|
|
|
- X_test = pd.read_csv('uploads/data/X_test_reflux.csv')
|
|
|
|
- Y_test = pd.read_csv('uploads/data/Y_test_reflux.csv')
|
|
|
|
- elif model.Data_type == 'reduce':
|
|
|
|
- X_test = pd.read_csv('uploads/data/X_test_reduce.csv')
|
|
|
|
- Y_test = pd.read_csv('uploads/data/Y_test_reduce.csv')
|
|
|
|
- else:
|
|
|
|
- return jsonify({'error': '不支持的数据类型'}), 400
|
|
|
|
-
|
|
|
|
- # 获取预测值
|
|
|
|
- y_pred = ML_model.predict(X_test)
|
|
|
|
-
|
|
|
|
- # 生成散点图数据
|
|
|
|
- scatter_data = [
|
|
|
|
- [float(true), float(pred)]
|
|
|
|
- for true, pred in zip(Y_test.iloc[:, 0], y_pred)
|
|
|
|
- ]
|
|
|
|
-
|
|
|
|
- # 计算R²分数
|
|
|
|
- r2 = r2_score(Y_test, y_pred)
|
|
|
|
-
|
|
|
|
- # 获取数据范围,用于绘制对角线
|
|
|
|
- y_min = min(min(Y_test.iloc[:, 0]), min(y_pred))
|
|
|
|
- y_max = max(max(Y_test.iloc[:, 0]), max(y_pred))
|
|
|
|
-
|
|
|
|
- return jsonify({
|
|
|
|
- 'scatter_data': scatter_data,
|
|
|
|
- 'r2_score': float(r2),
|
|
|
|
- 'y_range': [float(y_min), float(y_max)],
|
|
|
|
- 'model_name': model.Model_name,
|
|
|
|
- 'model_type': model.Model_type
|
|
|
|
- }), 200
|
|
|
|
-
|
|
|
|
|
|
+ return jsonify({'error': 'Model not found'}), 404
|
|
|
|
+
|
|
|
|
+ # 更新模型状态(或其他切换逻辑)
|
|
|
|
+ # 假设此处是更新模型的某些字段来进行切换
|
|
|
|
+ model.status = 'active' # 假设有一个字段记录模型状态
|
|
|
|
+ session.commit()
|
|
|
|
+
|
|
|
|
+ # 记录切换日志
|
|
|
|
+ logger.info(f'Model {model_name} (ID: {model_id}) switched successfully.')
|
|
|
|
+
|
|
|
|
+ return jsonify({'success': True, 'message': f'Model {model_name} switched successfully!'}), 200
|
|
|
|
+
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- logger.error(f'获取模型散点图数据失败: {str(e)}', exc_info=True)
|
|
|
|
- return jsonify({'error': f'获取数据失败: {str(e)}'}), 500
|
|
|
|
-
|
|
|
|
|
|
+ logger.error('Failed to switch model:', exc_info=True)
|
|
|
|
+ return jsonify({'error': str(e)}), 400
|
|
finally:
|
|
finally:
|
|
- session.close()
|
|
|
|
|
|
+ if session:
|
|
|
|
+ session.close()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# 添加查看登录状态接口
|
|
|
|
+@bp.route('/getInfo', methods=['GET'])
|
|
|
|
+def getInfo_user():
|
|
|
|
+ name = session.get("name")
|
|
|
|
+ if name is not None:
|
|
|
|
+ return jsonify(name=name)
|
|
|
|
+ else:
|
|
|
|
+ return jsonify(msg="错误")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# 添加退出登录状态接口
|
|
|
|
+@bp.route('/logout', methods=['GET', 'POST'])
|
|
|
|
+def logout_user():
|
|
|
|
+ try:
|
|
|
|
+ session.clear()
|
|
|
|
+ return jsonify({"msg": "退出成功"}), 200
|
|
|
|
+ except Exception as e:
|
|
|
|
+ logger.error(f"Error during logout process: {e}", exc_info=True)
|
|
|
|
+ return jsonify({"msg": "退出失败"}), 500
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# 获取软件介绍信息的路由
|
|
|
|
+@bp.route('/software-intro/<int:id>', methods=['GET'])
|
|
|
|
+def get_software_intro(id):
|
|
|
|
+ try:
|
|
|
|
+ conn = get_db()
|
|
|
|
+ cursor = conn.cursor()
|
|
|
|
+ cursor.execute('SELECT title, intro FROM software_intro WHERE id = ?', (id,))
|
|
|
|
+ result = cursor.fetchone()
|
|
|
|
+ conn.close()
|
|
|
|
+
|
|
|
|
+ if result:
|
|
|
|
+ title, intro = result
|
|
|
|
+ return jsonify({
|
|
|
|
+ 'title': title,
|
|
|
|
+ 'intro': intro
|
|
|
|
+ })
|
|
|
|
+ return jsonify({}), 404
|
|
|
|
+ except sqlite3.Error as e:
|
|
|
|
+ print(f"数据库错误: {e}")
|
|
|
|
+ return jsonify({"error": f"数据库错误: {str(e)}"}), 500
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# 更新软件介绍信息的路由
|
|
|
|
+@bp.route('/software-intro/<int:id>', methods=['PUT'])
|
|
|
|
+def update_software_intro(id):
|
|
|
|
+ try:
|
|
|
|
+ data = request.get_json()
|
|
|
|
+ title = data.get('title')
|
|
|
|
+ intro = data.get('intro')
|
|
|
|
+
|
|
|
|
+ conn = get_db()
|
|
|
|
+ cursor = conn.cursor()
|
|
|
|
+ cursor.execute('UPDATE software_intro SET title =?, intro =? WHERE id = ?', (title, intro, id))
|
|
|
|
+ conn.commit()
|
|
|
|
+ conn.close()
|
|
|
|
+
|
|
|
|
+ return jsonify({'message': '软件介绍更新成功'})
|
|
|
|
+ except sqlite3.Error as e:
|
|
|
|
+ print(f"数据库错误: {e}")
|
|
|
|
+ return jsonify({"error": f"数据库错误: {str(e)}"}), 500
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# 处理图片上传的路由
|
|
|
|
+@bp.route('/upload-image', methods=['POST'])
|
|
|
|
+def upload_image():
|
|
|
|
+ file = request.files['image']
|
|
|
|
+ if file:
|
|
|
|
+ filename = str(uuid.uuid4()) + '.' + file.filename.rsplit('.', 1)[1].lower()
|
|
|
|
+ file.save(os.path.join(bp.config['UPLOAD_FOLDER'], filename))
|
|
|
|
+ imageUrl = f'http://127.0.0.1:5000/uploads/{filename}'
|
|
|
|
+ return jsonify({'imageUrl': imageUrl})
|
|
|
|
+ return jsonify({'error': '未找到图片文件'}), 400
|
|
|
|
+
|
|
|
|
+ # 配置静态资源服务
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@bp.route('/uploads/<path:filename>')
|
|
|
|
+def serve_image(filename):
|
|
|
|
+ uploads_folder = os.path.join(bp.root_path, 'uploads')
|
|
|
|
+ return send_from_directory(uploads_folder, filename)
|