feat(dc): Complete Tool C quick action buttons Phase 1-2 - 7 functions
Summary: - Implement 7 quick action functions (filter, recode, binning, conditional, dropna, compute, pivot) - Refactor to pre-written Python functions architecture (stable and secure) - Add 7 Python operations modules with full type hints - Add 7 frontend Dialog components with user-friendly UI - Fix NaN serialization issues and auto type conversion - Update all related documentation Technical Details: - Python: operations/ module (filter.py, recode.py, binning.py, conditional.py, dropna.py, compute.py, pivot.py) - Backend: QuickActionService.ts with 7 execute methods - Frontend: 7 Dialog components with complete validation - Toolbar: Enable 7 quick action buttons Status: Phase 1-2 completed, basic testing passed, ready for further testing
This commit is contained in:
@@ -17,6 +17,7 @@ import { MultipartFile } from '@fastify/multipart';
|
||||
import { logger } from '../../../../common/logging/index.js';
|
||||
import { sessionService } from '../services/SessionService.js';
|
||||
import { dataProcessService } from '../services/DataProcessService.js';
|
||||
import * as xlsx from 'xlsx';
|
||||
|
||||
// ==================== 请求参数类型定义 ====================
|
||||
|
||||
@@ -291,6 +292,76 @@ export class SessionController {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ✨ 导出Excel文件(新增)
|
||||
*
|
||||
* GET /api/v1/dc/tool-c/sessions/:id/export
|
||||
*/
|
||||
async exportData(
|
||||
request: FastifyRequest<{ Params: SessionIdParams }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const { id } = request.params;
|
||||
|
||||
logger.info(`[SessionController] 导出Excel: ${id}`);
|
||||
|
||||
// 1. 获取Session信息
|
||||
const session = await sessionService.getSession(id);
|
||||
|
||||
// 2. 获取完整数据
|
||||
const data = await sessionService.getFullData(id);
|
||||
|
||||
// 3. 生成Excel
|
||||
const workbook = xlsx.utils.book_new();
|
||||
const worksheet = xlsx.utils.json_to_sheet(data);
|
||||
|
||||
// 设置列宽(自动调整)
|
||||
const colWidths = session.columns.map(col => {
|
||||
const maxLength = Math.max(
|
||||
col.length,
|
||||
...data.slice(0, 100).map(row => String(row[col] || '').length)
|
||||
);
|
||||
return { wch: Math.min(maxLength + 2, 50) };
|
||||
});
|
||||
worksheet['!cols'] = colWidths;
|
||||
|
||||
xlsx.utils.book_append_sheet(workbook, worksheet, 'Data');
|
||||
|
||||
// 4. 生成Buffer
|
||||
const buffer = xlsx.write(workbook, {
|
||||
type: 'buffer',
|
||||
bookType: 'xlsx',
|
||||
compression: true,
|
||||
});
|
||||
|
||||
// 5. 生成文件名(加上_cleaned后缀和时间戳)
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
const baseFileName = session.fileName.replace(/\.[^/.]+$/, ''); // 去除扩展名
|
||||
const exportFileName = `${baseFileName}_cleaned_${timestamp}.xlsx`;
|
||||
|
||||
logger.info(`[SessionController] 导出成功: ${exportFileName}, 大小: ${(buffer.length / 1024).toFixed(2)}KB`);
|
||||
|
||||
// 6. 返回文件
|
||||
reply.header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
reply.header('Content-Disposition', `attachment; filename="${encodeURIComponent(exportFileName)}"`);
|
||||
reply.header('Content-Length', buffer.length);
|
||||
|
||||
return reply.send(buffer);
|
||||
} catch (error: any) {
|
||||
logger.error(`[SessionController] 导出Excel失败: ${error.message}`);
|
||||
|
||||
const statusCode = error.message.includes('不存在') || error.message.includes('过期')
|
||||
? 404
|
||||
: 500;
|
||||
|
||||
return reply.code(statusCode).send({
|
||||
success: false,
|
||||
error: error.message || '导出Excel失败',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 导出单例实例 ====================
|
||||
|
||||
Reference in New Issue
Block a user