Skip to content

Commit 7ffd375

Browse files
committed
fix:paste bug
1 parent c0adb1c commit 7ffd375

8 files changed

Lines changed: 178 additions & 140 deletions

File tree

chat2db-client/src/components/SearchResult/TableBox/index.tsx

Lines changed: 76 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import styles from './index.less';
1313
// 工具函数
1414
import { compareStrings } from '@/utils/sort';
1515
import { downloadFile } from '@/utils/common';
16-
import { transformInputValue } from './utils';
16+
import { transformInputValue, useCheckCanPaste } from './utils';
1717

1818
// 类型定义
1919
import { CRUD } from '@/constants';
@@ -132,6 +132,10 @@ export default function TableBox(props: ITableProps) {
132132
const [columnResize, setColumnResize] = useState<number[]>([0]);
133133
// 表格的宽度
134134
// const [tableBoxWidth, setTableBoxWidth] = useState<number>(0);
135+
// 判断是否可以执行cmd+v
136+
const [canPaste, setCanPaste] = useState<boolean>(false);
137+
// 判断是否聚焦在了可粘贴的区域中 hooks
138+
useCheckCanPaste(setCanPaste);
135139
const { setFocusedContent } = useWorkspaceStore((state) => {
136140
return {
137141
setFocusedContent: state.setFocusedContent,
@@ -297,12 +301,12 @@ export default function TableBox(props: ITableProps) {
297301
};
298302

299303
// 编辑数据
300-
const updateTableData = (type: 'setCell' | 'setRow' , _data: string | null | Array<string | null>) => {
304+
const updateTableData = (type: 'setCell' | 'setRow', _data: string | null | Array<string | null>) => {
301305
const newTableData = lodash.cloneDeep(tableData);
302306
let oldRowDataList: Array<string | null> = [];
303307
let newRowDataList: Array<string | null> = [];
304-
let curRowNo:string | null = '0';
305-
if(type === 'setCell' &&( typeof _data === 'string' || _data === null)){
308+
let curRowNo: string | null = '0';
309+
if (type === 'setCell' && (typeof _data === 'string' || _data === null)) {
306310
const [colIndex, rowNo] = editingCell!;
307311
curRowNo = rowNo;
308312
newTableData.forEach((item) => {
@@ -313,19 +317,19 @@ export default function TableBox(props: ITableProps) {
313317
});
314318
}
315319

316-
if(type === 'setRow' && Array.isArray(_data)){
320+
if (type === 'setRow' && Array.isArray(_data)) {
317321
curRowNo = curOperationRowNo;
318322
_data.unshift(curOperationRowNo);
319-
newTableData.forEach((t)=>{
320-
if(t[`${preCode}0No.`] === curOperationRowNo){
323+
newTableData.forEach((t) => {
324+
if (t[`${preCode}0No.`] === curOperationRowNo) {
321325
const dataLength = Object.keys(t).length;
322326
Object.keys(t).forEach((item, index) => {
323-
if(index > dataLength) return
327+
if (index > dataLength) return;
324328
t[item] = _data[index] || null;
325-
})
326-
return
329+
});
330+
return;
327331
}
328-
})
332+
});
329333
newRowDataList = _data;
330334
}
331335

@@ -353,7 +357,7 @@ export default function TableBox(props: ITableProps) {
353357
type: CRUD.UPDATE,
354358
oldDataList: oldRowDataList,
355359
dataList: newRowDataList,
356-
rowNo:curRowNo!,
360+
rowNo: curRowNo!,
357361
},
358362
]);
359363
return;
@@ -572,9 +576,7 @@ export default function TableBox(props: ITableProps) {
572576
// 如果删除的这个数据时编辑过的,要把这个数据恢复
573577
setTableData(
574578
tableData.map((item) =>
575-
item[`${preCode}0No.`] === rowNo
576-
? oldTableData.find((i) => i[`${preCode}0No.`] === rowNo)!
577-
: item,
579+
item[`${preCode}0No.`] === rowNo ? oldTableData.find((i) => i[`${preCode}0No.`] === rowNo)! : item,
578580
),
579581
);
580582
const newDataOldList = oldDataList.find((item) => item[0] === rowNo);
@@ -727,18 +729,18 @@ export default function TableBox(props: ITableProps) {
727729

728730
useEffect(() => {
729731
const handleCopy = () => {
730-
if(curOperationRowNo) {
732+
if (curOperationRowNo) {
731733
navigator.clipboard
732734
.readText()
733735
.then((text) => {
734-
const array2D = clipboardToArray(text);
736+
const array2D = clipboardToArray(text);
735737
updateTableData('setRow', array2D[0]);
736738
})
737739
.catch((err) => {
738740
console.error('Failed to read clipboard contents: ', err);
739741
});
740742
}
741-
if(editingCell && editingCell[2] === false){
743+
if (editingCell && editingCell[2] === false) {
742744
navigator.clipboard
743745
.readText()
744746
.then((text) => {
@@ -749,11 +751,15 @@ export default function TableBox(props: ITableProps) {
749751
});
750752
}
751753
};
752-
document.addEventListener('paste', handleCopy);
754+
if (canPaste) {
755+
document.addEventListener('paste', handleCopy);
756+
} else {
757+
document.removeEventListener('paste', handleCopy);
758+
}
753759
return () => {
754760
document.removeEventListener('paste', handleCopy);
755761
};
756-
}, [curOperationRowNo, editingCell]);
762+
}, [curOperationRowNo, editingCell, canPaste]);
757763

758764
// 表格 列配置
759765
const columns: ArtColumn[] = useMemo(() => {
@@ -772,18 +778,19 @@ export default function TableBox(props: ITableProps) {
772778
render: (value: any, rowData) => {
773779
const rowNo = rowData[`${preCode}0No.`];
774780
return (
775-
<div
776-
data-chat2db-can-copy-element
777-
onClick={() => {
778-
handelRowNoClick(rowNo);
779-
}}
780-
onContextMenu={() => {
781-
handelRowNoClick(rowNo);
782-
}}
783-
className={tableCellStyle(value, colIndex, rowNo)}
784-
>
785-
<div className={styles.tableItemNo}>{value}</div>
786-
</div>
781+
<div
782+
data-chat2db-general-can-copy-element
783+
data-chat2db-edit-table-data-can-paste
784+
onClick={() => {
785+
handelRowNoClick(rowNo);
786+
}}
787+
onContextMenu={() => {
788+
handelRowNoClick(rowNo);
789+
}}
790+
className={tableCellStyle(value, colIndex, rowNo)}
791+
>
792+
<div className={styles.tableItemNo}>{value}</div>
793+
</div>
787794
);
788795
},
789796
};
@@ -798,7 +805,8 @@ export default function TableBox(props: ITableProps) {
798805
const rowNo = rowData[`${preCode}0No.`];
799806
return (
800807
<div
801-
data-chat2db-can-copy-element
808+
data-chat2db-general-can-copy-element
809+
data-chat2db-edit-table-data-can-paste
802810
className={tableCellStyle(value, colIndex, rowNo)}
803811
onClick={handleClickTableItem.bind(null, colIndex, rowNo, value, false)}
804812
onDoubleClick={handleClickTableItem.bind(null, colIndex, rowNo, value, true)}
@@ -989,7 +997,7 @@ export default function TableBox(props: ITableProps) {
989997
});
990998
},
991999
};
992-
const rowRightClickMenu = useMemo(()=>{
1000+
const rowRightClickMenu = useMemo(() => {
9931001
// const allSupportedMenus = {
9941002
// [AllSupportedMenusType.CopyCell]: copyCell,
9951003
// [AllSupportedMenusType.CopyRow]: copyRow,
@@ -1000,8 +1008,8 @@ export default function TableBox(props: ITableProps) {
10001008
// [AllSupportedMenusType.ViewData]: viewData,
10011009
// }
10021010

1003-
let rightClickMenu:any = [];
1004-
if(curOperationRowNo){
1011+
let rightClickMenu: any = [];
1012+
if (curOperationRowNo) {
10051013
rightClickMenu = [copyRow, cloneRow, deleteRow];
10061014
// 如果当前数据不可编辑,则不显示cloneRow和deleteRow
10071015
if (!queryResultData.canEdit) {
@@ -1011,7 +1019,7 @@ export default function TableBox(props: ITableProps) {
10111019
}
10121020
}
10131021

1014-
if(editingCell){
1022+
if (editingCell) {
10151023
rightClickMenu = [viewData, copyCell, copyRow, cloneRow, setNull, setDefault, deleteRow];
10161024
// 判断是否有默认值,如果没有默认值,则不显示设置默认值的菜单
10171025
const hasDefaultValue =
@@ -1030,13 +1038,11 @@ export default function TableBox(props: ITableProps) {
10301038
}
10311039
}
10321040

1033-
1034-
if(!curOperationRowNo && !editingCell){
1035-
return null
1041+
if (!curOperationRowNo && !editingCell) {
1042+
return null;
10361043
}
1037-
return rightClickMenu
1038-
1039-
},[curOperationRowNo, editingCell])
1044+
return rightClickMenu;
1045+
}, [curOperationRowNo, editingCell]);
10401046

10411047
const renderContent = () => {
10421048
const bottomStatus = (
@@ -1158,13 +1164,13 @@ export default function TableBox(props: ITableProps) {
11581164
{allDataReady && (
11591165
<>
11601166
{tableLoading && <Spin className={styles.supportBaseTableSpin} />}
1161-
<SupportBaseTable
1162-
className={classnames('supportBaseTable', props.className, styles.table)}
1163-
components={{ EmptyContent: () => <h2>{i18n('common.text.noData')}</h2> }}
1164-
isStickyHead
1165-
stickyTop={31}
1166-
{...pipeline.getProps()}
1167-
/>
1167+
<SupportBaseTable
1168+
className={classnames('supportBaseTable', props.className, styles.table)}
1169+
components={{ EmptyContent: () => <h2>{i18n('common.text.noData')}</h2> }}
1170+
isStickyHead
1171+
stickyTop={31}
1172+
{...pipeline.getProps()}
1173+
/>
11681174
</>
11691175
)}
11701176
</div>
@@ -1179,6 +1185,25 @@ export default function TableBox(props: ITableProps) {
11791185
}
11801186
};
11811187

1188+
const renderMonacoEditor = useMemo(() => {
1189+
return (
1190+
<div className={styles.monacoEditor}>
1191+
<MonacoEditor
1192+
ref={monacoEditorRef}
1193+
id={`view_table-Cell_data-${uuid()}`}
1194+
appendValue={{
1195+
text: viewTableCellData?.value,
1196+
range: 'reset',
1197+
}}
1198+
options={{
1199+
lineNumbers: 'off',
1200+
readOnly: !queryResultData.canEdit,
1201+
}}
1202+
/>
1203+
</div>
1204+
);
1205+
}, [queryResultData, viewTableCellData]);
1206+
11821207
return (
11831208
<div className={classnames(className, styles.tableBox, { [styles.noDataTableBox]: !tableData.length })}>
11841209
{renderContent()}
@@ -1197,22 +1222,7 @@ export default function TableBox(props: ITableProps) {
11971222
]
11981223
}
11991224
>
1200-
<>
1201-
<div className={styles.monacoEditor}>
1202-
<MonacoEditor
1203-
ref={monacoEditorRef}
1204-
id={`view_table-Cell_data-${uuid()}`}
1205-
appendValue={{
1206-
text: viewTableCellData?.value,
1207-
range: 'reset',
1208-
}}
1209-
options={{
1210-
lineNumbers: 'off',
1211-
readOnly: !queryResultData.canEdit,
1212-
}}
1213-
/>
1214-
</div>
1215-
</>
1225+
{renderMonacoEditor}
12161226
</Modal>
12171227
<Modal
12181228
width="60vw"
Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
1-
// 在input中把USER_FILLED_VALUE转换为null
1+
import { useEffect } from 'react';
22
import { USER_FILLED_VALUE } from './index';
3+
4+
// 在input中把USER_FILLED_VALUE转换为null
35
export const transformInputValue = (value: string) => {
46
if (value === USER_FILLED_VALUE.DEFAULT) {
57
return null;
68
}
79
return value;
810
};
11+
12+
13+
// 判断是否聚焦在了可粘贴的区域中 hooks
14+
export const useCheckCanPaste = (setCanPaste)=>{
15+
useEffect(()=>{
16+
const handleClick = (event) => {
17+
const targetElement = event.target as Element;
18+
if (targetElement.closest('[data-chat2db-edit-table-data-can-paste]')) {
19+
setCanPaste(true);
20+
}else{
21+
setCanPaste(false);
22+
}
23+
};
24+
document.addEventListener('click', handleClick);
25+
document.addEventListener('contextmenu', handleClick);
26+
return () => {
27+
document.removeEventListener('click', handleClick);
28+
document.removeEventListener('contextmenu', handleClick);
29+
};
30+
},[])
31+
}

chat2db-client/src/hooks/useCopyFocusData.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { useEffect } from 'react';
2+
import { useWorkspaceStore } from '@/store/workspace';
3+
import { tableCopy, copy } from '@/utils'
4+
5+
// 如果用户点击的不是可复制的元素,就清空选中的内容
6+
function useCopyFocusData() {
7+
const { setFocusedContent, focusedContent } = useWorkspaceStore((state) => {
8+
return {
9+
setFocusedContent: state.setFocusedContent,
10+
focusedContent: state.focusedContent
11+
}
12+
});
13+
14+
// 注册快捷键监听cmd+c或ctrl+c复制focusedContent
15+
useEffect(() => {
16+
const handleCopy = (e: KeyboardEvent) => {
17+
if (e.key === 'c' && (e.metaKey || e.ctrlKey)) {
18+
if (!focusedContent) return
19+
// 如果是数据是数组,就调用tableCopy
20+
if (Array.isArray(focusedContent)) {
21+
tableCopy(focusedContent as any)
22+
return
23+
}
24+
copy(focusedContent as any)
25+
}
26+
};
27+
document.addEventListener('keydown', handleCopy);
28+
return () => {
29+
document.removeEventListener('keydown', handleCopy);
30+
};
31+
}, [focusedContent]);
32+
33+
useEffect(() => {
34+
const handleClick = (event) => {
35+
const targetElement = event.target as Element;
36+
if (!targetElement.closest('[data-chat2db-general-can-copy-element]')) {
37+
setFocusedContent(null)
38+
}
39+
};
40+
document.addEventListener('click', handleClick);
41+
document.addEventListener('contextmenu', handleClick);
42+
return () => {
43+
document.removeEventListener('click', handleClick);
44+
document.removeEventListener('contextmenu', handleClick);
45+
};
46+
}, [focusedContent]);
47+
}
48+
49+
export default useCopyFocusData;

0 commit comments

Comments
 (0)