浏览代码

清除data_parse接口里一些没有再使用的接口。
新增解析任务管理API接口说明文档。

hedpma 1 天之前
父节点
当前提交
5a1c2be79b
共有 2 个文件被更改,包括 1597 次插入507 次删除
  1. 7 507
      app/api/data_parse/routes.py
  2. 1590 0
      解析任务管理API接口说明文档.md

+ 7 - 507
app/api/data_parse/routes.py

@@ -38,10 +38,10 @@ from app.core.data_parse.hotel_management import (
     query_hotel_group_brands, 
     delete_hotel_group_brands
 )
-# 导入新的名片图片解析函数和添加名片函数
-from app.core.data_parse.parse_card import process_business_card_image, add_business_card, delete_business_card, batch_process_business_card_images
+# 导入名片处理函数
+from app.core.data_parse.parse_card import delete_business_card, batch_process_business_card_images
 # 导入网页文本解析函数
-from app.core.data_parse.parse_web import process_webpage_with_QWen, add_webpage_talent, batch_process_md
+from app.core.data_parse.parse_web import batch_process_md
 # 导入简历解析函数
 from app.core.data_parse.parse_resume import batch_parse_resumes
 # 导入门墩儿数据处理函数
@@ -92,139 +92,6 @@ def get_minio_client():
         secure=config.MINIO_SECURE
     )
 
-# 名片解析接口
-@bp.route('/business-card-parse', methods=['POST'])
-def parse_business_card_route():
-    """
-    解析名片图片并提取信息的API接口(仅解析,不保存到数据库)
-    
-    请求参数:
-        - image: 名片图片文件 (multipart/form-data)
-        
-    返回:
-        - JSON: 包含提取的名片信息和处理状态
-        
-    注意:此接口仅负责图片解析和信息提取,不会将数据保存到数据库
-    """
-    # 检查是否上传了文件
-    if 'image' not in request.files:
-        return jsonify({
-            'success': False,
-            'message': '未上传图片',
-            'data': None
-        }), 400
-    
-    image_file = request.files['image']
-    
-    # 检查文件是否为空
-    if image_file.filename == '':
-        return jsonify({
-            'success': False,
-            'message': '未选择文件',
-            'data': None
-        }), 400
-    
-    # 检查文件类型是否为图片
-    if not image_file.content_type.startswith('image/'):
-        return jsonify({
-            'success': False,
-            'message': '上传的文件不是图片',
-            'data': None
-        }), 400
-    
-    # 处理名片图片
-    result = process_business_card_image(image_file)
-    
-    if result['success']:
-        return jsonify(result), 200
-    else:
-        return jsonify(result), 500
-
-# 添加名片记录接口
-@bp.route('/add-business-card', methods=['POST'])
-def add_business_card_route():
-    """
-    添加名片记录的API接口(解析图片并保存到数据库)
-    
-    请求参数:
-        - card_data: 名片信息数据 (JSON格式,可以通过form-data或JSON body传递)
-        - image: 名片图片文件 (multipart/form-data,可选)
-        
-    返回:
-        - JSON: 包含保存结果和处理状态
-        
-    注意:此接口负责业务逻辑处理,包括重复检查、MinIO上传和数据库保存
-    """
-    try:
-        # 获取名片数据 - 支持两种方式
-        card_data = None
-        
-        # 方式1:通过JSON body传递
-        if request.is_json:
-            card_data = request.get_json()
-        # 方式2:通过form-data传递card_data字段
-        elif 'card_data' in request.form:
-            import json
-            try:
-                card_data = json.loads(request.form['card_data'])
-            except json.JSONDecodeError:
-                return jsonify({
-                    'success': False,
-                    'message': 'card_data格式错误,必须是有效的JSON字符串',
-                    'data': None
-                }), 400
-        
-        # 检查是否提供了名片数据
-        if not card_data:
-            return jsonify({
-                'success': False,
-                'message': '未提供名片数据,请通过JSON body或form-data的card_data字段传递',
-                'data': None
-            }), 400
-        
-        # 获取可选的图片文件
-        image_file = None
-        if 'image' in request.files:
-            image_file = request.files['image']
-            
-            # 检查文件是否为空
-            if image_file.filename == '':
-                image_file = None
-            # 检查文件类型是否为图片
-            elif not image_file.content_type.startswith('image/'):
-                return jsonify({
-                    'success': False,
-                    'message': '上传的文件不是图片',
-                    'data': None
-                }), 400
-        
-        # 调用业务逻辑函数处理名片数据
-        result = add_business_card(card_data, image_file)
-        
-        # 根据处理结果设置HTTP状态码
-        if result['success']:
-            if result['code'] == 200:
-                status_code = 200
-            elif result['code'] == 202:
-                status_code = 202  # Accepted - 创建成功但有疑似重复记录
-            else:
-                status_code = 200
-        else:
-            if result['code'] == 400:
-                status_code = 400
-            else:
-                status_code = 500
-        
-        return jsonify(result), status_code
-        
-    except Exception as e:
-        logger.error(f"添加名片记录失败: {str(e)}")
-        return jsonify({
-            'success': False,
-            'message': f'添加名片记录失败: {str(e)}',
-            'data': None
-        }), 500
-
 # 更新名片信息接口
 @bp.route('/business-cards/<int:card_id>', methods=['PUT'])
 def update_business_card_route(card_id):
@@ -659,67 +526,9 @@ def talent_update_tags_route():
             'data': None
         }), 500
 
-# 测试MinIO连接
-def test_minio_connection():
-    """测试MinIO连接是否正常"""
-    try:
-        client = get_minio_client()
-        if client.bucket_exists(minio_bucket):
-            return {
-                'success': True,
-                'message': f'连接MinIO服务器成功,存储桶 {minio_bucket} 存在',
-                'config': {
-                    'host': config.MINIO_HOST,
-                    'bucket': minio_bucket,
-                    'secure': use_ssl
-                }
-            }
-        else:
-            return {
-                'success': False,
-                'message': f'连接MinIO服务器成功,但存储桶 {minio_bucket} 不存在',
-                'config': {
-                    'host': config.MINIO_HOST,
-                    'bucket': minio_bucket,
-                    'secure': use_ssl
-                }
-            }
-    except Exception as e:
-        return {
-            'success': False,
-            'message': f'连接MinIO服务器失败: {str(e)}',
-            'config': {
-                'host': config.MINIO_HOST,
-                'bucket': minio_bucket,
-                'secure': use_ssl
-            }
-        }
 
-# MinIO测试接口
-@bp.route('/test-minio-connection', methods=['GET'])
-def test_minio_connection_route():
-    """
-    测试MinIO连接的API接口
-    
-    返回:
-        - JSON: 包含连接测试结果
-    """
-    try:
-        result = test_minio_connection()
-        status_code = 200 if result['success'] else 500
-        return jsonify(result), status_code
-        
-    except Exception as e:
-        logger.error(f"测试MinIO连接失败: {str(e)}")
-        return jsonify({
-            'success': False,
-            'message': f'测试MinIO连接失败: {str(e)}',
-            'config': {
-                'host': config.MINIO_HOST,
-                'bucket': minio_bucket,
-                'secure': use_ssl
-            }
-        }), 500
+
+
 
 # 获取单个名片记录的API接口
 @bp.route('/get-business-card/<int:card_id>', methods=['GET'])
@@ -1518,318 +1327,9 @@ def fix_broken_duplicate_records_route():
         }), 500
 
 
-# 网页文本解析接口
-@bp.route('/webpage-parse', methods=['POST'])
-def webpage_parse_route():
-    """
-    解析网页 Markdown 文本并提取人员信息的API接口
-    
-    请求参数:
-        - markdown_text: 网页的 Markdown 格式文本内容 (JSON格式)
-        - publish_time: 发布时间,用于career_path中的date字段 (JSON格式)
-        
-    请求体示例:
-        {
-            "markdown_text": "# 张三\n\n职位:高级经理\n\n公司:XX酒店\n\n![照片](http://example.com/photo.jpg)",
-            "publish_time": "2025-01-15"
-        }
-        
-    返回:
-        - JSON: 包含提取的人员信息和处理状态
-        
-    功能说明:
-        - 接收 Markdown 格式的网页文本
-        - 进行必要的格式和内容验证
-        - 使用 Qwen VL Max 模型提取人员信息
-        - 支持提取照片链接 (pic_url)
-        - 返回标准化的人员信息数据
-        
-    状态码:
-        - 200: 解析成功
-        - 400: 请求参数错误
-        - 500: 解析失败
-    """
-    try:
-        # 检查请求是否为 JSON 格式
-        if not request.is_json:
-            return jsonify({
-                'success': False,
-                'message': '请求必须是 JSON 格式',
-                'data': None
-            }), 400
-        
-        # 获取请求数据
-        data = request.get_json()
-        
-        # 检查是否提供了 markdown_text 参数
-        if 'markdown_text' not in data:
-            return jsonify({
-                'success': False,
-                'message': '缺少必填参数: markdown_text',
-                'data': None
-            }), 400
-        
-        # 检查是否提供了 publish_time 参数
-        if 'publish_time' not in data:
-            return jsonify({
-                'success': False,
-                'message': '缺少必填参数: publish_time',
-                'data': None
-            }), 400
-        
-        markdown_text = data['markdown_text']
-        publish_time = data['publish_time']
-        
-        # 验证 markdown_text 是否为字符串
-        if not isinstance(markdown_text, str):
-            return jsonify({
-                'success': False,
-                'message': 'markdown_text 必须是字符串类型',
-                'data': None
-            }), 400
-        
-        # 验证 publish_time 是否为字符串
-        if not isinstance(publish_time, str):
-            return jsonify({
-                'success': False,
-                'message': 'publish_time 必须是字符串类型',
-                'data': None
-            }), 400
-        
-        # 验证文本内容不能为空
-        if not markdown_text.strip():
-            return jsonify({
-                'success': False,
-                'message': 'markdown_text 内容不能为空',
-                'data': None
-            }), 400
-        
-        # 验证文本长度(防止过长的文本)
-        if len(markdown_text) > 50000:  # 限制最大50KB
-            return jsonify({
-                'success': False,
-                'message': 'markdown_text 内容过长,最大支持50KB',
-                'data': None
-            }), 400
-        
-        # 基本的 Markdown 格式验证(可选)
-        # 检查是否包含一些基本的文本内容
-        if len(markdown_text.strip()) < 10:
-            return jsonify({
-                'success': False,
-                'message': 'markdown_text 内容过短,无法进行有效解析',
-                'data': None
-            }), 400
-        
-        # 记录解析请求
-        logger.info(f"开始解析网页文本,内容长度: {len(markdown_text)} 字符")
-        
-        # 调用网页文本解析函数
-        extracted_data = process_webpage_with_QWen(markdown_text, publish_time)
-        
-        # 返回成功结果
-        return jsonify({
-            'success': True,
-            'message': '网页文本解析成功',
-            'data': extracted_data
-        }), 200
-        
-    except Exception as e:
-        # 记录错误日志
-        error_msg = f"网页文本解析失败: {str(e)}"
-        logger.error(error_msg, exc_info=True)
-        
-        # 返回错误响应
-        return jsonify({
-            'success': False,
-            'message': error_msg,
-            'data': None
-        }), 500
 
-# 添加网页人才信息接口
-@bp.route('/add-webpage-talent', methods=['POST'])
-def add_webpage_talent_route():
-    """
-    添加网页人才信息的API接口,包括保存网页内容和创建名片记录
-    
-    请求参数:
-        - talent_list: 人才信息列表,每个item包含业务卡片格式的数据 (JSON数组)
-        - web_md: 网页markdown文本内容 (JSON字符串)
-        
-    请求体示例:
-        {
-            "talent_list": [
-                {
-                    "name_zh": "张三",
-                    "name_en": "Zhang San",
-                    "title_zh": "总经理",
-                    "title_en": "General Manager",
-                    "hotel_zh": "北京万豪酒店",
-                    "hotel_en": "Beijing Marriott Hotel",
-                    "brand_group": "万豪",
-                    "mobile": "13800138000",
-                    "email": "zhangsan@example.com"
-                },
-                {
-                    "name_zh": "李四",
-                    "name_en": "Li Si",
-                    "title_zh": "市场总监",
-                    "title_en": "Marketing Director",
-                    "hotel_zh": "上海希尔顿酒店",
-                    "hotel_en": "Shanghai Hilton Hotel",
-                    "brand_group": "希尔顿",
-                    "mobile": "13900139000",
-                    "email": "lisi@example.com"
-                }
-            ],
-            "web_md": "# 人事任命公告\n\n**1** 张三被任命为北京万豪酒店总经理...\n\n**2** 李四被任命为上海希尔顿酒店市场总监..."
-        }
-        
-    返回:
-        - JSON: 包含处理结果,包括成功和失败的记录统计
-        
-    功能说明:
-        - 将网页markdown内容保存到MinIO
-        - 循环处理talent_list中的每个人才记录
-        - 为每个人才创建business_card记录
-        - 使用与名片上传相同的重复检查逻辑
-        - 在business_card记录的updated_by字段中记录MinIO路径
-        
-    状态码:
-        - 200: 所有记录处理成功
-        - 206: 部分记录处理成功
-        - 400: 请求参数错误
-        - 500: 处理失败
-    """
-    try:
-        # 检查请求是否为 JSON 格式
-        if not request.is_json:
-            return jsonify({
-                'success': False,
-                'message': '请求必须是 JSON 格式',
-                'data': None
-            }), 400
-        
-        # 获取请求数据
-        data = request.get_json()
-        
-        # 检查是否提供了 talent_list 参数
-        if 'talent_list' not in data:
-            return jsonify({
-                'success': False,
-                'message': '缺少必填参数: talent_list',
-                'data': None
-            }), 400
-        
-        # 检查是否提供了 web_md 参数
-        if 'web_md' not in data:
-            return jsonify({
-                'success': False,
-                'message': '缺少必填参数: web_md',
-                'data': None
-            }), 400
-        
-        talent_list = data['talent_list']
-        web_md = data['web_md']
-        
-        # 验证 talent_list 是否为数组
-        if not isinstance(talent_list, list):
-            return jsonify({
-                'success': False,
-                'message': 'talent_list 必须是数组类型',
-                'data': None
-            }), 400
-        
-        # 验证 web_md 是否为字符串
-        if not isinstance(web_md, str):
-            return jsonify({
-                'success': False,
-                'message': 'web_md 必须是字符串类型',
-                'data': None
-            }), 400
-        
-        # 验证数组不能为空
-        if len(talent_list) == 0:
-            return jsonify({
-                'success': False,
-                'message': 'talent_list 不能为空数组',
-                'data': None
-            }), 400
-        
-        # 验证文本内容不能为空
-        if not web_md.strip():
-            return jsonify({
-                'success': False,
-                'message': 'web_md 内容不能为空',
-                'data': None
-            }), 400
-        
-        # 验证文本长度(防止过长的文本)
-        if len(web_md) > 100000:  # 限制最大100KB
-            return jsonify({
-                'success': False,
-                'message': 'web_md 内容过长,最大支持100KB',
-                'data': None
-            }), 400
-        
-        # 验证数组长度(防止过多记录)
-        if len(talent_list) > 50:  # 限制最大50条记录
-            return jsonify({
-                'success': False,
-                'message': 'talent_list 记录过多,最大支持50条记录',
-                'data': None
-            }), 400
-        
-        # 基本的数据格式验证
-        for index, talent_data in enumerate(talent_list):
-            if not isinstance(talent_data, dict):
-                return jsonify({
-                    'success': False,
-                    'message': f'talent_list 第{index + 1}项必须是对象类型',
-                    'data': None
-                }), 400
-            
-            # 检查必要的字段
-            if not talent_data.get('name_zh'):
-                return jsonify({
-                    'success': False,
-                    'message': f'talent_list 第{index + 1}项缺少必填字段: name_zh',
-                    'data': None
-                }), 400
-        
-        # 记录处理请求
-        logger.info(f"开始处理网页人才信息,人才数量: {len(talent_list)}, 网页内容长度: {len(web_md)} 字符")
-        
-        # 调用网页人才处理函数
-        result = add_webpage_talent(talent_list, web_md)
-        
-        # 根据处理结果设置HTTP状态码
-        if result['success']:
-            if result['code'] == 200:
-                status_code = 200  # 全部成功
-            elif result['code'] == 206:
-                status_code = 206  # 部分成功
-            else:
-                status_code = 200  # 默认成功
-        else:
-            if result['code'] == 400:
-                status_code = 400  # 参数错误
-            else:
-                status_code = 500  # 服务器错误
-        
-        return jsonify(result), status_code
-        
-    except Exception as e:
-        # 记录错误日志
-        error_msg = f"添加网页人才信息失败: {str(e)}"
-        logger.error(error_msg, exc_info=True)
-        
-        # 返回错误响应
-        return jsonify({
-            'success': False,
-            'message': error_msg,
-            'data': None
-        }), 500
+
+
 
 
 # 获取解析任务列表接口

+ 1590 - 0
解析任务管理API接口说明文档.md

@@ -0,0 +1,1590 @@
+# 解析任务管理类API接口操作说明文档
+
+> **版本**: v1.0  
+> **更新时间**: 2025-01-18  
+> **适用对象**: 前端开发工程师  
+
+## 📋 目录
+
+1. [接口概览](#接口概览)
+2. [通用说明](#通用说明)
+3. [接口详细说明](#接口详细说明)
+   - [1. 获取解析任务列表](#1-获取解析任务列表)
+   - [2. 获取解析任务详情](#2-获取解析任务详情)
+   - [3. 新增解析任务](#3-新增解析任务)
+   - [4. 执行解析任务](#4-执行解析任务)
+   - [5. 处理解析结果](#5-处理解析结果)
+4. [前端集成示例](#前端集成示例)
+5. [错误处理](#错误处理)
+6. [最佳实践](#最佳实践)
+
+---
+
+## 接口概览
+
+| 序号 | 接口名称 | HTTP方法 | 接口路径 | 功能描述 |
+|------|----------|----------|----------|----------|
+| 1 | 获取解析任务列表 | GET | `/api/data-parse/get-parse-tasks` | 分页查询解析任务列表,支持过滤 |
+| 2 | 获取解析任务详情 | GET | `/api/data-parse/get-parse-task-detail` | 根据任务名称获取详细信息 |
+| 3 | 新增解析任务 | POST | `/api/data-parse/add-parse-task` | 创建新的解析任务并上传文件 |
+| 4 | 执行解析任务 | POST | `/api/data-parse/execute-parse-task` | 执行指定的批量解析任务 |
+| 5 | 处理解析结果 | POST | `/api/data-parse/add-parsed-talents` | 将解析结果写入人才数据库 |
+
+---
+
+## 通用说明
+
+### 🌐 服务器信息
+- **开发环境**: `http://localhost:5000`
+- **生产环境**: `http://192.168.3.143:5000`
+- **API前缀**: `/api/data-parse`
+
+### 🔒 认证方式
+- 当前版本暂无认证要求
+- 后续版本可能需要Bearer Token
+
+### 📊 响应格式
+所有接口均返回统一的JSON格式:
+
+```json
+{
+  "success": boolean,      // 请求是否成功
+  "message": string,       // 响应消息
+  "data": object | null    // 响应数据
+}
+```
+
+### 📋 任务类型说明
+
+| 任务类型 | 代码值 | 支持文件格式 | 存储目录 | 说明 |
+|----------|--------|--------------|----------|------|
+| 名片 | `"名片"` | JPG, PNG | `talent_photos/` | 名片图片解析 |
+| 简历 | `"简历"` | PDF | `resume_files/` | 简历文档解析 |
+| 新任命 | `"新任命"` | MD | `appointment_files/` | 任命文档解析 |
+| 招聘 | `"招聘"` | 无需文件 | 无 | 数据库记录处理 |
+| 杂项 | `"杂项"` | 任意格式 | `misc_files/` | 其他类型文件 |
+
+---
+
+## 接口详细说明
+
+### 1. 获取解析任务列表
+
+#### 📝 基本信息
+- **接口路径**: `GET /api/data-parse/get-parse-tasks`
+- **功能**: 分页查询解析任务列表,支持按任务类型和状态过滤
+- **内容类型**: `application/json`
+
+#### 📥 请求参数
+
+| 参数名 | 类型 | 必填 | 默认值 | 说明 | 示例值 |
+|--------|------|------|--------|------|--------|
+| `page` | integer | 否 | 1 | 页码,从1开始 | `1` |
+| `per_page` | integer | 否 | 10 | 每页记录数,最大100 | `20` |
+| `task_type` | string | 否 | - | 任务类型过滤 | `"名片"` |
+| `task_status` | string | 否 | - | 任务状态过滤 | `"待解析"` |
+
+#### 📤 响应结果
+
+```json
+{
+  "success": true,
+  "message": "获取解析任务列表成功",
+  "data": {
+    "tasks": [
+      {
+        "id": 123,
+        "task_name": "parse_task_20250118_a1b2c3d4",
+        "task_status": "待解析",
+        "task_type": "名片",
+        "task_source": {
+          "minio_paths_json": [
+            "talent_photos/talent_photo_20250118_143012_a1b2c3d4.jpg"
+          ],
+          "upload_time": "2025-01-18T14:30:25.123456"
+        },
+        "collection_count": 5,
+        "parse_count": 0,
+        "parse_result": null,
+        "created_at": "2025-01-18 14:30:25",
+        "created_by": "api_user",
+        "updated_at": "2025-01-18 14:30:25",
+        "updated_by": "api_user"
+      }
+    ],
+    "pagination": {
+      "page": 1,
+      "per_page": 10,
+      "total": 25,
+      "pages": 3,
+      "has_next": true,
+      "has_prev": false
+    }
+  }
+}
+```
+
+#### 🎯 前端调用示例
+
+```javascript
+// 使用fetch API
+async function getParseTaskList(page = 1, perPage = 10, taskType = null, taskStatus = null) {
+  const params = new URLSearchParams();
+  params.append('page', page);
+  params.append('per_page', perPage);
+  if (taskType) params.append('task_type', taskType);
+  if (taskStatus) params.append('task_status', taskStatus);
+  
+  try {
+    const response = await fetch(`/api/data-parse/get-parse-tasks?${params}`, {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+      }
+    });
+    
+    const result = await response.json();
+    
+    if (result.success) {
+      console.log('任务列表获取成功:', result.data);
+      return result.data;
+    } else {
+      console.error('获取失败:', result.message);
+      throw new Error(result.message);
+    }
+  } catch (error) {
+    console.error('请求异常:', error);
+    throw error;
+  }
+}
+
+// 使用示例
+getParseTaskList(1, 20, '名片', '待解析')
+  .then(data => {
+    console.log('总任务数:', data.pagination.total);
+    console.log('任务列表:', data.tasks);
+  })
+  .catch(error => {
+    console.error('获取任务列表失败:', error);
+  });
+```
+
+#### 📊 状态码说明
+
+| HTTP状态码 | 业务状态 | 说明 |
+|------------|----------|------|
+| 200 | success: true | 查询成功 |
+| 400 | success: false | 请求参数错误 |
+| 500 | success: false | 服务器内部错误 |
+
+---
+
+### 2. 获取解析任务详情
+
+#### 📝 基本信息
+- **接口路径**: `GET /api/data-parse/get-parse-task-detail`
+- **功能**: 根据任务名称获取解析任务的详细信息
+- **内容类型**: `application/json`
+
+#### 📥 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 | 示例值 |
+|--------|------|------|------|--------|
+| `task_name` | string | 是 | 任务名称 | `"parse_task_20250118_a1b2c3d4"` |
+
+#### 📤 响应结果
+
+```json
+{
+  "success": true,
+  "message": "成功获取任务 parse_task_20250118_a1b2c3d4 的详细信息",
+  "data": {
+    "id": 123,
+    "task_name": "parse_task_20250118_a1b2c3d4",
+    "task_status": "解析完成",
+    "task_type": "名片",
+    "task_source": {
+      "minio_paths_json": [
+        "talent_photos/talent_photo_20250118_143012_a1b2c3d4.jpg",
+        "talent_photos/talent_photo_20250118_143015_b2c3d4e5.jpg"
+      ],
+      "upload_time": "2025-01-18T14:30:25.123456"
+    },
+    "collection_count": 2,
+    "parse_count": 2,
+    "parse_result": {
+      "summary": {
+        "total_files": 2,
+        "success_count": 2,
+        "failed_count": 0,
+        "success_rate": 100.0
+      },
+      "results": [
+        {
+          "index": 0,
+          "success": true,
+          "data": {
+            "name_zh": "张三",
+            "title_zh": "技术总监",
+            "hotel_zh": "北京万豪酒店",
+            "mobile": "13800138000",
+            "email": "zhangsan@marriott.com"
+          }
+        }
+      ]
+    },
+    "created_at": "2025-01-18 14:30:25",
+    "created_by": "api_user",
+    "updated_at": "2025-01-18 15:45:30",
+    "updated_by": "system"
+  }
+}
+```
+
+#### 🎯 前端调用示例
+
+```javascript
+// 使用fetch API
+async function getParseTaskDetail(taskName) {
+  if (!taskName) {
+    throw new Error('任务名称不能为空');
+  }
+  
+  const params = new URLSearchParams();
+  params.append('task_name', taskName);
+  
+  try {
+    const response = await fetch(`/api/data-parse/get-parse-task-detail?${params}`, {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+      }
+    });
+    
+    const result = await response.json();
+    
+    if (result.success) {
+      console.log('任务详情获取成功:', result.data);
+      return result.data;
+    } else {
+      console.error('获取失败:', result.message);
+      throw new Error(result.message);
+    }
+  } catch (error) {
+    console.error('请求异常:', error);
+    throw error;
+  }
+}
+
+// 使用示例
+getParseTaskDetail('parse_task_20250118_a1b2c3d4')
+  .then(taskDetail => {
+    console.log('任务状态:', taskDetail.task_status);
+    console.log('解析结果:', taskDetail.parse_result);
+  })
+  .catch(error => {
+    console.error('获取任务详情失败:', error);
+  });
+```
+
+#### 📊 状态码说明
+
+| HTTP状态码 | 业务状态 | 说明 |
+|------------|----------|------|
+| 200 | success: true | 查询成功 |
+| 400 | success: false | 请求参数错误 |
+| 404 | success: false | 任务不存在 |
+| 500 | success: false | 服务器内部错误 |
+
+---
+
+### 3. 新增解析任务
+
+#### 📝 基本信息
+- **接口路径**: `POST /api/data-parse/add-parse-task`
+- **功能**: 创建新的解析任务并上传文件到MinIO存储
+- **内容类型**: `multipart/form-data`
+
+#### 📥 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 | 示例值 |
+|--------|------|------|------|--------|
+| `task_type` | string | 是 | 任务类型 | `"名片"` |
+| `files` | File[] | 否* | 文件数组 | `[file1.jpg, file2.png]` |
+| `created_by` | string | 否 | 创建者 | `"frontend_user"` |
+
+> **注意**: 除"招聘"类型外,其他类型必须上传文件
+
+#### 📤 响应结果
+
+```json
+{
+  "success": true,
+  "message": "解析任务创建成功,所有文件上传完成",
+  "data": {
+    "task_info": {
+      "id": 124,
+      "task_name": "parse_task_20250118_b2c3d4e5",
+      "task_status": "待解析",
+      "task_type": "名片",
+      "task_source": {
+        "minio_paths_json": [
+          "talent_photos/talent_photo_20250118_143012_a1b2c3d4.jpg"
+        ],
+        "upload_time": "2025-01-18T14:30:25.123456"
+      },
+      "collection_count": 2,
+      "parse_count": 0,
+      "parse_result": null,
+      "created_by": "frontend_user",
+      "updated_by": "frontend_user",
+      "created_at": "2025-01-18 14:30:25",
+      "updated_at": "2025-01-18 14:30:25"
+    },
+    "upload_summary": {
+      "task_type": "名片",
+      "total_files": 2,
+      "uploaded_count": 2,
+      "failed_count": 0,
+      "uploaded_files": [
+        {
+          "original_filename": "business_card1.jpg",
+          "minio_path": "talent_photos/talent_photo_20250118_143012_a1b2c3d4.jpg",
+          "relative_path": "talent_photos/talent_photo_20250118_143012_a1b2c3d4.jpg",
+          "file_size": 256000
+        }
+      ],
+      "failed_uploads": []
+    }
+  }
+}
+```
+
+#### 🎯 前端调用示例
+
+```javascript
+// 使用fetch API和FormData
+async function createParseTask(taskType, files, createdBy = 'frontend_user') {
+  const formData = new FormData();
+  
+  // 添加任务类型
+  formData.append('task_type', taskType);
+  
+  // 添加创建者
+  formData.append('created_by', createdBy);
+  
+  // 添加文件(如果有的话)
+  if (files && files.length > 0) {
+    for (let i = 0; i < files.length; i++) {
+      formData.append('files', files[i]);
+    }
+  }
+  
+  try {
+    const response = await fetch('/api/data-parse/add-parse-task', {
+      method: 'POST',
+      body: formData
+      // 注意:不要设置Content-Type,让浏览器自动设置multipart/form-data
+    });
+    
+    const result = await response.json();
+    
+    if (result.success) {
+      console.log('任务创建成功:', result.data);
+      return result.data;
+    } else {
+      console.error('创建失败:', result.message);
+      throw new Error(result.message);
+    }
+  } catch (error) {
+    console.error('请求异常:', error);
+    throw error;
+  }
+}
+
+// HTML文件上传示例
+function setupFileUpload() {
+  const fileInput = document.getElementById('fileInput');
+  const taskTypeSelect = document.getElementById('taskTypeSelect');
+  const uploadBtn = document.getElementById('uploadBtn');
+  
+  uploadBtn.addEventListener('click', async () => {
+    const taskType = taskTypeSelect.value;
+    const files = fileInput.files;
+    
+    if (!taskType) {
+      alert('请选择任务类型');
+      return;
+    }
+    
+    if (taskType !== '招聘' && files.length === 0) {
+      alert('请选择要上传的文件');
+      return;
+    }
+    
+    try {
+      const result = await createParseTask(taskType, files);
+      alert(`任务创建成功!任务ID: ${result.task_info.id}`);
+      
+      // 清空文件选择
+      fileInput.value = '';
+    } catch (error) {
+      alert(`任务创建失败: ${error.message}`);
+    }
+  });
+}
+
+// 页面加载完成后初始化
+document.addEventListener('DOMContentLoaded', setupFileUpload);
+```
+
+#### 🌐 HTML示例
+
+```html
+<!DOCTYPE html>
+<html>
+<head>
+    <title>创建解析任务</title>
+</head>
+<body>
+    <div>
+        <label for="taskTypeSelect">任务类型:</label>
+        <select id="taskTypeSelect">
+            <option value="">请选择任务类型</option>
+            <option value="名片">名片</option>
+            <option value="简历">简历</option>
+            <option value="新任命">新任命</option>
+            <option value="招聘">招聘</option>
+            <option value="杂项">杂项</option>
+        </select>
+    </div>
+    
+    <div>
+        <label for="fileInput">选择文件:</label>
+        <input type="file" id="fileInput" multiple accept="image/*,.pdf,.md">
+    </div>
+    
+    <button id="uploadBtn">创建任务</button>
+    
+    <script src="parse-task.js"></script>
+</body>
+</html>
+```
+
+#### 📊 状态码说明
+
+| HTTP状态码 | 业务状态 | 说明 |
+|------------|----------|------|
+| 200 | success: true | 所有文件上传成功,任务创建成功 |
+| 206 | success: true | 部分文件上传成功,任务创建成功 |
+| 400 | success: false | 请求参数错误 |
+| 500 | success: false | 服务器内部错误 |
+
+---
+
+### 4. 执行解析任务
+
+#### 📝 基本信息
+- **接口路径**: `POST /api/data-parse/execute-parse-task`
+- **功能**: 根据任务类型执行相应的批量处理函数
+- **内容类型**: `application/json`
+
+#### 📥 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 | 示例值 |
+|--------|------|------|------|--------|
+| `task_type` | string | 是 | 任务类型 | `"名片"` |
+| `data` | array | 是 | 数据列表,格式因任务类型而异 | `["path1.jpg", "path2.jpg"]` |
+| `publish_time` | string | 否* | 发布时间(仅新任命任务需要) | `"2025-01-18"` |
+| `process_type` | string | 否 | 处理类型(仅杂项任务) | `"table"` |
+| `id` | integer | 是 | 解析任务ID | `123` |
+
+> **注意**: 新任命任务必须提供`publish_time`参数
+
+#### 📋 不同任务类型的data格式
+
+| 任务类型 | data格式 | 示例 |
+|----------|----------|------|
+| 名片 | MinIO路径数组 | `["talent_photos/card1.jpg", "talent_photos/card2.jpg"]` |
+| 简历 | PDF文件路径数组 | `["resume_files/resume1.pdf", "resume_files/resume2.pdf"]` |
+| 新任命 | Markdown文件路径数组 | `["appointment_files/appointment1.md"]` |
+| 招聘 | 招聘数据对象数组 | `[{"name": "张三", "position": "经理"}]` |
+| 杂项 | 文件路径数组 | `["misc_files/file1.xlsx", "misc_files/file2.docx"]` |
+
+#### 📤 响应结果
+
+```json
+{
+  "success": true,
+  "message": "批量处理完成,全部 2 个文件处理成功",
+  "data": {
+    "summary": {
+      "total_files": 2,
+      "success_count": 2,
+      "failed_count": 0,
+      "success_rate": 100.0
+    },
+    "results": [
+      {
+        "index": 0,
+        "filename": "card1.jpg",
+        "success": true,
+        "error": null,
+        "data": {
+          "name_zh": "张三",
+          "title_zh": "技术总监",
+          "hotel_zh": "北京万豪酒店",
+          "mobile": "13800138000",
+          "email": "zhangsan@marriott.com",
+          "career_path": [
+            {
+              "date": "2025-01-18",
+              "hotel_zh": "北京万豪酒店",
+              "title_zh": "技术总监",
+              "source": "business_card"
+            }
+          ]
+        },
+        "message": "处理成功"
+      }
+    ],
+    "processed_time": "2025-01-18T15:30:45.123456"
+  }
+}
+```
+
+#### 🎯 前端调用示例
+
+```javascript
+// 执行解析任务
+async function executeParseTask(taskType, data, taskId, publishTime = null, processType = 'table') {
+  const requestBody = {
+    task_type: taskType,
+    data: data,
+    id: taskId
+  };
+  
+  // 新任命任务需要发布时间
+  if (taskType === '新任命' && publishTime) {
+    requestBody.publish_time = publishTime;
+  }
+  
+  // 杂项任务可以指定处理类型
+  if (taskType === '杂项') {
+    requestBody.process_type = processType;
+  }
+  
+  try {
+    const response = await fetch('/api/data-parse/execute-parse-task', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(requestBody)
+    });
+    
+    const result = await response.json();
+    
+    if (result.success) {
+      console.log('解析任务执行成功:', result.data);
+      return result.data;
+    } else {
+      console.error('执行失败:', result.message);
+      throw new Error(result.message);
+    }
+  } catch (error) {
+    console.error('请求异常:', error);
+    throw error;
+  }
+}
+
+// 使用示例
+const taskData = [
+  "talent_photos/talent_photo_20250118_143012_a1b2c3d4.jpg",
+  "talent_photos/talent_photo_20250118_143015_b2c3d4e5.jpg"
+];
+
+executeParseTask('名片', taskData, 123)
+  .then(result => {
+    console.log('处理结果:', result);
+    
+    // 检查处理统计
+    const summary = result.summary;
+    console.log(`总共${summary.total_files}个文件,成功${summary.success_count}个,失败${summary.failed_count}个`);
+    
+    // 处理每个结果
+    result.results.forEach((item, index) => {
+      if (item.success) {
+        console.log(`第${index + 1}个文件处理成功:`, item.data);
+      } else {
+        console.error(`第${index + 1}个文件处理失败:`, item.error);
+      }
+    });
+  })
+  .catch(error => {
+    console.error('解析任务执行失败:', error);
+  });
+
+// 新任命任务示例
+const appointmentData = ["appointment_files/appointment_20250118.md"];
+executeParseTask('新任命', appointmentData, 124, '2025-01-18')
+  .then(result => {
+    console.log('新任命解析完成:', result);
+  })
+  .catch(error => {
+    console.error('新任命解析失败:', error);
+  });
+```
+
+#### 📊 状态码说明
+
+| HTTP状态码 | 业务状态 | 说明 |
+|------------|----------|------|
+| 200 | success: true | 全部处理成功 |
+| 206 | success: true | 部分处理成功 |
+| 400 | success: false | 请求参数错误 |
+| 500 | success: false | 服务器内部错误 |
+
+---
+
+### 5. 处理解析结果
+
+#### 📝 基本信息
+- **接口路径**: `POST /api/data-parse/add-parsed-talents`
+- **功能**: 处理execute-parse-task API的响应数据,将人才信息写入business_cards表
+- **内容类型**: `application/json`
+
+#### 📥 请求参数
+
+请求体为execute-parse-task API的完整返回数据:
+
+```json
+{
+  "success": true,
+  "message": "处理完成",
+  "data": {
+    "summary": {
+      "total_files": 5,
+      "success_count": 4,
+      "failed_count": 1,
+      "success_rate": 80.0
+    },
+    "results": [
+      {
+        "index": 0,
+        "success": true,
+        "data": {
+          "name_zh": "张三",
+          "title_zh": "经理",
+          "hotel_zh": "某酒店",
+          "image_path": "talent_photos/image1.jpg"
+        }
+      }
+    ],
+    "processed_time": "2025-01-18T10:30:00"
+  }
+}
+```
+
+#### 📤 响应结果
+
+```json
+{
+  "success": true,
+  "message": "批量处理完成,全部 4 条人才数据写入成功",
+  "data": {
+    "summary": {
+      "total_files": 4,
+      "success_count": 4,
+      "failed_count": 0,
+      "success_rate": 100.0,
+      "original_summary": {
+        "total_files": 5,
+        "success_count": 4,
+        "failed_count": 1,
+        "success_rate": 80.0
+      }
+    },
+    "results": [
+      {
+        "index": 0,
+        "original_index": 0,
+        "success": true,
+        "error": null,
+        "data": {
+          "id": 1001,
+          "name_zh": "张三",
+          "action": "created",
+          "message": "成功创建新的人才记录"
+        },
+        "message": "成功处理人员: 张三"
+      }
+    ],
+    "processed_time": "2025-01-18T16:45:30.789012",
+    "original_api_response": {
+      // 保留原始API响应数据用于调试
+    }
+  }
+}
+```
+
+#### 🎯 前端调用示例
+
+```javascript
+// 处理解析结果
+async function processParseResults(executeTaskResponse) {
+  if (!executeTaskResponse || typeof executeTaskResponse !== 'object') {
+    throw new Error('API响应数据格式错误');
+  }
+  
+  try {
+    const response = await fetch('/api/data-parse/add-parsed-talents', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(executeTaskResponse)
+    });
+    
+    const result = await response.json();
+    
+    if (result.success) {
+      console.log('解析结果处理成功:', result.data);
+      return result.data;
+    } else {
+      console.error('处理失败:', result.message);
+      throw new Error(result.message);
+    }
+  } catch (error) {
+    console.error('请求异常:', error);
+    throw error;
+  }
+}
+
+// 完整的解析流程示例
+async function completeParseWorkflow(taskType, data, taskId, publishTime = null) {
+  try {
+    // 第一步:执行解析任务
+    console.log('步骤1: 执行解析任务...');
+    const executeResult = await executeParseTask(taskType, data, taskId, publishTime);
+    
+    // 第二步:处理解析结果
+    console.log('步骤2: 处理解析结果...');
+    const processResult = await processParseResults(executeResult);
+    
+    // 第三步:显示最终结果
+    console.log('解析流程完成!');
+    console.log('原始解析统计:', executeResult.summary);
+    console.log('数据写入统计:', processResult.summary);
+    
+    return {
+      executeResult,
+      processResult
+    };
+    
+  } catch (error) {
+    console.error('解析流程失败:', error);
+    throw error;
+  }
+}
+
+// 使用示例
+const taskData = ["talent_photos/card1.jpg", "talent_photos/card2.jpg"];
+
+completeParseWorkflow('名片', taskData, 123)
+  .then(results => {
+    const { executeResult, processResult } = results;
+    
+    // 显示处理统计
+    console.log(`原始解析: ${executeResult.summary.success_count}/${executeResult.summary.total_files} 成功`);
+    console.log(`数据写入: ${processResult.summary.success_count}/${processResult.summary.total_files} 成功`);
+    
+    // 显示详细结果
+    processResult.results.forEach((item, index) => {
+      if (item.success) {
+        console.log(`人员${index + 1}: ${item.message}`);
+      } else {
+        console.error(`人员${index + 1}: ${item.error}`);
+      }
+    });
+  })
+  .catch(error => {
+    console.error('完整解析流程失败:', error);
+  });
+```
+
+#### 📊 状态码说明
+
+| HTTP状态码 | 业务状态 | 说明 |
+|------------|----------|------|
+| 200 | success: true | 全部处理成功 |
+| 206 | success: true | 部分处理成功 |
+| 400 | success: false | 请求参数错误 |
+| 500 | success: false | 服务器内部错误 |
+
+---
+
+## 前端集成示例
+
+### 🎨 Vue.js 组件示例
+
+```vue
+<template>
+  <div class="parse-task-manager">
+    <h2>解析任务管理</h2>
+    
+    <!-- 创建任务 -->
+    <div class="create-task-section">
+      <h3>创建新任务</h3>
+      <el-form ref="taskForm" :model="taskForm" label-width="120px">
+        <el-form-item label="任务类型">
+          <el-select v-model="taskForm.taskType" placeholder="请选择任务类型">
+            <el-option label="名片" value="名片"></el-option>
+            <el-option label="简历" value="简历"></el-option>
+            <el-option label="新任命" value="新任命"></el-option>
+            <el-option label="招聘" value="招聘"></el-option>
+            <el-option label="杂项" value="杂项"></el-option>
+          </el-select>
+        </el-form-item>
+        
+        <el-form-item label="文件上传" v-if="taskForm.taskType !== '招聘'">
+          <el-upload
+            ref="upload"
+            :file-list="fileList"
+            :auto-upload="false"
+            :multiple="true"
+            :on-change="handleFileChange"
+            :on-remove="handleFileRemove">
+            <el-button size="small" type="primary">选择文件</el-button>
+          </el-upload>
+        </el-form-item>
+        
+        <el-form-item>
+          <el-button type="primary" @click="createTask" :loading="loading">创建任务</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+    
+    <!-- 任务列表 -->
+    <div class="task-list-section">
+      <h3>任务列表</h3>
+      <el-table :data="taskList" style="width: 100%">
+        <el-table-column prop="id" label="ID" width="80"></el-table-column>
+        <el-table-column prop="task_name" label="任务名称" width="200"></el-table-column>
+        <el-table-column prop="task_type" label="类型" width="100"></el-table-column>
+        <el-table-column prop="task_status" label="状态" width="100"></el-table-column>
+        <el-table-column prop="collection_count" label="文件数" width="80"></el-table-column>
+        <el-table-column prop="parse_count" label="解析数" width="80"></el-table-column>
+        <el-table-column prop="created_at" label="创建时间" width="180"></el-table-column>
+        <el-table-column label="操作">
+          <template slot-scope="scope">
+            <el-button size="mini" @click="viewDetail(scope.row)">详情</el-button>
+            <el-button size="mini" type="primary" @click="executeTask(scope.row)" 
+                       :disabled="scope.row.task_status !== '待解析'">执行</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      
+      <!-- 分页 -->
+      <el-pagination
+        @current-change="handlePageChange"
+        :current-page="currentPage"
+        :page-size="pageSize"
+        :total="total"
+        layout="total, prev, pager, next">
+      </el-pagination>
+    </div>
+    
+    <!-- 任务详情对话框 -->
+    <el-dialog title="任务详情" :visible.sync="detailVisible" width="80%">
+      <div v-if="currentTask">
+        <h4>基本信息</h4>
+        <p><strong>任务名称:</strong> {{ currentTask.task_name }}</p>
+        <p><strong>任务类型:</strong> {{ currentTask.task_type }}</p>
+        <p><strong>任务状态:</strong> {{ currentTask.task_status }}</p>
+        <p><strong>文件数量:</strong> {{ currentTask.collection_count }}</p>
+        <p><strong>解析数量:</strong> {{ currentTask.parse_count }}</p>
+        
+        <h4 v-if="currentTask.parse_result">解析结果</h4>
+        <pre v-if="currentTask.parse_result">{{ JSON.stringify(currentTask.parse_result, null, 2) }}</pre>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ParseTaskManager',
+  data() {
+    return {
+      loading: false,
+      taskForm: {
+        taskType: '',
+      },
+      fileList: [],
+      taskList: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 0,
+      detailVisible: false,
+      currentTask: null
+    }
+  },
+  mounted() {
+    this.loadTaskList();
+  },
+  methods: {
+    // 文件选择处理
+    handleFileChange(file, fileList) {
+      this.fileList = fileList;
+    },
+    
+    handleFileRemove(file, fileList) {
+      this.fileList = fileList;
+    },
+    
+    // 创建任务
+    async createTask() {
+      if (!this.taskForm.taskType) {
+        this.$message.error('请选择任务类型');
+        return;
+      }
+      
+      if (this.taskForm.taskType !== '招聘' && this.fileList.length === 0) {
+        this.$message.error('请选择要上传的文件');
+        return;
+      }
+      
+      this.loading = true;
+      
+      try {
+        const files = this.fileList.map(item => item.raw);
+        const result = await this.createParseTask(this.taskForm.taskType, files);
+        
+        this.$message.success('任务创建成功');
+        this.resetForm();
+        this.loadTaskList();
+        
+      } catch (error) {
+        this.$message.error(`任务创建失败: ${error.message}`);
+      } finally {
+        this.loading = false;
+      }
+    },
+    
+    // 重置表单
+    resetForm() {
+      this.taskForm.taskType = '';
+      this.fileList = [];
+      this.$refs.upload.clearFiles();
+    },
+    
+    // 加载任务列表
+    async loadTaskList() {
+      try {
+        const data = await this.getParseTaskList(this.currentPage, this.pageSize);
+        this.taskList = data.tasks;
+        this.total = data.pagination.total;
+      } catch (error) {
+        this.$message.error(`加载任务列表失败: ${error.message}`);
+      }
+    },
+    
+    // 分页处理
+    handlePageChange(page) {
+      this.currentPage = page;
+      this.loadTaskList();
+    },
+    
+    // 查看详情
+    async viewDetail(task) {
+      try {
+        this.currentTask = await this.getParseTaskDetail(task.task_name);
+        this.detailVisible = true;
+      } catch (error) {
+        this.$message.error(`获取任务详情失败: ${error.message}`);
+      }
+    },
+    
+    // 执行任务
+    async executeTask(task) {
+      if (!task.task_source || !task.task_source.minio_paths_json) {
+        this.$message.error('任务数据不完整,无法执行');
+        return;
+      }
+      
+      try {
+        this.$loading = this.$loading.service({
+          lock: true,
+          text: '正在执行解析任务...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)'
+        });
+        
+        // 执行解析
+        const executeResult = await this.executeParseTask(
+          task.task_type, 
+          task.task_source.minio_paths_json, 
+          task.id
+        );
+        
+        // 处理结果
+        const processResult = await this.processParseResults(executeResult);
+        
+        this.$message.success(`解析完成,成功处理 ${processResult.summary.success_count} 条记录`);
+        this.loadTaskList();
+        
+      } catch (error) {
+        this.$message.error(`任务执行失败: ${error.message}`);
+      } finally {
+        this.$loading.close();
+      }
+    },
+    
+    // API调用方法
+    async createParseTask(taskType, files, createdBy = 'vue_user') {
+      // 实现createParseTask方法
+      // ... (参考前面的JavaScript示例)
+    },
+    
+    async getParseTaskList(page, perPage, taskType = null, taskStatus = null) {
+      // 实现getParseTaskList方法
+      // ... (参考前面的JavaScript示例)
+    },
+    
+    async getParseTaskDetail(taskName) {
+      // 实现getParseTaskDetail方法
+      // ... (参考前面的JavaScript示例)
+    },
+    
+    async executeParseTask(taskType, data, taskId, publishTime = null) {
+      // 实现executeParseTask方法
+      // ... (参考前面的JavaScript示例)
+    },
+    
+    async processParseResults(executeTaskResponse) {
+      // 实现processParseResults方法
+      // ... (参考前面的JavaScript示例)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.parse-task-manager {
+  padding: 20px;
+}
+
+.create-task-section,
+.task-list-section {
+  margin-bottom: 30px;
+  padding: 20px;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+}
+
+.el-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+
+pre {
+  background-color: #f5f5f5;
+  padding: 10px;
+  border-radius: 4px;
+  overflow-x: auto;
+  max-height: 400px;
+}
+</style>
+```
+
+### 🔧 工具类封装
+
+```javascript
+// parseTaskAPI.js - API调用工具类
+class ParseTaskAPI {
+  constructor(baseURL = '/api/data-parse') {
+    this.baseURL = baseURL;
+  }
+  
+  // 通用请求方法
+  async request(url, options = {}) {
+    const fullURL = `${this.baseURL}${url}`;
+    
+    try {
+      const response = await fetch(fullURL, {
+        headers: {
+          'Content-Type': 'application/json',
+          ...options.headers
+        },
+        ...options
+      });
+      
+      const result = await response.json();
+      
+      if (result.success) {
+        return result.data;
+      } else {
+        throw new Error(result.message);
+      }
+    } catch (error) {
+      console.error(`API请求失败: ${fullURL}`, error);
+      throw error;
+    }
+  }
+  
+  // GET请求(用于查询类接口)
+  async get(url, params = {}) {
+    const queryString = new URLSearchParams(params).toString();
+    const fullURL = queryString ? `${url}?${queryString}` : url;
+    
+    return this.request(fullURL, { method: 'GET' });
+  }
+  
+  // POST请求(用于操作类接口)
+  async post(url, data) {
+    return this.request(url, {
+      method: 'POST',
+      body: JSON.stringify(data)
+    });
+  }
+  
+  // FormData POST请求(用于文件上传)
+  async postFormData(url, formData) {
+    const fullURL = `${this.baseURL}${url}`;
+    
+    try {
+      const response = await fetch(fullURL, {
+        method: 'POST',
+        body: formData
+      });
+      
+      const result = await response.json();
+      
+      if (result.success) {
+        return result.data;
+      } else {
+        throw new Error(result.message);
+      }
+    } catch (error) {
+      console.error(`FormData请求失败: ${fullURL}`, error);
+      throw error;
+    }
+  }
+  
+  // 1. 获取解析任务列表
+  async getTaskList(page = 1, perPage = 10, taskType = null, taskStatus = null) {
+    const params = { page, per_page: perPage };
+    if (taskType) params.task_type = taskType;
+    if (taskStatus) params.task_status = taskStatus;
+    
+    return this.get('/get-parse-tasks', params);
+  }
+  
+  // 2. 获取解析任务详情
+  async getTaskDetail(taskName) {
+    if (!taskName) {
+      throw new Error('任务名称不能为空');
+    }
+    
+    return this.get('/get-parse-task-detail', { task_name: taskName });
+  }
+  
+  // 3. 新增解析任务
+  async createTask(taskType, files = [], createdBy = 'api_user') {
+    const formData = new FormData();
+    formData.append('task_type', taskType);
+    formData.append('created_by', createdBy);
+    
+    if (files && files.length > 0) {
+      for (let i = 0; i < files.length; i++) {
+        formData.append('files', files[i]);
+      }
+    }
+    
+    return this.postFormData('/add-parse-task', formData);
+  }
+  
+  // 4. 执行解析任务
+  async executeTask(taskType, data, taskId, publishTime = null, processType = 'table') {
+    const requestBody = {
+      task_type: taskType,
+      data: data,
+      id: taskId
+    };
+    
+    if (taskType === '新任命' && publishTime) {
+      requestBody.publish_time = publishTime;
+    }
+    
+    if (taskType === '杂项') {
+      requestBody.process_type = processType;
+    }
+    
+    return this.post('/execute-parse-task', requestBody);
+  }
+  
+  // 5. 处理解析结果
+  async processResults(executeTaskResponse) {
+    if (!executeTaskResponse || typeof executeTaskResponse !== 'object') {
+      throw new Error('API响应数据格式错误');
+    }
+    
+    return this.post('/add-parsed-talents', executeTaskResponse);
+  }
+  
+  // 组合方法:完整的解析流程
+  async completeParseWorkflow(taskType, data, taskId, publishTime = null) {
+    try {
+      // 执行解析任务
+      const executeResult = await this.executeTask(taskType, data, taskId, publishTime);
+      
+      // 处理解析结果
+      const processResult = await this.processResults(executeResult);
+      
+      return {
+        executeResult,
+        processResult
+      };
+    } catch (error) {
+      console.error('完整解析流程失败:', error);
+      throw error;
+    }
+  }
+}
+
+// 导出实例
+export default new ParseTaskAPI();
+
+// 使用示例:
+// import parseTaskAPI from './parseTaskAPI.js';
+// 
+// // 获取任务列表
+// const taskList = await parseTaskAPI.getTaskList(1, 20, '名片');
+// 
+// // 创建任务
+// const createResult = await parseTaskAPI.createTask('名片', files);
+// 
+// // 执行完整流程
+// const result = await parseTaskAPI.completeParseWorkflow('名片', data, taskId);
+```
+
+---
+
+## 错误处理
+
+### 🚨 常见错误类型
+
+| 错误类型 | HTTP状态码 | 错误信息示例 | 处理建议 |
+|----------|------------|--------------|----------|
+| 参数错误 | 400 | `"缺少task_type参数"` | 检查请求参数完整性 |
+| 文件格式错误 | 400 | `"不支持的文件格式"` | 检查文件类型是否匹配任务类型 |
+| 任务不存在 | 404 | `"未找到任务名称为 xxx 的记录"` | 确认任务名称正确 |
+| 服务器错误 | 500 | `"数据库连接失败"` | 联系后端开发人员 |
+| 部分成功 | 206 | `"部分文件上传成功"` | 检查失败的文件,重新上传 |
+
+### 🛠️ 错误处理最佳实践
+
+```javascript
+// 统一错误处理函数
+function handleAPIError(error, context = '') {
+  console.error(`${context}失败:`, error);
+  
+  // 根据错误类型给出不同的用户提示
+  if (error.message.includes('网络')) {
+    return '网络连接异常,请检查网络后重试';
+  } else if (error.message.includes('参数')) {
+    return '请求参数错误,请检查输入信息';
+  } else if (error.message.includes('权限')) {
+    return '权限不足,请联系管理员';
+  } else if (error.message.includes('不存在')) {
+    return '请求的资源不存在';
+  } else {
+    return `操作失败: ${error.message}`;
+  }
+}
+
+// 带重试机制的API调用
+async function apiCallWithRetry(apiFunction, maxRetries = 3, delay = 1000) {
+  for (let i = 0; i < maxRetries; i++) {
+    try {
+      return await apiFunction();
+    } catch (error) {
+      if (i === maxRetries - 1) {
+        throw error;
+      }
+      
+      // 如果是网络错误或服务器错误,等待后重试
+      if (error.message.includes('fetch') || error.message.includes('500')) {
+        console.log(`第${i + 1}次重试,${delay}ms后重新请求...`);
+        await new Promise(resolve => setTimeout(resolve, delay));
+        delay *= 2; // 指数退避
+      } else {
+        throw error; // 其他错误直接抛出
+      }
+    }
+  }
+}
+
+// 使用示例
+try {
+  const result = await apiCallWithRetry(
+    () => parseTaskAPI.getTaskList(1, 10),
+    3,
+    1000
+  );
+  console.log('获取任务列表成功:', result);
+} catch (error) {
+  const userMessage = handleAPIError(error, '获取任务列表');
+  alert(userMessage);
+}
+```
+
+---
+
+## 最佳实践
+
+### 🎯 前端开发建议
+
+1. **参数验证**
+   ```javascript
+   // 在调用API前进行客户端验证
+   function validateTaskType(taskType) {
+     const validTypes = ['名片', '简历', '新任命', '招聘', '杂项'];
+     if (!validTypes.includes(taskType)) {
+       throw new Error(`无效的任务类型: ${taskType}`);
+     }
+   }
+   
+   function validateFiles(files, taskType) {
+     if (taskType === '招聘') {
+       return; // 招聘任务不需要文件
+     }
+     
+     if (!files || files.length === 0) {
+       throw new Error('请选择要上传的文件');
+     }
+     
+     // 文件格式验证
+     const allowedFormats = {
+       '名片': ['jpg', 'jpeg', 'png'],
+       '简历': ['pdf'],
+       '新任命': ['md'],
+       '杂项': ['*'] // 支持所有格式
+     };
+     
+     const formats = allowedFormats[taskType];
+     if (formats && !formats.includes('*')) {
+       files.forEach(file => {
+         const ext = file.name.split('.').pop().toLowerCase();
+         if (!formats.includes(ext)) {
+           throw new Error(`${taskType}任务不支持${ext}格式文件`);
+         }
+       });
+     }
+   }
+   ```
+
+2. **进度显示**
+   ```javascript
+   // 文件上传进度显示
+   function showUploadProgress(current, total) {
+     const percentage = Math.round((current / total) * 100);
+     console.log(`上传进度: ${current}/${total} (${percentage}%)`);
+     
+     // 更新UI进度条
+     updateProgressBar(percentage);
+   }
+   
+   // 解析进度显示
+   function showParseProgress(results) {
+     const completed = results.filter(r => r.success || r.error).length;
+     const total = results.length;
+     const percentage = Math.round((completed / total) * 100);
+     
+     console.log(`解析进度: ${completed}/${total} (${percentage}%)`);
+   }
+   ```
+
+3. **缓存策略**
+   ```javascript
+   // 任务列表缓存
+   class TaskListCache {
+     constructor(ttl = 5 * 60 * 1000) { // 5分钟TTL
+       this.cache = new Map();
+       this.ttl = ttl;
+     }
+     
+     getKey(page, perPage, taskType, taskStatus) {
+       return `${page}_${perPage}_${taskType || ''}_${taskStatus || ''}`;
+     }
+     
+     get(page, perPage, taskType, taskStatus) {
+       const key = this.getKey(page, perPage, taskType, taskStatus);
+       const item = this.cache.get(key);
+       
+       if (!item) return null;
+       
+       if (Date.now() - item.timestamp > this.ttl) {
+         this.cache.delete(key);
+         return null;
+       }
+       
+       return item.data;
+     }
+     
+     set(page, perPage, taskType, taskStatus, data) {
+       const key = this.getKey(page, perPage, taskType, taskStatus);
+       this.cache.set(key, {
+         data,
+         timestamp: Date.now()
+       });
+     }
+     
+     clear() {
+       this.cache.clear();
+     }
+   }
+   
+   const taskListCache = new TaskListCache();
+   ```
+
+4. **状态管理**
+   ```javascript
+   // 使用Vuex或类似状态管理
+   const parseTaskStore = {
+     state: {
+       taskList: [],
+       currentTask: null,
+       loading: false,
+       error: null
+     },
+     
+     mutations: {
+       SET_TASK_LIST(state, tasks) {
+         state.taskList = tasks;
+       },
+       SET_CURRENT_TASK(state, task) {
+         state.currentTask = task;
+       },
+       SET_LOADING(state, loading) {
+         state.loading = loading;
+       },
+       SET_ERROR(state, error) {
+         state.error = error;
+       }
+     },
+     
+     actions: {
+       async loadTaskList({ commit }, { page, perPage, taskType, taskStatus }) {
+         commit('SET_LOADING', true);
+         commit('SET_ERROR', null);
+         
+         try {
+           const data = await parseTaskAPI.getTaskList(page, perPage, taskType, taskStatus);
+           commit('SET_TASK_LIST', data.tasks);
+           return data;
+         } catch (error) {
+           commit('SET_ERROR', error.message);
+           throw error;
+         } finally {
+           commit('SET_LOADING', false);
+         }
+       }
+     }
+   };
+   ```
+
+### 📱 响应式设计
+
+```css
+/* 移动端适配 */
+@media (max-width: 768px) {
+  .parse-task-manager {
+    padding: 10px;
+  }
+  
+  .el-table {
+    font-size: 12px;
+  }
+  
+  .el-table-column {
+    min-width: 80px;
+  }
+  
+  .create-task-section,
+  .task-list-section {
+    padding: 15px;
+    margin-bottom: 20px;
+  }
+}
+
+/* 大屏优化 */
+@media (min-width: 1200px) {
+  .parse-task-manager {
+    max-width: 1200px;
+    margin: 0 auto;
+  }
+}
+```
+
+### 🔍 调试工具
+
+```javascript
+// 开发环境调试工具
+if (process.env.NODE_ENV === 'development') {
+  window.parseTaskDebug = {
+    // 显示API调用日志
+    enableAPILogging() {
+      const originalRequest = parseTaskAPI.request;
+      parseTaskAPI.request = function(...args) {
+        console.group(`API调用: ${args[0]}`);
+        console.log('参数:', args[1]);
+        console.time('请求耗时');
+        
+        return originalRequest.apply(this, args)
+          .then(result => {
+            console.log('响应:', result);
+            console.timeEnd('请求耗时');
+            console.groupEnd();
+            return result;
+          })
+          .catch(error => {
+            console.error('错误:', error);
+            console.timeEnd('请求耗时');
+            console.groupEnd();
+            throw error;
+          });
+      };
+    },
+    
+    // 模拟API响应
+    mockAPI(endpoint, response) {
+      const originalRequest = parseTaskAPI.request;
+      parseTaskAPI.request = function(url, options) {
+        if (url.includes(endpoint)) {
+          console.log(`Mock API: ${endpoint}`, response);
+          return Promise.resolve(response);
+        }
+        return originalRequest.apply(this, arguments);
+      };
+    }
+  };
+}
+```
+
+---
+
+## 📞 技术支持
+
+如有任何问题,请联系:
+
+- **后端开发团队**: backend@company.com
+- **API文档维护**: api-docs@company.com
+- **技术支持**: tech-support@company.com
+
+---
+
+> **文档更新记录**  
+> - v1.0 (2025-01-18): 初始版本,包含5个解析任务管理接口的完整说明
+> - 下次更新预计: 根据接口变更情况更新