fix(batch-image): 修复单元格选择和复制粘贴功能
- 修复单元格无法填满 td 的问题 (height: 100%) - 添加 user-select: none 防止浏览器文本选择干扰 - 添加 pointer-events: none 到 .cell-text 确保点击事件传递 - 实现 Ctrl+C/V 复制粘贴功能,支持多行 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
382e94b76d
commit
faa24b9da0
2 files changed
+69
-1
No files matched your search
@@ -104,6 +104,7 @@
|
||||
border: 1px solid #e0e0e0;
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
height: 1px; // 让 td 高度由内容撑开,同时允许子元素 height: 100% 生效
|
||||
}
|
||||
|
||||
th {
|
||||
@@ -187,11 +188,14 @@
|
||||
// 单元格
|
||||
.excel-cell {
|
||||
min-height: 40px;
|
||||
height: 100%; // 填满整个 td
|
||||
padding: 8px;
|
||||
cursor: cell;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
user-select: none; // 禁用文本选择,防止浏览器原生选择干扰单元格选择
|
||||
box-sizing: border-box;
|
||||
|
||||
&.active {
|
||||
background: white;
|
||||
@@ -207,6 +211,7 @@
|
||||
.cell-text {
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
pointer-events: none; // 确保点击事件传递到父级 .excel-cell
|
||||
}
|
||||
|
||||
input, textarea, select {
|
||||
@@ -218,6 +223,7 @@
|
||||
font-family: inherit;
|
||||
padding: 0;
|
||||
resize: none;
|
||||
user-select: text; // 编辑模式下允许文本选择
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
||||
@@ -838,6 +838,68 @@ const BatchImageGeneration: React.FC<BatchImageGenerationProps> = ({ onSwitchToS
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl+C 复制(支持多行)
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
|
||||
e.preventDefault();
|
||||
// 收集所有选中单元格的值(按行排序)
|
||||
const sortedCells = [...selectedCells].sort((a, b) => a.row - b.row);
|
||||
const values = sortedCells.map(cell => {
|
||||
const cellValue = (tasks[cell.row] as any)?.[cell.col];
|
||||
return { row: cell.row, col: cell.col, value: cellValue };
|
||||
});
|
||||
|
||||
if (values.length > 0) {
|
||||
// 生成文本用于系统剪贴板(每行一个值)
|
||||
const textToCopy = values.map(v =>
|
||||
v.col === 'images' ? JSON.stringify(v.value) : String(v.value ?? '')
|
||||
).join('\n');
|
||||
|
||||
navigator.clipboard.writeText(textToCopy).then(() => {
|
||||
// 存储复制的单元格信息用于内部粘贴
|
||||
(window as any).__copiedCells = values;
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl+V 粘贴(支持多行)
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'v') {
|
||||
e.preventDefault();
|
||||
// 优先使用内部复制的单元格数据
|
||||
const copiedCells = (window as any).__copiedCells as Array<{row: number, col: string, value: any}> | undefined;
|
||||
|
||||
if (copiedCells && copiedCells.length > 0 && copiedCells[0].col === col) {
|
||||
// 从当前活动单元格开始粘贴多行
|
||||
copiedCells.forEach((copied, index) => {
|
||||
const targetRow = row + index;
|
||||
if (targetRow < tasks.length) {
|
||||
updateCellValue(targetRow, col, copied.value);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 从系统剪贴板粘贴文本(支持多行)
|
||||
navigator.clipboard.readText().then(text => {
|
||||
const lines = text.split('\n');
|
||||
lines.forEach((line, index) => {
|
||||
const targetRow = row + index;
|
||||
if (targetRow >= tasks.length) return;
|
||||
|
||||
if (col === 'prompt') {
|
||||
updateCellValue(targetRow, col, line);
|
||||
} else if (col === 'count') {
|
||||
const num = parseInt(line);
|
||||
if (!isNaN(num) && num >= 1) {
|
||||
updateCellValue(targetRow, col, num);
|
||||
}
|
||||
} else if (col === 'size' && SIZE_OPTIONS.includes(line)) {
|
||||
updateCellValue(targetRow, col, line);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
@@ -878,7 +940,7 @@ const BatchImageGeneration: React.FC<BatchImageGenerationProps> = ({ onSwitchToS
|
||||
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||
}, [activeCell, editingCell, tasks.length, selectCell, enterEditMode, updateCellValue]);
|
||||
}, [activeCell, editingCell, tasks, selectedCells, selectCell, enterEditMode, updateCellValue]);
|
||||
|
||||
// 渲染单元格内容
|
||||
const renderCellContent = (task: TaskRow, rowIndex: number, col: string) => {
|
||||
|
||||
Reference in new issue
Block a user