From c942b7673a9c17075ccb965291b7b3a68a4797b6 Mon Sep 17 00:00:00 2001 From: kura Date: Fri, 3 Jan 2025 09:33:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=9B=BE=E7=89=87=E7=9A=84?= =?UTF-8?q?=E6=94=BE=E5=A4=A7=E7=BC=A9=E5=B0=8F=E7=A7=BB=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/file/item/fileReader.vue | 223 +++++++++++++++++++++++++---- src/pages/file/utils/peer.ts | 6 +- 2 files changed, 203 insertions(+), 26 deletions(-) diff --git a/src/pages/file/item/fileReader.vue b/src/pages/file/item/fileReader.vue index c87401b..4b5d0b1 100644 --- a/src/pages/file/item/fileReader.vue +++ b/src/pages/file/item/fileReader.vue @@ -4,7 +4,8 @@

{{ file.name }}

+ +
+
+ +
+
{{ fileContent }}
+
+ -
- +
+
@@ -30,6 +63,14 @@
+ +
+ +
+
@@ -61,29 +102,22 @@
- -
-
- -
-
{{ fileContent }}
-
- {{ - fileTypeCheck === "unsupported-size" - ? "文件过大,无法预览,请传输后查看" - : "不支持预览该类型的文件" - }} +
+ {{ + fileTypeCheck === "unsupported-size" + ? "文件过大,无法预览,请传输后查看" + : "不支持预览该类型的文件" + }} +
+
+ +
@@ -100,6 +134,7 @@ import hljs from "highlight.js"; import "highlight.js/styles/github.css"; import { Modal } from "ant-design-vue"; import { localCurrentFile, remoteCurrentFile } from "../utils/common"; +import { NEED_CHUNK_FILE_SIZE_PREVIEW } from "../utils/fileTransfer"; const props = defineProps<{ file: FileInfo; @@ -116,6 +151,15 @@ const selectedLanguage = ref("auto"); const isEditing = ref(false); const editingContent = ref(""); const editorHeight = ref(300); +const openWithText = ref(false); +const scale = ref(1); +const translateX = ref(0); +const translateY = ref(0); +const isTransitioning = ref(false); +const isDragging = ref(false); +const lastMouseX = ref(0); +const lastMouseY = ref(0); +const lastTouchDistance = ref(0); // 下载文件 const downloadFile = async () => { @@ -158,7 +202,7 @@ const canEdit = computed(() => { // 文件类型判断 const fileTypeCheck = computed(() => { //如果文件大于30M,则不预览 - if (props.file.size > 30 * 1024 * 1024) { + if (props.file.size > NEED_CHUNK_FILE_SIZE_PREVIEW) { return "unsupported-size"; } const ext = props.file.name.split(".").pop()?.toLowerCase() || ""; @@ -172,6 +216,10 @@ const fileTypeCheck = computed(() => { if (["mp4", "webm", "ogg"].includes(ext)) { return "video"; } + // 音频类型 + if (["mp3", "wav", "ogg"].includes(ext)) { + return "audio"; + } // 代码类型 if ( @@ -193,6 +241,31 @@ const fileTypeCheck = computed(() => { "lua", "sql", "shell", + "cfg", + "ini", + "conf", + "xml", + "yaml", + "toml", + "applescript", + "sh", + "bat", + "ps1", + "asp", + "aspx", + "php", + "jsp", + "cc", + "c++", + "cs", + "dart", + "sh", + "bash", + "kt", + "swift", + "rb", + "R", + "rust", ].includes(ext) ) { return "code"; @@ -277,6 +350,9 @@ const loadedFile = ref<{ // 加载文件内容 const loadFile = async () => { try { + if (fileTypeCheck.value === "unsupported-size") { + return; + } const file: FileData = (await props.file.getFile(true)) as FileData; loadedFile.value = file; if (file.buffer == null) { @@ -298,7 +374,98 @@ const loadFile = async () => { } }; +// 处理鼠标滚轮缩放 +const handleWheel = (e: WheelEvent) => { + const delta = e.deltaY > 0 ? -0.1 : 0.1; + const newScale = Math.max(0.1, Math.min(5, scale.value + delta)); + scale.value = newScale; +}; + +// 处理触摸开始 +const handleTouchStart = (e: TouchEvent) => { + if (e.touches.length === 2) { + const touch1 = e.touches[0]; + const touch2 = e.touches[1]; + lastTouchDistance.value = Math.hypot( + touch2.clientX - touch1.clientX, + touch2.clientY - touch1.clientY + ); + } else if (e.touches.length === 1) { + isDragging.value = true; + lastMouseX.value = e.touches[0].clientX; + lastMouseY.value = e.touches[0].clientY; + } +}; + +// 处理触摸移动 +const handleTouchMove = (e: TouchEvent) => { + if (e.touches.length === 2) { + const touch1 = e.touches[0]; + const touch2 = e.touches[1]; + const distance = Math.hypot( + touch2.clientX - touch1.clientX, + touch2.clientY - touch1.clientY + ); + + const delta = distance - lastTouchDistance.value; + const scaleDelta = delta * 0.01; + scale.value = Math.max(0.1, Math.min(5, scale.value + scaleDelta)); + lastTouchDistance.value = distance; + } else if (e.touches.length === 1 && isDragging.value) { + const deltaX = e.touches[0].clientX - lastMouseX.value; + const deltaY = e.touches[0].clientY - lastMouseY.value; + translateX.value += deltaX; + translateY.value += deltaY; + lastMouseX.value = e.touches[0].clientX; + lastMouseY.value = e.touches[0].clientY; + } +}; + +// 处理触摸结束 +const handleTouchEnd = () => { + isDragging.value = false; + lastTouchDistance.value = 0; +}; + +// 开始拖动 +const startDrag = (e: MouseEvent) => { + if (scale.value > 1) { + isDragging.value = true; + lastMouseX.value = e.clientX; + lastMouseY.value = e.clientY; + } +}; + +// 拖动中 +const onDrag = (e: MouseEvent) => { + if (isDragging.value) { + const deltaX = e.clientX - lastMouseX.value; + const deltaY = e.clientY - lastMouseY.value; + translateX.value += deltaX; + translateY.value += deltaY; + lastMouseX.value = e.clientX; + lastMouseY.value = e.clientY; + } +}; + +// 停止拖动 +const stopDrag = () => { + isDragging.value = false; +}; + +// 双击重置缩放 +const resetZoom = () => { + isTransitioning.value = true; + scale.value = 1; + translateX.value = 0; + translateY.value = 0; + setTimeout(() => { + isTransitioning.value = false; + }, 300); +}; + onMounted(() => { + openWithText.value = false; loadFile(); }); @@ -344,12 +511,17 @@ onUnmounted(() => { justify-content: center; align-items: center; height: 100%; + overflow: hidden; + user-select: none; + touch-action: none; } .image-viewer img { max-width: 100%; max-height: 100%; object-fit: contain; + will-change: transform; + transform-origin: center center; } .video-viewer { @@ -382,6 +554,7 @@ onUnmounted(() => { .unsupported { display: flex; + flex-direction: column; justify-content: center; align-items: center; height: 100%; diff --git a/src/pages/file/utils/peer.ts b/src/pages/file/utils/peer.ts index 0e9c3e6..4c211c2 100644 --- a/src/pages/file/utils/peer.ts +++ b/src/pages/file/utils/peer.ts @@ -160,6 +160,10 @@ class Peer extends EventTarget { async handleMessage(data: Message, conn: DataConnection) { const remoteD = data.data; let file: FileInfo | null = null; + if (data.type == MessageType.error) { + console.error('handleMessage recive error', data.data) + return + } let resData: Message = { type: MessageType.error, data: null, @@ -190,7 +194,7 @@ class Peer extends EventTarget { resData.data = await navigator.clipboard.readText().then(text => { return text }).catch(err => { - return '对方窗口未聚焦,无法复制' + return '没有粘贴板权限或窗口未聚焦,无法复制' }); break; case MessageType.request_fileInfo: