convert.api.md 6.0 KB

import type { ActionFunctionArgs } from '@remix-run/node';
import type { ConvertRequest, ConvertResponse, Template } from '@shared/types/mod.ts';
import { ERROR_CODES, EXCEL_TEMPLATE_TABLE } from '@shared/types/mod.ts';
import { excelParser } from '~/lib/ExcelParser.server.ts';
import { getApiClient } from '~/lib/ApiClient.server.ts';

/**
 * 公开的Excel转JSON API接口 
 * POST /api/v1/convert
 * 
 * 需要在请求头中提供有效的API密钥:
 * - X-API-Key: 'YOUR_API_KEY'
 */
export const action = async ({ request }: ActionFunctionArgs) => {
  console.log('[ExcelToJSON API] 收到转换请求');
  
  // 只支持POST请求
  if (request.method !== 'POST') {
    console.log('[ExcelToJSON API] 错误: 不支持的请求方法', request.method);
    return Response.json({
      success: false,
      code: ERROR_CODES.VALIDATION_ERROR,
      message: '不支持的请求方法,仅支持POST'
    }, { status: 405 });
  }

  // 验证API密钥
  const apiKey = request.headers.get('X-API-Key');
  if (!apiKey) {
    console.log('[ExcelToJSON API] 错误: 缺少API密钥');
    return Response.json({
      success: false,
      code: ERROR_CODES.AUTH_ERROR,
      message: '缺少API密钥,请在请求头中提供X-API-Key'
    }, { status: 401 });
  }

  // TODO: 在实际生产环境中,应该从数据库或环境变量中获取并验证API密钥
  const validApiKey = process.env.API_KEY || 'excel2json-api-key';
  if (apiKey !== validApiKey) {
    console.log('[ExcelToJSON API] 错误: API密钥无效', apiKey);
    return Response.json({
      success: false,
      code: ERROR_CODES.AUTH_ERROR,
      message: 'API密钥无效'
    }, { status: 401 });
  }

  try {
    // 解析请求数据
    const requestData = await request.json() as ConvertRequest;
    console.log('[ExcelToJSON API] 请求数据:', {
      templateId: requestData.templateId,
      hasConfig: !!requestData.config,
      inputType: requestData.input?.substring(0, 20) + '...' // 只记录输入类型的前20个字符
    });
    
    // 验证输入参数
    if (!requestData.input) {
      console.log('[ExcelToJSON API] 错误: 缺少input参数');
      return Response.json({
        success: false,
        code: ERROR_CODES.VALIDATION_ERROR,
        message: '请提供input参数'
      }, { status: 400 });
    }

    // 获取API客户端
    console.log('[ExcelToJSON API] 获取API客户端');
    const apiClient = await getApiClient();
    
    // 解析配置
    let templateConfig;
    
    // 如果提供了templateId,从数据库获取模板配置
    if (requestData.templateId) {
      console.log('[ExcelToJSON API] 正在获取模板,ID:', requestData.templateId);
      try {
        const template = await apiClient.database.table(EXCEL_TEMPLATE_TABLE)
          .where('id', requestData.templateId)
          .where('is_deleted', 0)
          .first() as Template;
        
        if (!template) {
          console.log('[ExcelToJSON API] 错误: 模板不存在', requestData.templateId);
          return Response.json({
            success: false,
            code: ERROR_CODES.NOT_FOUND,
            message: '模板不存在'
          }, { status: 404 });
        }
        
        templateConfig = template.template_config;
        console.log('[ExcelToJSON API] 成功获取模板配置,工作表数:', templateConfig.sheets?.length);
        
      } catch (error) {
        console.error('[ExcelToJSON API] 获取模板失败:', error);
        return Response.json({
          success: false,
          code: ERROR_CODES.SERVER_ERROR,
          message: '获取模板失败'
        }, { status: 500 });
      }
    } 
    // 如果提供了自定义配置,使用自定义配置
    else if (requestData.config) {
      templateConfig = requestData.config;
      console.log('[ExcelToJSON API] 使用自定义配置,工作表数:', templateConfig.sheets?.length);
    } 
    // 如果没有提供模板ID或自定义配置,返回错误
    else {
      console.log('[ExcelToJSON API] 错误: 缺少templateId或config参数');
      return Response.json({
        success: false,
        code: ERROR_CODES.VALIDATION_ERROR,
        message: '请提供templateId或config参数'
      }, { status: 400 });
    }

    // 将输入转换为ArrayBuffer
    let buffer: ArrayBuffer;
    
    try {
      console.log('[ExcelToJSON API] 正在获取文件数据');
      buffer = await excelParser.getBufferFromUrlOrBase64(requestData.input);
      console.log('[ExcelToJSON API] 成功获取文件数据,大小:', buffer.byteLength, '字节');
    } catch (error) {
      console.error('[ExcelToJSON API] 获取文件数据失败:', error);
      return Response.json({
        success: false,
        code: ERROR_CODES.VALIDATION_ERROR,
        message: '获取文件数据失败,请确保提供了有效的URL或Base64编码'
      }, { status: 400 });
    }
    
    // 处理Excel文件
    console.log('[ExcelToJSON API] 开始解析Excel文件');
    const result = await excelParser.parseExcelBuffer(buffer, templateConfig.sheets);
    console.log('[ExcelToJSON API] Excel解析完成,总表格数:', result.totalTables, '警告数:', result.warnings.length);
    
    // 构造响应
    const response: ConvertResponse = {
      success: true,
      data: result.exportData,
      warnings: result.warnings,
      availableFields: result.availableFieldsBySheet,
      totalTables: result.totalTables
    };
    
    // 记录API调用日志(可选)
    // await apiClient.database.table('api_logs').insert({
    //   api_key: apiKey,
    //   endpoint: '/api/v1/convert',
    //   created_at: new Date()
    // });
    
    console.log('[ExcelToJSON API] 转换成功,响应数据大小:', 
      JSON.stringify(response).length, '字节');
    return Response.json(response);
    
  } catch (error) {
    console.error('[ExcelToJSON API] 转换失败:', error);
    return Response.json({
      success: false,
      code: ERROR_CODES.SERVER_ERROR,
      message: `转换失败: ${error instanceof Error ? error.message : '未知错误'}`
    }, { status: 500 });
  }
};