"""Import API routes for XLSX file import operations.""" from flask import request, send_file from flask_restx import Namespace, Resource, fields from werkzeug.datastructures import FileStorage from app.services.import_service import ImportService from app.utils.auth_decorator import require_auth import_ns = Namespace('import', description='数据导入接口') # File upload parser upload_parser = import_ns.parser() upload_parser.add_argument( 'file', location='files', type=FileStorage, required=True, help='XLSX文件' ) # Response models for Swagger documentation error_response = import_ns.model('ImportErrorResponse', { 'success': fields.Boolean(description='操作是否成功'), 'error': fields.String(description='错误信息'), 'errors': fields.List(fields.String, description='错误信息列表'), 'code': fields.String(description='错误代码') }) success_response = import_ns.model('ImportSuccessResponse', { 'success': fields.Boolean(description='操作是否成功'), 'count': fields.Integer(description='成功导入的记录数') }) @import_ns.route('/template') class ImportTemplate(Resource): """Resource for downloading import template.""" @import_ns.doc('download_template') @import_ns.response(200, 'XLSX模板文件下载') @import_ns.response(500, '服务器错误', error_response) @import_ns.produces(['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']) @require_auth def get(self): """下载导入模板 下载包含以下列的XLSX模板文件: - 人员姓名 - 物品名称 - 工作日期 (格式: YYYY-MM-DD) - 数量 Requirements: 3.6 """ try: template_file = ImportService.generate_template() return send_file( template_file, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', as_attachment=True, download_name='import_template.xlsx' ) except Exception as e: return { 'success': False, 'error': f'生成模板失败: {str(e)}', 'code': 'SERVER_ERROR' }, 500 @import_ns.route('/upload') class ImportUpload(Resource): """Resource for uploading and importing XLSX files.""" @import_ns.doc('upload_import') @import_ns.expect(upload_parser) @import_ns.response(200, '导入成功', success_response) @import_ns.response(400, '验证错误', error_response) @import_ns.response(500, '服务器错误', error_response) @require_auth def post(self): """上传并导入XLSX文件 上传XLSX文件并批量创建工作记录。 文件大小限制: 5MB 验证规则: - 文件必须是XLSX格式 - 必须包含所有必需列 - 人员姓名必须匹配系统中已存在的人员 - 物品名称必须匹配系统中已存在的物品 - 工作日期格式必须为 YYYY-MM-DD - 数量必须为正数 Requirements: 4.9, 4.11, 4.12 """ # Check if file is present if 'file' not in request.files: return { 'success': False, 'error': '请选择要上传的文件', 'code': 'VALIDATION_ERROR' }, 400 file = request.files['file'] # Check if file is selected if file.filename == '': return { 'success': False, 'error': '请选择要上传的文件', 'code': 'VALIDATION_ERROR' }, 400 # Check file extension if not file.filename.lower().endswith('.xlsx'): return { 'success': False, 'error': '文件格式错误,请上传XLSX文件', 'code': 'VALIDATION_ERROR' }, 400 # Read file content and check size file_content = file.read() # Validate file size (5MB limit) if len(file_content) > ImportService.MAX_FILE_SIZE: return { 'success': False, 'error': '文件大小超过限制(最大5MB)', 'code': 'VALIDATION_ERROR' }, 400 try: # Parse and validate file content valid_records, errors = ImportService.parse_and_validate(file_content) # If there are validation errors, return them (atomic operation - no records created) if errors: return { 'success': False, 'errors': errors, 'code': 'VALIDATION_ERROR' }, 400 # If no valid records found if not valid_records: return { 'success': False, 'error': '文件中没有有效的数据行', 'code': 'VALIDATION_ERROR' }, 400 # Import the validated records count = ImportService.import_records(valid_records) return { 'success': True, 'count': count }, 200 except Exception as e: return { 'success': False, 'error': f'导入失败: {str(e)}', 'code': 'SERVER_ERROR' }, 500