preview.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <template>
  2. <view class="page_preview">
  3. <common-header :title="fileName" @back="goBack"></common-header>
  4. <web-view
  5. v-if="previewUrl"
  6. :src="previewUrl"
  7. class="preview_webview"
  8. @error="handleWebViewError"
  9. @load="handleWebViewLoad"
  10. ></web-view>
  11. <view v-if="showRetry" class="retry_container">
  12. <text class="retry_text">预览加载失败,正在尝试其他服务...</text>
  13. </view>
  14. <view v-if="showLoading" class="loading_container">
  15. <text class="loading_text">加载中...</text>
  16. </view>
  17. </view>
  18. </template>
  19. <script setup>
  20. import { ref, computed, onMounted } from 'vue';
  21. import { onLoad } from '@dcloudio/uni-app';
  22. import CommonHeader from '@/components/common-header.vue';
  23. const fileUrl = ref('');
  24. const fileName = ref('文件预览');
  25. const currentServiceIndex = ref(0);
  26. const showRetry = ref(false);
  27. const showLoading = ref(true);
  28. const isPdf = computed(() => {
  29. const ext = fileUrl.value.split('.').pop()?.toLowerCase();
  30. return ext === 'pdf';
  31. });
  32. const previewServices = [
  33. (fileUrl) => `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(fileUrl)}`,
  34. (fileUrl) => `http://api.idocv.com/view/url?url=${encodeURIComponent(fileUrl)}&name=${encodeURIComponent(fileName.value)}`,
  35. (fileUrl) => fileUrl
  36. ];
  37. const previewUrl = computed(() => {
  38. const ext = fileUrl.value.split('.').pop()?.toLowerCase();
  39. if (!ext) return fileUrl.value;
  40. if (ext === 'pdf') {
  41. return `/static/pdfh5/index.html?url=${encodeURIComponent(fileUrl.value)}`;
  42. }
  43. if (['docx', 'doc', 'xlsx', 'xls', 'ppt', 'pptx', 'txt', 'csv', 'wps', 'dps', 'et'].includes(ext)) {
  44. return previewServices[currentServiceIndex.value](fileUrl.value);
  45. }
  46. return fileUrl.value;
  47. });
  48. const handleWebViewError = () => {
  49. if (!isPdf.value && currentServiceIndex.value < previewServices.length - 1) {
  50. showRetry.value = true;
  51. currentServiceIndex.value++;
  52. setTimeout(() => {
  53. showRetry.value = false;
  54. }, 2000);
  55. } else {
  56. showLoading.value = false;
  57. uni.showToast({
  58. title: '预览失败,请重试',
  59. icon: 'none'
  60. });
  61. }
  62. };
  63. const handleWebViewLoad = () => {
  64. showLoading.value = false;
  65. showRetry.value = false;
  66. };
  67. onLoad((options) => {
  68. if (options && options.url) {
  69. fileUrl.value = decodeURIComponent(options.url);
  70. }
  71. if (options && options.name) {
  72. fileName.value = decodeURIComponent(options.name);
  73. }
  74. });
  75. onMounted(() => {
  76. if (!previewUrl.value) {
  77. showLoading.value = false;
  78. }
  79. });
  80. const goBack = () => {
  81. uni.navigateBack();
  82. };
  83. </script>
  84. <style lang="scss">
  85. .page_preview {
  86. height: 100vh;
  87. display: flex;
  88. flex-direction: column;
  89. background-color: #FFFFFF;
  90. }
  91. .preview_webview {
  92. flex: 1;
  93. margin-top: 96rpx;
  94. }
  95. .retry_container {
  96. position: fixed;
  97. top: 120rpx;
  98. left: 50%;
  99. transform: translateX(-50%);
  100. background-color: rgba(0, 0, 0, 0.7);
  101. padding: 20rpx 40rpx;
  102. border-radius: 12rpx;
  103. z-index: 100;
  104. .retry_text {
  105. font-size: 26rpx;
  106. color: #FFFFFF;
  107. }
  108. }
  109. .loading_container {
  110. position: fixed;
  111. top: 50%;
  112. left: 50%;
  113. transform: translate(-50%, -50%);
  114. background-color: rgba(0, 0, 0, 0.5);
  115. padding: 40rpx 60rpx;
  116. border-radius: 12rpx;
  117. z-index: 1000;
  118. .loading_text {
  119. font-size: 28rpx;
  120. color: #FFFFFF;
  121. }
  122. }
  123. </style>