/** * 数值映射(重编码)对话框 * * 功能: * - 自动提取列的唯一值 * - 用户配置映射关系 * - 支持创建新列或覆盖原列 */ import React, { useState, useEffect } from 'react'; import { Modal, Select, Input, Button, Checkbox, Table, Spin, App } from 'antd'; interface RecodeDialogProps { visible: boolean; columns: Array<{ id: string; name: string }>; data: any[]; sessionId: string | null; onClose: () => void; onApply: (newData: any[]) => void; } interface MappingRow { originalValue: any; newValue: string; } const RecodeDialog: React.FC = ({ visible, columns, data, sessionId, onClose, onApply, }) => { const { message } = App.useApp(); const [selectedColumn, setSelectedColumn] = useState(''); const [uniqueValues, setUniqueValues] = useState([]); const [mappingTable, setMappingTable] = useState([]); const [createNewColumn, setCreateNewColumn] = useState(true); const [newColumnName, setNewColumnName] = useState(''); const [loading, setLoading] = useState(false); const [extracting, setExtracting] = useState(false); // 当选择列时,从后端获取唯一值 useEffect(() => { if (!selectedColumn || !sessionId) { setUniqueValues([]); setMappingTable([]); return; } const fetchUniqueValues = async () => { setExtracting(true); try { // ✨ 调用后端API获取唯一值(从完整数据中提取,不受前端50行限制) const response = await fetch( `/api/v1/dc/tool-c/sessions/${sessionId}/unique-values?column=${encodeURIComponent(selectedColumn)}` ); const result = await response.json(); if (!result.success) { throw new Error(result.error || '获取唯一值失败'); } const unique = result.data.uniqueValues; setUniqueValues(unique); // 初始化映射表 const initialMapping = unique.map((val: any) => ({ originalValue: val, newValue: '', })); setMappingTable(initialMapping); // 生成默认新列名 setNewColumnName(`${selectedColumn}_编码`); } catch (error: any) { console.error('[RecodeDialog] 获取唯一值失败:', error); message.error(error.message || '获取唯一值失败'); setUniqueValues([]); setMappingTable([]); } finally { setExtracting(false); } }; fetchUniqueValues(); }, [selectedColumn, sessionId, message]); // 更新映射值 const updateMapping = (originalValue: any, newValue: string) => { setMappingTable( mappingTable.map((row) => row.originalValue === originalValue ? { ...row, newValue } : row ) ); }; // 表格列定义 const tableColumns = [ { title: '原值', dataIndex: 'originalValue', key: 'originalValue', width: '45%', render: (value: any) => ( {String(value)} ), }, { title: '→', key: 'arrow', width: '10%', align: 'center' as const, render: () => , }, { title: '新值', dataIndex: 'newValue', key: 'newValue', width: '45%', render: (_: any, record: MappingRow) => ( updateMapping(record.originalValue, e.target.value)} size="small" /> ), }, ]; // 执行重编码 const handleApply = async () => { if (!sessionId || !selectedColumn) { message.error('请先选择列'); return; } // 验证映射表 const emptyMapping = mappingTable.find((row) => !row.newValue); if (emptyMapping) { message.warning('请为所有原值指定新值'); return; } if (createNewColumn && !newColumnName) { message.warning('请输入新列名'); return; } // 构建映射对象 const mapping: Record = {}; mappingTable.forEach((row) => { mapping[String(row.originalValue)] = row.newValue; }); setLoading(true); try { const response = await fetch('/api/v1/dc/tool-c/quick-action', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sessionId, action: 'recode', params: { column: selectedColumn, mapping, createNewColumn, newColumnName: createNewColumn ? newColumnName : undefined, }, }), }); const result = await response.json(); if (result.success) { message.success('重编码成功!'); onApply(result.data.newDataPreview); onClose(); } else { // 友好的错误提示 message.error({ content: result.error || '重编码失败', duration: 5, }); } } catch (error: any) { console.error('[RecodeDialog] 执行失败:', error); message.error({ content: '网络错误,请检查服务是否正常运行', duration: 5, }); } finally { setLoading(false); } }; return (
{/* 选择列 */}
setNewColumnName(e.target.value)} size="small" prefix={新列名:} />
)}
)} )} {/* 操作按钮 */}
); }; export default RecodeDialog;