|
@@ -573,6 +573,504 @@ def add_parse_task(files, task_type, created_by='system'):
|
|
|
error_msg = f"新增解析任务失败: {str(e)}"
|
|
|
logging.error(error_msg, exc_info=True)
|
|
|
|
|
|
+ return {
|
|
|
+ 'code': 500,
|
|
|
+ 'success': False,
|
|
|
+ 'message': error_msg,
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def add_single_talent(talent_data):
|
|
|
+ """
|
|
|
+ 添加单个人才记录(基于add_business_card逻辑,去除MinIO图片上传)
|
|
|
+
|
|
|
+ Args:
|
|
|
+ talent_data (dict): 人才信息数据
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ dict: 处理结果,包含保存的信息和状态
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 检查必要的数据
|
|
|
+ if not talent_data:
|
|
|
+ return {
|
|
|
+ 'code': 400,
|
|
|
+ 'success': False,
|
|
|
+ 'message': '人才数据不能为空',
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+ # 检查重复记录
|
|
|
+ try:
|
|
|
+ from app.core.data_parse.parse_system import check_duplicate_business_card
|
|
|
+ duplicate_check = check_duplicate_business_card(talent_data)
|
|
|
+ logging.info(f"重复记录检查结果: {duplicate_check['reason']}")
|
|
|
+ except Exception as e:
|
|
|
+ logging.error(f"重复记录检查失败: {str(e)}", exc_info=True)
|
|
|
+ # 如果检查失败,默认创建新记录
|
|
|
+ duplicate_check = {
|
|
|
+ 'is_duplicate': False,
|
|
|
+ 'action': 'create_new',
|
|
|
+ 'existing_card': None,
|
|
|
+ 'reason': f'重复检查失败,创建新记录: {str(e)}'
|
|
|
+ }
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 根据重复检查结果执行不同操作
|
|
|
+ if duplicate_check['action'] == 'update':
|
|
|
+ # 更新现有记录
|
|
|
+ existing_card = duplicate_check['existing_card']
|
|
|
+
|
|
|
+ # 导入手机号码处理函数
|
|
|
+ from app.core.data_parse.parse_system import normalize_mobile_numbers, merge_mobile_numbers
|
|
|
+
|
|
|
+ # 更新基本信息
|
|
|
+ existing_card.name_en = talent_data.get('name_en', existing_card.name_en)
|
|
|
+ existing_card.title_zh = talent_data.get('title_zh', existing_card.title_zh)
|
|
|
+ existing_card.title_en = talent_data.get('title_en', existing_card.title_en)
|
|
|
+
|
|
|
+ # 处理手机号码字段,支持多个手机号码
|
|
|
+ if 'mobile' in talent_data:
|
|
|
+ new_mobile = normalize_mobile_numbers(talent_data.get('mobile', ''))
|
|
|
+ if new_mobile:
|
|
|
+ # 如果有新的手机号码,合并到现有手机号码中
|
|
|
+ existing_card.mobile = merge_mobile_numbers(existing_card.mobile, new_mobile)
|
|
|
+ elif talent_data.get('mobile') == '':
|
|
|
+ # 如果明确传入空字符串,则清空手机号码
|
|
|
+ existing_card.mobile = ''
|
|
|
+
|
|
|
+ existing_card.phone = talent_data.get('phone', existing_card.phone)
|
|
|
+ existing_card.email = talent_data.get('email', existing_card.email)
|
|
|
+ existing_card.hotel_zh = talent_data.get('hotel_zh', existing_card.hotel_zh)
|
|
|
+ existing_card.hotel_en = talent_data.get('hotel_en', existing_card.hotel_en)
|
|
|
+ existing_card.address_zh = talent_data.get('address_zh', existing_card.address_zh)
|
|
|
+ existing_card.address_en = talent_data.get('address_en', existing_card.address_en)
|
|
|
+ existing_card.postal_code_zh = talent_data.get('postal_code_zh', existing_card.postal_code_zh)
|
|
|
+ existing_card.postal_code_en = talent_data.get('postal_code_en', existing_card.postal_code_en)
|
|
|
+ existing_card.brand_zh = talent_data.get('brand_zh', existing_card.brand_zh)
|
|
|
+ existing_card.brand_en = talent_data.get('brand_en', existing_card.brand_en)
|
|
|
+ existing_card.affiliation_zh = talent_data.get('affiliation_zh', existing_card.affiliation_zh)
|
|
|
+ existing_card.affiliation_en = talent_data.get('affiliation_en', existing_card.affiliation_en)
|
|
|
+
|
|
|
+ # 处理生日字段
|
|
|
+ if talent_data.get('birthday'):
|
|
|
+ try:
|
|
|
+ existing_card.birthday = datetime.strptime(talent_data.get('birthday'), '%Y-%m-%d').date()
|
|
|
+ except ValueError:
|
|
|
+ # 如果日期格式不正确,保持原值
|
|
|
+ pass
|
|
|
+
|
|
|
+ # 处理年龄字段
|
|
|
+ if 'age' in talent_data:
|
|
|
+ try:
|
|
|
+ if talent_data['age'] is not None and str(talent_data['age']).strip():
|
|
|
+ age_value = int(talent_data['age'])
|
|
|
+ if 0 < age_value <= 150: # 合理的年龄范围检查
|
|
|
+ existing_card.age = age_value
|
|
|
+ else:
|
|
|
+ existing_card.age = None
|
|
|
+ except (ValueError, TypeError):
|
|
|
+ # 如果年龄格式不正确,保持原值
|
|
|
+ pass
|
|
|
+
|
|
|
+ existing_card.native_place = talent_data.get('native_place', existing_card.native_place)
|
|
|
+ existing_card.residence = talent_data.get('residence', existing_card.residence)
|
|
|
+ existing_card.brand_group = talent_data.get('brand_group', existing_card.brand_group)
|
|
|
+ # 更新image_path字段,从talent_data中获取
|
|
|
+ existing_card.image_path = talent_data.get('image_path', existing_card.image_path)
|
|
|
+ existing_card.origin_source = talent_data.get('origin_source', existing_card.origin_source)
|
|
|
+ existing_card.talent_profile = talent_data.get('talent_profile', existing_card.talent_profile)
|
|
|
+ existing_card.updated_by = 'talent_system'
|
|
|
+
|
|
|
+ # 更新职业轨迹,传递从talent_data获取的图片路径
|
|
|
+ from app.core.data_parse.parse_system import update_career_path
|
|
|
+ image_path = talent_data.get('image_path', '')
|
|
|
+ existing_card.career_path = update_career_path(existing_card, talent_data, image_path)
|
|
|
+
|
|
|
+ db.session.commit()
|
|
|
+
|
|
|
+ logging.info(f"已更新现有人才记录,ID: {existing_card.id}")
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'code': 200,
|
|
|
+ 'success': True,
|
|
|
+ 'message': f'人才信息已更新。{duplicate_check["reason"]}',
|
|
|
+ 'data': existing_card.to_dict()
|
|
|
+ }
|
|
|
+
|
|
|
+ elif duplicate_check['action'] == 'create_with_duplicates':
|
|
|
+ # 创建新记录作为主记录,并保存疑似重复记录信息
|
|
|
+ from app.core.data_parse.parse_system import create_main_card_with_duplicates
|
|
|
+ main_card, duplicate_record = create_main_card_with_duplicates(
|
|
|
+ talent_data,
|
|
|
+ talent_data.get('image_path', ''), # 从talent_data获取图片路径
|
|
|
+ duplicate_check['suspected_duplicates'],
|
|
|
+ duplicate_check['reason']
|
|
|
+ )
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'code': 202, # Accepted,表示已接受但需要进一步处理
|
|
|
+ 'success': True,
|
|
|
+ 'message': f'创建新记录成功,发现疑似重复记录待处理。{duplicate_check["reason"]}',
|
|
|
+ 'data': {
|
|
|
+ 'main_card': main_card.to_dict(),
|
|
|
+ 'duplicate_record_id': duplicate_record.id,
|
|
|
+ 'suspected_duplicates_count': len(duplicate_check['suspected_duplicates']),
|
|
|
+ 'processing_status': 'pending',
|
|
|
+ 'duplicate_reason': duplicate_record.duplicate_reason,
|
|
|
+ 'created_at': duplicate_record.created_at.strftime('%Y-%m-%d %H:%M:%S')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ else:
|
|
|
+ # 创建新记录
|
|
|
+ # 准备初始职业轨迹,包含从talent_data获取的图片路径
|
|
|
+ image_path = talent_data.get('image_path', '')
|
|
|
+ initial_entry = {
|
|
|
+ 'date': datetime.now().strftime('%Y-%m-%d'),
|
|
|
+ 'hotel_zh': talent_data.get('hotel_zh', ''),
|
|
|
+ 'hotel_en': talent_data.get('hotel_en', ''),
|
|
|
+ 'title_zh': talent_data.get('title_zh', ''),
|
|
|
+ 'title_en': talent_data.get('title_en', ''),
|
|
|
+ 'image_path': image_path, # 从talent_data获取图片路径
|
|
|
+ 'source': 'talent_data_creation'
|
|
|
+ }
|
|
|
+ initial_career_path = [initial_entry]
|
|
|
+
|
|
|
+ # 导入手机号码处理函数和BusinessCard模型
|
|
|
+ from app.core.data_parse.parse_system import normalize_mobile_numbers, BusinessCard
|
|
|
+
|
|
|
+ # 处理年龄字段,确保是有效的整数或None
|
|
|
+ age_value = None
|
|
|
+ if talent_data.get('age'):
|
|
|
+ try:
|
|
|
+ age_value = int(talent_data.get('age'))
|
|
|
+ if age_value <= 0 or age_value > 150: # 合理的年龄范围检查
|
|
|
+ age_value = None
|
|
|
+ except (ValueError, TypeError):
|
|
|
+ age_value = None
|
|
|
+
|
|
|
+ business_card = BusinessCard(
|
|
|
+ name_zh=talent_data.get('name_zh', ''),
|
|
|
+ name_en=talent_data.get('name_en', ''),
|
|
|
+ title_zh=talent_data.get('title_zh', ''),
|
|
|
+ title_en=talent_data.get('title_en', ''),
|
|
|
+ mobile=normalize_mobile_numbers(talent_data.get('mobile', '')),
|
|
|
+ phone=talent_data.get('phone', ''),
|
|
|
+ email=talent_data.get('email', ''),
|
|
|
+ hotel_zh=talent_data.get('hotel_zh', ''),
|
|
|
+ hotel_en=talent_data.get('hotel_en', ''),
|
|
|
+ address_zh=talent_data.get('address_zh', ''),
|
|
|
+ address_en=talent_data.get('address_en', ''),
|
|
|
+ postal_code_zh=talent_data.get('postal_code_zh', ''),
|
|
|
+ postal_code_en=talent_data.get('postal_code_en', ''),
|
|
|
+ brand_zh=talent_data.get('brand_zh', ''),
|
|
|
+ brand_en=talent_data.get('brand_en', ''),
|
|
|
+ affiliation_zh=talent_data.get('affiliation_zh', ''),
|
|
|
+ affiliation_en=talent_data.get('affiliation_en', ''),
|
|
|
+ birthday=datetime.strptime(talent_data.get('birthday'), '%Y-%m-%d').date() if talent_data.get('birthday') else None,
|
|
|
+ age=age_value,
|
|
|
+ native_place=talent_data.get('native_place', ''),
|
|
|
+ residence=talent_data.get('residence', ''),
|
|
|
+ image_path=image_path, # 从talent_data获取图片路径
|
|
|
+ career_path=initial_career_path,
|
|
|
+ brand_group=talent_data.get('brand_group', ''),
|
|
|
+ origin_source=talent_data.get('origin_source'),
|
|
|
+ talent_profile=talent_data.get('talent_profile', ''),
|
|
|
+ status='active',
|
|
|
+ updated_by='talent_system'
|
|
|
+ )
|
|
|
+
|
|
|
+ db.session.add(business_card)
|
|
|
+ db.session.commit()
|
|
|
+
|
|
|
+ logging.info(f"人才信息已保存到数据库,ID: {business_card.id}")
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'code': 200,
|
|
|
+ 'success': True,
|
|
|
+ 'message': f'人才信息保存成功。{duplicate_check["reason"]}',
|
|
|
+ 'data': business_card.to_dict()
|
|
|
+ }
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ db.session.rollback()
|
|
|
+ error_msg = f"保存人才信息到数据库失败: {str(e)}"
|
|
|
+ logging.error(error_msg, exc_info=True)
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'code': 500,
|
|
|
+ 'success': False,
|
|
|
+ 'message': error_msg,
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ db.session.rollback()
|
|
|
+ error_msg = f"人才处理失败: {str(e)}"
|
|
|
+ logging.error(error_msg, exc_info=True)
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'code': 500,
|
|
|
+ 'success': False,
|
|
|
+ 'message': error_msg,
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def add_parsed_talents(api_response_data):
|
|
|
+ """
|
|
|
+ 处理execute-parse-task API响应数据,提取人才信息并写入business_cards表
|
|
|
+
|
|
|
+ Args:
|
|
|
+ api_response_data (dict): execute-parse-task API的返回数据
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ dict: 批量处理结果,格式与其他batch函数保持一致
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 验证参数
|
|
|
+ if not api_response_data or not isinstance(api_response_data, dict):
|
|
|
+ return {
|
|
|
+ 'code': 400,
|
|
|
+ 'success': False,
|
|
|
+ 'message': 'api_response_data参数必须是非空字典',
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+ # 检查API响应是否成功
|
|
|
+ if not api_response_data.get('success', False):
|
|
|
+ return {
|
|
|
+ 'code': 400,
|
|
|
+ 'success': False,
|
|
|
+ 'message': f"API响应表示处理失败: {api_response_data.get('message', '未知错误')}",
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+ # 获取data字段
|
|
|
+ response_data = api_response_data.get('data')
|
|
|
+ if not response_data or not isinstance(response_data, dict):
|
|
|
+ return {
|
|
|
+ 'code': 400,
|
|
|
+ 'success': False,
|
|
|
+ 'message': 'API响应中缺少有效的data字段',
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+ # 获取results数组
|
|
|
+ results = response_data.get('results', [])
|
|
|
+ if not isinstance(results, list):
|
|
|
+ return {
|
|
|
+ 'code': 400,
|
|
|
+ 'success': False,
|
|
|
+ 'message': 'API响应中的results字段必须是数组',
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(results) == 0:
|
|
|
+ return {
|
|
|
+ 'code': 400,
|
|
|
+ 'success': False,
|
|
|
+ 'message': 'API响应中的results数组为空,没有人才数据需要处理',
|
|
|
+ 'data': None
|
|
|
+ }
|
|
|
+
|
|
|
+ logging.info(f"开始处理API响应中的人才数据,共 {len(results)} 条记录")
|
|
|
+
|
|
|
+ processed_results = []
|
|
|
+ success_count = 0
|
|
|
+ failed_count = 0
|
|
|
+
|
|
|
+ # 逐一处理每个结果项
|
|
|
+ for i, result_item in enumerate(results):
|
|
|
+ try:
|
|
|
+ logging.debug(f"处理第 {i+1}/{len(results)} 条记录")
|
|
|
+
|
|
|
+ # 检查结果项是否成功
|
|
|
+ if not result_item.get('success', False):
|
|
|
+ failed_count += 1
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'success': False,
|
|
|
+ 'error': f"原始解析失败: {result_item.get('error', '未知错误')}",
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.warning(f"第 {i+1} 条记录原始解析失败,跳过处理")
|
|
|
+ continue
|
|
|
+
|
|
|
+ # 获取人才数据
|
|
|
+ item_data = result_item.get('data')
|
|
|
+ if not item_data:
|
|
|
+ failed_count += 1
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'success': False,
|
|
|
+ 'error': '结果项中缺少data字段',
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.warning(f"第 {i+1} 条记录缺少data字段")
|
|
|
+ continue
|
|
|
+
|
|
|
+ # 处理不同的数据格式
|
|
|
+ talent_data = None
|
|
|
+
|
|
|
+ # 检查是否是批量解析结果(如新任命等,包含多个人员)
|
|
|
+ if isinstance(item_data, dict):
|
|
|
+ if 'all_results' in item_data and isinstance(item_data['all_results'], list):
|
|
|
+ # 新任命等批量数据格式,包含多个人员
|
|
|
+ all_talents = item_data['all_results']
|
|
|
+ logging.info(f"第 {i+1} 条记录包含 {len(all_talents)} 个人员信息")
|
|
|
+
|
|
|
+ # 处理每个人员
|
|
|
+ for j, single_talent in enumerate(all_talents):
|
|
|
+ try:
|
|
|
+ talent_result = add_single_talent(single_talent)
|
|
|
+ if talent_result.get('success', False):
|
|
|
+ success_count += 1
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'sub_index': j,
|
|
|
+ 'success': True,
|
|
|
+ 'error': None,
|
|
|
+ 'data': talent_result.get('data'),
|
|
|
+ 'message': f'成功处理人员: {single_talent.get("name_zh", "未知")}'
|
|
|
+ })
|
|
|
+ logging.debug(f"成功处理第 {i+1} 条记录中的第 {j+1} 个人员")
|
|
|
+ else:
|
|
|
+ failed_count += 1
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'sub_index': j,
|
|
|
+ 'success': False,
|
|
|
+ 'error': talent_result.get('message', '处理失败'),
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.error(f"处理第 {i+1} 条记录中的第 {j+1} 个人员失败")
|
|
|
+ except Exception as talent_error:
|
|
|
+ failed_count += 1
|
|
|
+ error_msg = f"处理人员数据异常: {str(talent_error)}"
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'sub_index': j,
|
|
|
+ 'success': False,
|
|
|
+ 'error': error_msg,
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.error(error_msg, exc_info=True)
|
|
|
+ continue
|
|
|
+ else:
|
|
|
+ # 单个人员数据格式
|
|
|
+ talent_data = item_data
|
|
|
+ elif isinstance(item_data, list) and len(item_data) > 0:
|
|
|
+ # 如果是数组,取第一个元素
|
|
|
+ talent_data = item_data[0]
|
|
|
+ else:
|
|
|
+ failed_count += 1
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'success': False,
|
|
|
+ 'error': 'data字段格式不正确,无法识别人才数据',
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.warning(f"第 {i+1} 条记录data字段格式不正确")
|
|
|
+ continue
|
|
|
+
|
|
|
+ # 处理单个人才数据
|
|
|
+ if talent_data:
|
|
|
+ try:
|
|
|
+ talent_result = add_single_talent(talent_data)
|
|
|
+ if talent_result.get('success', False):
|
|
|
+ success_count += 1
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'success': True,
|
|
|
+ 'error': None,
|
|
|
+ 'data': talent_result.get('data'),
|
|
|
+ 'message': f'成功处理人员: {talent_data.get("name_zh", "未知")}'
|
|
|
+ })
|
|
|
+ logging.debug(f"成功处理第 {i+1} 条记录")
|
|
|
+ else:
|
|
|
+ failed_count += 1
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'success': False,
|
|
|
+ 'error': talent_result.get('message', '处理失败'),
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.error(f"处理第 {i+1} 条记录失败: {talent_result.get('message', '未知错误')}")
|
|
|
+ except Exception as talent_error:
|
|
|
+ failed_count += 1
|
|
|
+ error_msg = f"处理人才数据异常: {str(talent_error)}"
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'success': False,
|
|
|
+ 'error': error_msg,
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.error(error_msg, exc_info=True)
|
|
|
+
|
|
|
+ except Exception as item_error:
|
|
|
+ failed_count += 1
|
|
|
+ error_msg = f"处理结果项异常: {str(item_error)}"
|
|
|
+ processed_results.append({
|
|
|
+ 'index': i,
|
|
|
+ 'original_index': result_item.get('index', i),
|
|
|
+ 'success': False,
|
|
|
+ 'error': error_msg,
|
|
|
+ 'data': None
|
|
|
+ })
|
|
|
+ logging.error(error_msg, exc_info=True)
|
|
|
+
|
|
|
+ # 组装最终结果
|
|
|
+ batch_result = {
|
|
|
+ 'summary': {
|
|
|
+ 'total_files': len(results),
|
|
|
+ 'success_count': success_count,
|
|
|
+ 'failed_count': failed_count,
|
|
|
+ 'success_rate': round((success_count / len(results)) * 100, 2) if len(results) > 0 else 0,
|
|
|
+ 'original_summary': response_data.get('summary', {})
|
|
|
+ },
|
|
|
+ 'results': processed_results,
|
|
|
+ 'processed_time': datetime.now().isoformat(),
|
|
|
+ 'original_api_response': api_response_data # 保留原始API响应用于调试
|
|
|
+ }
|
|
|
+
|
|
|
+ if failed_count == 0:
|
|
|
+ return {
|
|
|
+ 'code': 200,
|
|
|
+ 'success': True,
|
|
|
+ 'message': f'批量处理完成,全部 {success_count} 条人才数据写入成功',
|
|
|
+ 'data': batch_result
|
|
|
+ }
|
|
|
+ elif success_count == 0:
|
|
|
+ return {
|
|
|
+ 'code': 500,
|
|
|
+ 'success': False,
|
|
|
+ 'message': f'批量处理失败,全部 {failed_count} 条人才数据写入失败',
|
|
|
+ 'data': batch_result
|
|
|
+ }
|
|
|
+ else:
|
|
|
+ return {
|
|
|
+ 'code': 206, # Partial Content
|
|
|
+ 'success': True,
|
|
|
+ 'message': f'批量处理部分成功,成功 {success_count} 条,失败 {failed_count} 条',
|
|
|
+ 'data': batch_result
|
|
|
+ }
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ error_msg = f"处理API响应数据失败: {str(e)}"
|
|
|
+ logging.error(error_msg, exc_info=True)
|
|
|
+
|
|
|
return {
|
|
|
'code': 500,
|
|
|
'success': False,
|