From 3fe7f013dc2c3d2f5e52f7bb3ba1f9a114156a83 Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Thu, 26 Mar 2026 20:40:34 -0400 Subject: [PATCH] support resize --- src/components/modals/ExportModal.vue | 131 ++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 16 deletions(-) diff --git a/src/components/modals/ExportModal.vue b/src/components/modals/ExportModal.vue index c16bea0..f3e1bc5 100644 --- a/src/components/modals/ExportModal.vue +++ b/src/components/modals/ExportModal.vue @@ -23,9 +23,61 @@ const selectedTags = ref(mainTags.value.map(t => t.id)); // 表格数据 const dateList = ref([]); const previewData = ref>>({}); -const isDesc = ref(false); +const isDesc = ref(true); const sortedDateList = computed(() => isDesc.value ? [...dateList.value].reverse() : dateList.value); +// 拖拽调整宽高状态 +const colWidths = ref>({}); +const rowHeights = ref>({}); +const isDragging = ref(false); + +let dragType: 'col' | 'row' | null = null; +let dragKey: string | number | null = null; +let startPos = 0; +let startSize = 0; + +const MIN_COL_WIDTH = 120; +const MIN_ROW_HEIGHT = 48; + +const startResizeCol = (e: MouseEvent, key: string | number) => { + isDragging.value = true; + dragType = 'col'; + dragKey = key; + startPos = e.clientX; + startSize = colWidths.value[key] || MIN_COL_WIDTH; + document.addEventListener('mousemove', onMouseMove); + document.addEventListener('mouseup', onMouseUp); +}; + +const startResizeRow = (e: MouseEvent, key: string) => { + isDragging.value = true; + dragType = 'row'; + dragKey = key; + startPos = e.clientY; + startSize = rowHeights.value[key] || (e.target as HTMLElement).closest('td')?.offsetHeight || MIN_ROW_HEIGHT; + document.addEventListener('mousemove', onMouseMove); + document.addEventListener('mouseup', onMouseUp); +}; + +const onMouseMove = (e: MouseEvent) => { + if (!isDragging.value || dragKey === null) return; + if (dragType === 'col') { + const delta = e.clientX - startPos; + colWidths.value[dragKey] = Math.max(MIN_COL_WIDTH, startSize + delta); + } else if (dragType === 'row') { + const delta = e.clientY - startPos; + rowHeights.value[dragKey as string] = Math.max(MIN_ROW_HEIGHT, startSize + delta); + } +}; + +const onMouseUp = () => { + isDragging.value = false; + dragType = null; + dragKey = null; + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); +}; + const toggleTag = (id: number) => { if (selectedTags.value.includes(id)) { selectedTags.value = selectedTags.value.filter(tId => tId !== id); @@ -50,6 +102,8 @@ onMounted(() => { onUnmounted(() => { window.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); }); const exportStartCalendarDays = computed(() => { @@ -107,6 +161,17 @@ const handlePreview = async () => { } dateList.value = dates; + // 初始化列宽 + colWidths.value = { date: 150 }; + selectedTags.value.forEach(tagId => { + colWidths.value[tagId] = 200; + }); + // 初始化统一行高 + rowHeights.value = {}; + dates.forEach(d => { + rowHeights.value[d] = 100; + }); + // 过滤选中的主标签并构建矩阵 const matrix: Record> = {}; dates.forEach(d => matrix[d] = {}); @@ -146,7 +211,6 @@ const copyColumn = async (tagId: number | 'date') => { lines.push(date); } else { let cellStr = previewData.value[date][tagId] || ""; - // Excel/Sheets 处理带换行符的单元格,需要用双引号包围 if (cellStr.includes('\n') || cellStr.includes('\t') || cellStr.includes('"')) { cellStr = `"${cellStr.replace(/"/g, '""')}"`; } @@ -161,6 +225,30 @@ const copyColumn = async (tagId: number | 'date') => { showToast("复制失败", "error"); } }; + +const copyToClipboard = async () => { + const header = ["日期", ...selectedTags.value.map(id => getTagName(id))]; + let tsv = header.join("\t") + "\n"; + + for (const date of sortedDateList.value) { + let row = [date]; + for (const tagId of selectedTags.value) { + let cellStr = previewData.value[date][tagId] || ""; + if (cellStr.includes('\n') || cellStr.includes('\t') || cellStr.includes('"')) { + cellStr = `"${cellStr.replace(/"/g, '""')}"`; + } + row.push(cellStr); + } + tsv += row.join("\t") + "\n"; + } + + try { + await navigator.clipboard.writeText(tsv); + showToast("表格已复制,可直接粘贴到 Excel"); + } catch(err) { + showToast("复制失败", "error"); + } +}; + \ No newline at end of file