refactor: 重构文件操作逻辑,统一使用 useFileOperation
- 删除收藏页和产品详情页中重复的文件操作代码(~290行) - 统一使用 useFileOperation composable - 简化 onDownload/onView 函数为 viewFile 调用 - 保持功能完全一致 影响文件: - src/pages/favorites/index.vue - src/pages/product-detail/index.vue Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
2 changed files
with
8 additions
and
279 deletions
| ... | @@ -42,7 +42,7 @@ | ... | @@ -42,7 +42,7 @@ |
| 42 | <!-- Action Buttons --> | 42 | <!-- Action Buttons --> |
| 43 | <view class="flex flex-col items-end gap-[16rpx] ml-[16rpx] flex-shrink-0"> | 43 | <view class="flex flex-col items-end gap-[16rpx] ml-[16rpx] flex-shrink-0"> |
| 44 | <!-- View Button --> | 44 | <!-- View Button --> |
| 45 | - <view class="flex items-center justify-center px-[20rpx] py-[10rpx] bg-blue-50 rounded-full active:bg-blue-100 transition-colors" @tap.stop="onView(item)"> | 45 | + <view class="flex items-center justify-center px-[20rpx] py-[10rpx] bg-blue-50 rounded-full active:bg-blue-100 transition-colors" @tap.stop="viewFile({...item, fileName: item.title})"> |
| 46 | <IconFont name="eye" size="14" color="#2563EB" class="mr-[6rpx]" /> | 46 | <IconFont name="eye" size="14" color="#2563EB" class="mr-[6rpx]" /> |
| 47 | <text class="text-[24rpx] text-blue-600 font-medium leading-none">查看</text> | 47 | <text class="text-[24rpx] text-blue-600 font-medium leading-none">查看</text> |
| 48 | </view> | 48 | </view> |
| ... | @@ -70,13 +70,15 @@ | ... | @@ -70,13 +70,15 @@ |
| 70 | 70 | ||
| 71 | <script setup> | 71 | <script setup> |
| 72 | import { ref, computed } from 'vue' | 72 | import { ref, computed } from 'vue' |
| 73 | +import Taro from '@tarojs/taro' | ||
| 73 | import { useGo } from '@/hooks/useGo' | 74 | import { useGo } from '@/hooks/useGo' |
| 75 | +import { useFileOperation } from '@/composables/useFileOperation' | ||
| 74 | import IconFont from '@/components/IconFont.vue' | 76 | import IconFont from '@/components/IconFont.vue' |
| 75 | import TabBar from '@/components/TabBar.vue' | 77 | import TabBar from '@/components/TabBar.vue' |
| 76 | import NavHeader from '@/components/NavHeader.vue' | 78 | import NavHeader from '@/components/NavHeader.vue' |
| 77 | -import Taro from '@tarojs/taro' | ||
| 78 | 79 | ||
| 79 | const go = useGo() | 80 | const go = useGo() |
| 81 | +const { viewFile } = useFileOperation() | ||
| 80 | const activeTab = ref('all') | 82 | const activeTab = ref('all') |
| 81 | 83 | ||
| 82 | const tabs = [ | 84 | const tabs = [ |
| ... | @@ -141,88 +143,6 @@ const filteredList = computed(() => { | ... | @@ -141,88 +143,6 @@ const filteredList = computed(() => { |
| 141 | return list.value.filter(item => item.type === activeTab.value) | 143 | return list.value.filter(item => item.type === activeTab.value) |
| 142 | }) | 144 | }) |
| 143 | 145 | ||
| 144 | -const onView = (item) => { | ||
| 145 | - // 检查是否有下载地址 | ||
| 146 | - if (!item.downloadUrl) { | ||
| 147 | - Taro.showToast({ | ||
| 148 | - title: '该文件暂无查看地址', | ||
| 149 | - icon: 'none', | ||
| 150 | - duration: 2000 | ||
| 151 | - }) | ||
| 152 | - return | ||
| 153 | - } | ||
| 154 | - | ||
| 155 | - // 显示加载提示 | ||
| 156 | - Taro.showLoading({ | ||
| 157 | - title: '打开中...', | ||
| 158 | - mask: true | ||
| 159 | - }) | ||
| 160 | - | ||
| 161 | - // 下载并打开文件 | ||
| 162 | - downloadAndOpenFile(item) | ||
| 163 | -} | ||
| 164 | - | ||
| 165 | -// 打开文件的通用函数 | ||
| 166 | -const openFile = async (filePath, item) => { | ||
| 167 | - try { | ||
| 168 | - await Taro.openDocument({ | ||
| 169 | - filePath: filePath, | ||
| 170 | - showMenu: true, // 显示右上角菜单,用户可以转发、保存等 | ||
| 171 | - success: () => { | ||
| 172 | - console.log('文件打开成功') | ||
| 173 | - // 文件打开后,延迟提示用户如果看不到内容该如何操作 | ||
| 174 | - const fileExt = item.title.split('.').pop()?.toLowerCase() || '' | ||
| 175 | - const unsupportedFormats = ['docx', 'doc', 'pptx', 'ppt', 'xlsx', 'xls'] | ||
| 176 | - | ||
| 177 | - if (unsupportedFormats.includes(fileExt)) { | ||
| 178 | - setTimeout(() => { | ||
| 179 | - Taro.showToast({ | ||
| 180 | - title: '如无法预览,请使用右上角菜单分享', | ||
| 181 | - icon: 'none', | ||
| 182 | - duration: 3000 | ||
| 183 | - }) | ||
| 184 | - }, 1500) | ||
| 185 | - } | ||
| 186 | - }, | ||
| 187 | - fail: (err) => { | ||
| 188 | - console.error('打开文件失败:', err) | ||
| 189 | - | ||
| 190 | - // 获取文件扩展名 | ||
| 191 | - const fileExt = item.title.split('.').pop()?.toLowerCase() || '' | ||
| 192 | - | ||
| 193 | - // 根据文件类型给出提示 | ||
| 194 | - let message = '文件打开失败' | ||
| 195 | - let suggestion = '' | ||
| 196 | - | ||
| 197 | - if (['docx', 'doc', 'pptx', 'ppt', 'xlsx', 'xls'].includes(fileExt)) { | ||
| 198 | - message = '暂不支持预览 Office 文档' | ||
| 199 | - suggestion = '\n\n建议:\n1. 点击右上角"..."菜单\n2. 选择"发送给朋友"\n3. 在电脑或支持的应用中打开' | ||
| 200 | - } else if (['pdf'].includes(fileExt)) { | ||
| 201 | - message = 'PDF 文件打开失败' | ||
| 202 | - suggestion = '\n\n文件可能已损坏,请联系管理员' | ||
| 203 | - } else { | ||
| 204 | - message = `暂不支持预览 ${fileExt.toUpperCase()} 格式文件` | ||
| 205 | - suggestion = '\n\n请在电脑或其他应用中打开' | ||
| 206 | - } | ||
| 207 | - | ||
| 208 | - Taro.showModal({ | ||
| 209 | - title: '提示', | ||
| 210 | - content: message + suggestion, | ||
| 211 | - showCancel: false, | ||
| 212 | - confirmText: '我知道了' | ||
| 213 | - }) | ||
| 214 | - } | ||
| 215 | - }) | ||
| 216 | - } catch (error) { | ||
| 217 | - console.error('打开文件异常:', error) | ||
| 218 | - Taro.showToast({ | ||
| 219 | - title: '打开文件失败', | ||
| 220 | - icon: 'none', | ||
| 221 | - duration: 2000 | ||
| 222 | - }) | ||
| 223 | - } | ||
| 224 | -} | ||
| 225 | - | ||
| 226 | const onDelete = (item) => { | 146 | const onDelete = (item) => { |
| 227 | Taro.showModal({ | 147 | Taro.showModal({ |
| 228 | title: '提示', | 148 | title: '提示', |
| ... | @@ -235,71 +155,6 @@ const onDelete = (item) => { | ... | @@ -235,71 +155,6 @@ const onDelete = (item) => { |
| 235 | } | 155 | } |
| 236 | }) | 156 | }) |
| 237 | } | 157 | } |
| 238 | - | ||
| 239 | -// 下载并打开文件的内部函数 | ||
| 240 | -const downloadAndOpenFile = async (item) => { | ||
| 241 | - try { | ||
| 242 | - // 下载文件 | ||
| 243 | - const downloadResult = await Taro.downloadFile({ | ||
| 244 | - url: item.downloadUrl | ||
| 245 | - }) | ||
| 246 | - | ||
| 247 | - // 检查下载结果 | ||
| 248 | - if (downloadResult.statusCode !== 200) { | ||
| 249 | - throw new Error(`打开失败: HTTP ${downloadResult.statusCode}`) | ||
| 250 | - } | ||
| 251 | - | ||
| 252 | - if (!downloadResult.tempFilePath) { | ||
| 253 | - throw new Error('打开失败: 未获取到文件') | ||
| 254 | - } | ||
| 255 | - | ||
| 256 | - // 隐藏加载提示 | ||
| 257 | - Taro.hideLoading() | ||
| 258 | - | ||
| 259 | - // 获取文件扩展名 | ||
| 260 | - const fileExt = item.title.split('.').pop()?.toLowerCase() || '' | ||
| 261 | - | ||
| 262 | - // 微信小程序对 Office 文档支持有限,提前提示用户 | ||
| 263 | - const unsupportedFormats = ['docx', 'doc', 'pptx', 'ppt', 'xlsx', 'xls'] | ||
| 264 | - | ||
| 265 | - if (unsupportedFormats.includes(fileExt)) { | ||
| 266 | - // 对于 Office 文档,先提示用户,但仍尝试打开 | ||
| 267 | - Taro.showModal({ | ||
| 268 | - title: '预览提示', | ||
| 269 | - content: `小程序对 ${fileExt.toUpperCase()} 文档的预览支持有限,如果显示为空白,请点击右上角"..."菜单,选择"发送给朋友"后在电脑或其他应用中打开。\n\n是否继续尝试预览?`, | ||
| 270 | - confirmText: '继续', | ||
| 271 | - cancelText: '取消', | ||
| 272 | - success: (modalRes) => { | ||
| 273 | - if (modalRes.confirm) { | ||
| 274 | - openFile(downloadResult.tempFilePath, item) | ||
| 275 | - } | ||
| 276 | - } | ||
| 277 | - }) | ||
| 278 | - } else { | ||
| 279 | - // 其他格式直接打开 | ||
| 280 | - await openFile(downloadResult.tempFilePath, item) | ||
| 281 | - } | ||
| 282 | - } catch (error) { | ||
| 283 | - // 确保隐藏加载提示 | ||
| 284 | - Taro.hideLoading() | ||
| 285 | - | ||
| 286 | - console.error('打开文件出错:', error) | ||
| 287 | - | ||
| 288 | - // 根据错误类型显示不同的提示 | ||
| 289 | - let errorMessage = '打开失败,请重试' | ||
| 290 | - if (error.errMsg && error.errMsg.includes('network')) { | ||
| 291 | - errorMessage = '网络连接失败,请检查网络' | ||
| 292 | - } else if (error.errMsg && error.errMsg.includes('TLS')) { | ||
| 293 | - errorMessage = '安全连接失败,请检查网络' | ||
| 294 | - } | ||
| 295 | - | ||
| 296 | - Taro.showToast({ | ||
| 297 | - title: errorMessage, | ||
| 298 | - icon: 'none', | ||
| 299 | - duration: 2000 | ||
| 300 | - }) | ||
| 301 | - } | ||
| 302 | -} | ||
| 303 | </script> | 158 | </script> |
| 304 | 159 | ||
| 305 | <style lang="less"> | 160 | <style lang="less"> | ... | ... |
| ... | @@ -101,7 +101,7 @@ | ... | @@ -101,7 +101,7 @@ |
| 101 | <span class="text-[#9CA3AF] text-[24rpx]">{{ file.size }}</span> | 101 | <span class="text-[#9CA3AF] text-[24rpx]">{{ file.size }}</span> |
| 102 | </div> | 102 | </div> |
| 103 | </div> | 103 | </div> |
| 104 | - <IconFont name="download" size="20" color="#2563EB" @tap="onDownload(file)" /> | 104 | + <IconFont name="download" size="20" color="#2563EB" @tap="viewFile(file)" /> |
| 105 | </div> | 105 | </div> |
| 106 | </div> | 106 | </div> |
| 107 | </div> | 107 | </div> |
| ... | @@ -118,8 +118,11 @@ import { ref } from 'vue' | ... | @@ -118,8 +118,11 @@ import { ref } from 'vue' |
| 118 | import NavHeader from '@/components/NavHeader.vue' | 118 | import NavHeader from '@/components/NavHeader.vue' |
| 119 | import TabBar from '@/components/TabBar.vue' | 119 | import TabBar from '@/components/TabBar.vue' |
| 120 | import IconFont from '@/components/IconFont.vue' | 120 | import IconFont from '@/components/IconFont.vue' |
| 121 | +import { useFileOperation } from '@/composables/useFileOperation' | ||
| 121 | import Taro, { useLoad } from '@tarojs/taro' | 122 | import Taro, { useLoad } from '@tarojs/taro' |
| 122 | 123 | ||
| 124 | +const { viewFile } = useFileOperation() | ||
| 125 | + | ||
| 123 | // 接收页面参数 | 126 | // 接收页面参数 |
| 124 | const productId = ref(null) | 127 | const productId = ref(null) |
| 125 | 128 | ||
| ... | @@ -231,9 +234,6 @@ const files = ref([ | ... | @@ -231,9 +234,6 @@ const files = ref([ |
| 231 | // 收藏状态 | 234 | // 收藏状态 |
| 232 | const isCollected = ref(false) | 235 | const isCollected = ref(false) |
| 233 | 236 | ||
| 234 | -// 记录是否已经提示过 Office 文档预览限制 | ||
| 235 | -const hasShownOfficeTip = ref(false) | ||
| 236 | - | ||
| 237 | // 切换收藏状态 | 237 | // 切换收藏状态 |
| 238 | const toggleCollect = () => { | 238 | const toggleCollect = () => { |
| 239 | isCollected.value = !isCollected.value | 239 | isCollected.value = !isCollected.value |
| ... | @@ -249,130 +249,4 @@ const toggleCollect = () => { | ... | @@ -249,130 +249,4 @@ const toggleCollect = () => { |
| 249 | }) | 249 | }) |
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | - | ||
| 253 | -// 打开文件的通用函数 | ||
| 254 | -const openFile = async (filePath, file) => { | ||
| 255 | - try { | ||
| 256 | - await Taro.openDocument({ | ||
| 257 | - filePath: filePath, | ||
| 258 | - showMenu: true, | ||
| 259 | - success: () => { | ||
| 260 | - console.log('文件打开成功') | ||
| 261 | - }, | ||
| 262 | - fail: (err) => { | ||
| 263 | - console.error('打开文件失败:', err) | ||
| 264 | - | ||
| 265 | - const fileExt = file.fileName.split('.').pop()?.toLowerCase() || '' | ||
| 266 | - let message = '文件打开失败' | ||
| 267 | - let suggestion = '' | ||
| 268 | - | ||
| 269 | - if (['docx', 'doc', 'pptx', 'ppt', 'xlsx', 'xls'].includes(fileExt)) { | ||
| 270 | - message = '暂不支持预览 Office 文档' | ||
| 271 | - suggestion = '\n\n建议:\n1. 点击右上角"..."菜单\n2. 选择"发送给朋友"\n3. 在电脑或支持的应用中打开' | ||
| 272 | - } else if (['pdf'].includes(fileExt)) { | ||
| 273 | - message = 'PDF 文件打开失败' | ||
| 274 | - suggestion = '\n\n文件可能已损坏,请联系管理员' | ||
| 275 | - } else { | ||
| 276 | - message = `暂不支持预览 ${fileExt.toUpperCase()} 格式文件` | ||
| 277 | - suggestion = '\n\n请在电脑或其他应用中打开' | ||
| 278 | - } | ||
| 279 | - | ||
| 280 | - Taro.showModal({ | ||
| 281 | - title: '提示', | ||
| 282 | - content: message + suggestion, | ||
| 283 | - showCancel: false, | ||
| 284 | - confirmText: '我知道了' | ||
| 285 | - }) | ||
| 286 | - } | ||
| 287 | - }) | ||
| 288 | - } catch (error) { | ||
| 289 | - console.error('打开文件异常:', error) | ||
| 290 | - Taro.showToast({ | ||
| 291 | - title: '打开文件失败', | ||
| 292 | - icon: 'none', | ||
| 293 | - duration: 2000 | ||
| 294 | - }) | ||
| 295 | - } | ||
| 296 | -} | ||
| 297 | - | ||
| 298 | -// 下载并打开文件的函数 | ||
| 299 | -const downloadAndOpenFile = async (file) => { | ||
| 300 | - try { | ||
| 301 | - const downloadResult = await Taro.downloadFile({ | ||
| 302 | - url: file.downloadUrl | ||
| 303 | - }) | ||
| 304 | - | ||
| 305 | - if (downloadResult.statusCode !== 200) { | ||
| 306 | - throw new Error(`打开失败: HTTP ${downloadResult.statusCode}`) | ||
| 307 | - } | ||
| 308 | - | ||
| 309 | - if (!downloadResult.tempFilePath) { | ||
| 310 | - throw new Error('打开失败: 未获取到文件') | ||
| 311 | - } | ||
| 312 | - | ||
| 313 | - Taro.hideLoading() | ||
| 314 | - | ||
| 315 | - const fileExt = file.fileName.split('.').pop()?.toLowerCase() || '' | ||
| 316 | - const unsupportedFormats = ['docx', 'doc', 'pptx', 'ppt', 'xlsx', 'xls'] | ||
| 317 | - | ||
| 318 | - if (unsupportedFormats.includes(fileExt)) { | ||
| 319 | - // 对于 Office 文档,如果还没提示过,就提示一次 | ||
| 320 | - if (!hasShownOfficeTip.value) { | ||
| 321 | - Taro.showModal({ | ||
| 322 | - title: '预览提示', | ||
| 323 | - content: `小程序对 ${fileExt.toUpperCase()} 文档的预览支持有限,如果显示为空白,请点击右上角"..."菜单,选择"发送给朋友"后在电脑或其他应用中打开。\n\n是否继续尝试预览?`, | ||
| 324 | - confirmText: '继续', | ||
| 325 | - cancelText: '取消', | ||
| 326 | - success: (modalRes) => { | ||
| 327 | - if (modalRes.confirm) { | ||
| 328 | - hasShownOfficeTip.value = true // 标记已提示过 | ||
| 329 | - openFile(downloadResult.tempFilePath, file) | ||
| 330 | - } | ||
| 331 | - } | ||
| 332 | - }) | ||
| 333 | - } else { | ||
| 334 | - // 已经提示过,直接打开 | ||
| 335 | - await openFile(downloadResult.tempFilePath, file) | ||
| 336 | - } | ||
| 337 | - } else { | ||
| 338 | - // PDF 等其他格式直接打开 | ||
| 339 | - await openFile(downloadResult.tempFilePath, file) | ||
| 340 | - } | ||
| 341 | - } catch (error) { | ||
| 342 | - Taro.hideLoading() | ||
| 343 | - console.error('打开文件出错:', error) | ||
| 344 | - | ||
| 345 | - let errorMessage = '打开失败,请重试' | ||
| 346 | - if (error.errMsg && error.errMsg.includes('network')) { | ||
| 347 | - errorMessage = '网络连接失败,请检查网络' | ||
| 348 | - } else if (error.errMsg && error.errMsg.includes('TLS')) { | ||
| 349 | - errorMessage = '安全连接失败,请检查网络' | ||
| 350 | - } | ||
| 351 | - | ||
| 352 | - Taro.showToast({ | ||
| 353 | - title: errorMessage, | ||
| 354 | - icon: 'none', | ||
| 355 | - duration: 2000 | ||
| 356 | - }) | ||
| 357 | - } | ||
| 358 | -} | ||
| 359 | - | ||
| 360 | -// 下载按钮点击处理 | ||
| 361 | -const onDownload = (file) => { | ||
| 362 | - if (!file.downloadUrl) { | ||
| 363 | - Taro.showToast({ | ||
| 364 | - title: '该文件暂无下载地址', | ||
| 365 | - icon: 'none', | ||
| 366 | - duration: 2000 | ||
| 367 | - }) | ||
| 368 | - return | ||
| 369 | - } | ||
| 370 | - | ||
| 371 | - Taro.showLoading({ | ||
| 372 | - title: '打开中...', | ||
| 373 | - mask: true | ||
| 374 | - }) | ||
| 375 | - | ||
| 376 | - downloadAndOpenFile(file) | ||
| 377 | -} | ||
| 378 | </script> | 252 | </script> | ... | ... |
-
Please register or login to post a comment