From dee37e4e2bb74bf970189b4eb9967933ddc9be49 Mon Sep 17 00:00:00 2001 From: WindowBird <13870814+windows-bird@user.noreply.gitee.com> Date: Mon, 10 Nov 2025 14:55:19 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B7=9F=E8=BF=9B=E8=AF=A6=E7=BB=86=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E8=A1=A5=E5=85=85=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/CustomerManagement.vue | 2 +- components/customer-detail/FollowupTab.vue | 2 +- pages/customer/follow/detail/index.vue | 233 +++++++++++++++++++++ pages/customer/follow/edit/index.vue | 2 - 4 files changed, 235 insertions(+), 4 deletions(-) diff --git a/components/CustomerManagement.vue b/components/CustomerManagement.vue index f9c2bd8..0e02596 100644 --- a/components/CustomerManagement.vue +++ b/components/CustomerManagement.vue @@ -95,8 +95,8 @@ 电话 + + 更多 - diff --git a/components/customer-detail/FollowupTab.vue b/components/customer-detail/FollowupTab.vue index 67461c7..0eac1d6 100644 --- a/components/customer-detail/FollowupTab.vue +++ b/components/customer-detail/FollowupTab.vue @@ -30,7 +30,7 @@ 🗑️ - + {{ item.content }} diff --git a/pages/customer/follow/detail/index.vue b/pages/customer/follow/detail/index.vue index 1c0de6c..feb97fc 100644 --- a/pages/customer/follow/detail/index.vue +++ b/pages/customer/follow/detail/index.vue @@ -62,6 +62,26 @@ + + + 附件 + + + {{ getFileIcon(file.name || file.path) }} + + {{ file.name || getFileNameFromUrl(file.path) }} + {{ formatFileSize(file.size) }} + + + + + + 时间信息 @@ -206,6 +226,60 @@ const followupImages = computed(() => { return []; }); +// 计算附件列表 +const followupAttachments = computed(() => { + const detail = followupDetail.value; + const attachments = []; + + const normalizeAttachment = (item) => { + if (!item) return null; + + if (typeof item === 'string') { + const trimmed = item.trim(); + if (!trimmed) return null; + return { + path: trimmed, + name: getFileNameFromUrl(trimmed), + size: 0 + }; + } + + if (typeof item === 'object' && item.path) { + return { + path: item.path, + name: item.name || getFileNameFromUrl(item.path), + size: item.size || 0 + }; + } + + return null; + }; + + const attachSources = [ + detail.attaches, + detail.attachments, + detail.files + ]; + + attachSources.forEach((source) => { + if (!source) return; + + if (typeof source === 'string') { + source.split(',').forEach((url) => { + const normalized = normalizeAttachment(url); + if (normalized) attachments.push(normalized); + }); + } else if (Array.isArray(source)) { + source.forEach((item) => { + const normalized = normalizeAttachment(item); + if (normalized) attachments.push(normalized); + }); + } + }); + + return attachments; +}); + // 获取页面参数 onLoad((options) => { if (options && options.followId) { @@ -360,6 +434,118 @@ const previewFollowupImages = (images, currentIndex) => { }); }; +// 获取文件名 +function getFileNameFromUrl(url = '') { + try { + const decodedUrl = decodeURIComponent(url); + const parts = decodedUrl.split('/'); + return parts.pop() || decodedUrl; + } catch (err) { + return url; + } +} + +// 获取文件图标 +function getFileIcon(filename = '') { + const ext = filename.split('.').pop()?.toLowerCase() || ''; + const iconMap = { + pdf: '📄', + doc: '📝', + docx: '📝', + xls: '📊', + xlsx: '📊', + ppt: '📈', + pptx: '📈', + txt: '📄', + zip: '📦', + rar: '📦', + jpg: '🖼️', + jpeg: '🖼️', + png: '🖼️', + gif: '🖼️', + mp4: '🎞️', + mp3: '🎵' + }; + return iconMap[ext] || '📁'; +} + +// 格式化文件大小 +function formatFileSize(bytes) { + if (!bytes || bytes <= 0) return ''; + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`; +} + +// 预览或下载附件 +const previewAttachment = (file) => { + if (!file || !file.path) { + uni.showToast({ + title: '文件不存在', + icon: 'none' + }); + return; + } + + const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp']; + const filename = file.name || getFileNameFromUrl(file.path); + const ext = filename.split('.').pop()?.toLowerCase() || ''; + + if (imageExts.includes(ext)) { + uni.previewImage({ + urls: [file.path], + current: file.path + }); + return; + } + + // #ifdef H5 + window.open(file.path, '_blank'); + // #endif + + // #ifdef APP-PLUS + if (typeof plus !== 'undefined' && plus.runtime) { + plus.runtime.openURL(file.path); + return; + } + // #endif + + // 其他平台尝试下载并打开 + uni.downloadFile({ + url: file.path, + success: (res) => { + if (res.statusCode === 200) { + uni.openDocument({ + filePath: res.tempFilePath, + success: () => { + console.log('打开附件成功'); + }, + fail: (err) => { + console.error('打开附件失败:', err); + uni.showToast({ + title: '无法打开此文件', + icon: 'none' + }); + } + }); + } else { + uni.showToast({ + title: '下载文件失败', + icon: 'none' + }); + } + }, + fail: (err) => { + console.error('下载附件失败:', err); + uni.showToast({ + title: '下载文件失败', + icon: 'none' + }); + } + }); +}; + // 返回 const handleBack = () => { uni.navigateBack(); @@ -534,6 +720,53 @@ onMounted(() => { object-fit: cover; } +.attachments-list { + display: flex; + flex-direction: column; + gap: 12px; +} + +.attachment-item { + display: flex; + align-items: center; + padding: 12px 0; + border-bottom: 1px solid #f5f5f5; + + &:last-child { + border-bottom: none; + padding-bottom: 0; + } +} + +.file-icon { + font-size: 24px; + margin-right: 12px; +} + +.file-info { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; +} + +.file-name { + font-size: 14px; + color: #333; + word-break: break-word; +} + +.file-size { + font-size: 12px; + color: #999; +} + +.preview-arrow { + font-size: 20px; + color: #bbb; + margin-left: 12px; +} + .status-badge { display: inline-block; padding: 4px 12px; diff --git a/pages/customer/follow/edit/index.vue b/pages/customer/follow/edit/index.vue index 4da4b68..0cbd4cc 100644 --- a/pages/customer/follow/edit/index.vue +++ b/pages/customer/follow/edit/index.vue @@ -1207,7 +1207,5 @@ const handleCancel = () => { background-color: #fff; border-top: 1px solid #e0e0e0; } - -