解析任务管理API接口说明文档.md 43 KB

解析任务管理类API接口操作说明文档

版本: v1.0
更新时间: 2025-01-18
适用对象: 前端开发工程师

📋 目录

  1. 接口概览
  2. 通用说明
  3. 接口详细说明
  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格式:

{
  "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 - 任务状态过滤 "待解析"

📤 响应结果

{
  "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
    }
  }
}

🎯 前端调用示例

// 使用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"

📤 响应结果

{
  "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"
  }
}

🎯 前端调用示例

// 使用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"

注意: 除"招聘"类型外,其他类型必须上传文件

📤 响应结果

{
  "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": []
    }
  }
}

🎯 前端调用示例

// 使用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示例

<!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"]

📤 响应结果

{
  "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"
  }
}

🎯 前端调用示例

// 执行解析任务
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的完整返回数据:

{
  "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"
  }
}

📤 响应结果

{
  "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响应数据用于调试
    }
  }
}

🎯 前端调用示例

// 处理解析结果
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 组件示例

<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>

🔧 工具类封装

// 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 "部分文件上传成功" 检查失败的文件,重新上传

🛠️ 错误处理最佳实践

// 统一错误处理函数
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}%)`);
   }
  1. 缓存策略 ```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);
         }
       }
     }
   };

📱 响应式设计

/* 移动端适配 */
@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;
  }
}

🔍 调试工具

// 开发环境调试工具
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个解析任务管理接口的完整说明
  • 下次更新预计: 根据接口变更情况更新