This commit is contained in:
ZhuJW
2026-07-10 18:55:55 +08:00
commit fce40c7d6c
317 changed files with 170079 additions and 0 deletions
@@ -0,0 +1,261 @@
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime, timedelta, timezone
from operator import or_
import os
import random
import string
import traceback
from flask import Blueprint, json, jsonify, current_app, request
from sqlalchemy.exc import SQLAlchemyError
from app.models import AccidList, DictItem, DictType, FileUpload
from app import db
file_uploads_bp = Blueprint("file_uploads_bp", __name__)
ALLOWED_EXTENSIONS={'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename):
"""验证图片格式是否合法"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def generate_file_alias(filename):
"""生成唯一存储别名(避免重名):时间戳+6位随机字符串+扩展名"""
ext = filename.rsplit('.', 1)[1].lower()
random_str = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
timestamp = int(datetime.now().timestamp())
return f"{timestamp}_{random_str}.{ext}"
# 接口1:图片上传(基础接口,返回文件ID)
@file_uploads_bp.route('/upload-image', methods=['POST'])
def upload_image():
"""
图片上传接口
- 请求方式:POST
- Content-Type: multipart/form-data
- 请求参数:
file: 图片文件(必传)
create_by: 上传人(可选,如admin
- 返回:文件ID、访问URL等信息
"""
try:
# 1. 校验文件是否存在
if 'file' not in request.files:
return jsonify({'code': 400, 'msg': '请选择要上传的图片', 'data': None}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'code': 400, 'msg': '文件名不能为空', 'data': None}), 400
# 2. 校验文件格式
if not allowed_file(file.filename):
return jsonify({
'code': 400,
'msg': f'仅支持{"/".join(ALLOWED_EXTENSIONS)}格式的图片',
'data': None
}), 400
# 3. 创建上传目录(不存在则自动创建)
os.makedirs(current_app.config['UPLOAD_FOLDER'], exist_ok=True)
# 4. 生成唯一别名并保存文件
file_alias = generate_file_alias(file.filename)
file_save_path = os.path.join(current_app.config['UPLOAD_FOLDER'], file_alias)
file.save(file_save_path)
# 5. 写入FileUpload表
file_size = os.path.getsize(file_save_path) # 获取文件大小(字节)
file_type = file.content_type # 获取MIME类型(如image/jpeg
create_by = request.form.get('create_by', None)
new_file = FileUpload(
file_name=file.filename,
file_alias=file_alias,
file_path=f"/uploads/{file_alias}", # 相对路径,前端拼接域名访问
file_size=file_size,
file_type=file_type,
create_by=create_by,
business_type='case', # 固定关联事故工单业务
business_id=None # 暂不关联具体工单,后续绑定
)
db.session.add(new_file)
db.session.commit()
# 6. 返回成功响应
return jsonify({
'code': 200,
'msg': '图片上传成功',
'data': new_file.to_dict()
}), 200
except Exception as e:
db.session.rollback() # 异常回滚
return jsonify({
'code': 500,
'msg': f'上传失败:{str(e)}',
'data': None
}), 500
# 接口2:绑定图片到事故工单
@file_uploads_bp.route('/bind-image', methods=['POST'])
def bind_image_to_case():
"""
绑定图片到事故工单(更新image_ids和business_id
- 请求方式:POST
- Content-Type: application/json
- 请求参数:
case_id: 事故工单ID(必传)
file_ids: 图片ID列表(如[1,2,3],必传)
"""
try:
data = request.get_json()
case_id = data.get('case_id')
file_ids = data.get('file_ids', [])
# 1. 校验参数
if not case_id or not isinstance(file_ids, list) or len(file_ids) == 0:
return jsonify({'code': 400, 'msg': '工单ID和图片ID列表不能为空', 'data': None}), 400
# 2. 检查工单是否存在
case = AccidList.query.get(case_id)
if not case:
return jsonify({'code': 404, 'msg': '事故工单不存在', 'data': None}), 404
# 3. 拼接图片ID串(去重)
existing_ids = case.image_ids.split(',') if case.image_ids.strip() else []
new_ids = list(set(existing_ids + [str(fid) for fid in file_ids])) # 去重
case.image_ids = ','.join(new_ids)
case.update_at = db.func.current_timestamp() # 更新工单修改时间
# 4. 更新FileUpload的business_id(关联具体工单)
FileUpload.query.filter(
FileUpload.id.in_(file_ids),
FileUpload.business_type == 'case'
).update({'business_id': case_id}, synchronize_session=False)
db.session.commit()
# 5. 返回结果
return jsonify({
'code': 200,
'msg': '图片绑定成功',
'data': {
'case_id': case_id,
'image_ids': case.image_ids,
'image_count': len(new_ids)
}
}), 200
except Exception as e:
db.session.rollback()
return jsonify({
'code': 500,
'msg': f'绑定失败:{str(e)}',
'data': None
}), 500
# 接口3:查询事故工单关联的图片
@file_uploads_bp.route('/get-images/<int:case_id>', methods=['GET'])
def get_case_images(case_id):
"""
查询工单关联的所有有效图片
- 请求方式:GET
- 路径参数:case_id - 事故工单ID
"""
try:
# 1. 检查工单是否存在
case = AccidList.query.get(case_id)
if not case:
return jsonify({'code': 404, 'msg': '事故工单不存在', 'data': None}), 404
# 2. 拆分图片ID并查询
image_ids = case.image_ids.split(',') if case.image_ids.strip() else []
if not image_ids:
return jsonify({'code': 200, 'msg': '暂无关联图片', 'data': []}), 200
# 3. 查询有效图片(status=1
images = FileUpload.query.filter(
FileUpload.id.in_(image_ids),
FileUpload.status == 1
).all()
# ========== 核心修改:拼接完整图片URL ==========
image_base_url = current_app.config['IMAGE_BASE_URL'] # 获取配置的基础URL
image_data = []
for img in images:
img_dict = img.to_dict() # 原有模型的to_dict方法
# 把相对路径拼接成完整URL(覆盖原有file_path
img_dict['file_path'] = f"{image_base_url}{img_dict['file_path']}"
image_data.append(img_dict)
# 4. 返回结果(改用拼接后的image_data)
return jsonify({
'code': 200,
'msg': '查询成功',
'data': image_data # 现在data里的file_path是完整URL
}), 200
except Exception as e:
return jsonify({
'code': 500,
'msg': f'查询失败:{str(e)}',
'data': None
}), 500
# 接口4:移除工单关联的图片(逻辑删除)
@file_uploads_bp.route('/remove-image', methods=['POST'])
def remove_case_image():
"""
移除工单关联的图片(逻辑删除)
- 请求方式:POST
- Content-Type: application/json
- 请求参数:
case_id: 工单ID(必传)
file_id: 图片ID(必传)
"""
try:
data = request.get_json()
case_id = data.get('case_id')
file_id = data.get('file_id')
# 1. 校验参数
if not case_id or not file_id:
return jsonify({'code': 400, 'msg': '工单ID和图片ID不能为空', 'data': None}), 400
# 2. 检查工单和图片是否存在
case = AccidList.query.get(case_id)
file = FileUpload.query.get(file_id)
if not case:
return jsonify({'code': 404, 'msg': '事故工单不存在', 'data': None}), 404
if not file:
return jsonify({'code': 404, 'msg': '图片不存在', 'data': None}), 404
# 3. 移除工单的image_ids中的该ID
existing_ids = case.image_ids.split(',') if case.image_ids.strip() else []
if str(file_id) in existing_ids:
existing_ids.remove(str(file_id))
case.image_ids = ','.join(existing_ids)
case.update_at = db.func.current_timestamp()
# 4. 逻辑删除图片(status=0
file.status = 0
db.session.commit()
return jsonify({
'code': 200,
'msg': '图片移除成功',
'data': {'case_id': case_id, 'file_id': file_id}
}), 200
except Exception as e:
db.session.rollback()
return jsonify({
'code': 500,
'msg': f'移除失败:{str(e)}',
'data': None
}), 500