1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<template>
  <div>
    <el-dialog title="查看附件"
               v-model="dialogVisitable" width="800px" @close="cancel">
      <div class="upload-container">
        <div class="form-container">
          <div class="title">巡检附件</div>
          <!-- 图片列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <img v-for="(item, index) in beforeProductionImgs" :key="index"
                 @click="showMedia(beforeProductionImgs, index, 'image')"
                 :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt="">
          </div>
          
          <!-- 视频列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <div
                v-for="(videoUrl, index) in beforeProductionVideos"
                :key="index"
                @click="showMedia(beforeProductionVideos, index, 'video')"
                style="position: relative; margin: 10px; cursor: pointer;"
            >
              <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;">
                <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" />
              </div>
              <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div>
            </div>
          </div>
        </div>
      </div>
    </el-dialog>
    <!-- 统一媒体查看器 -->
    <div v-if="isMediaViewerVisible" class="media-viewer-overlay" @click.self="closeMediaViewer">
      <div class="media-viewer-content" @click.stop>
        <!-- 图片 -->
        <vue-easy-lightbox
            v-if="mediaType === 'image'"
            :visible="isMediaViewerVisible"
            :imgs="mediaList"
            :index="currentMediaIndex"
            @hide="closeMediaViewer"
        ></vue-easy-lightbox>
        
        <!-- 视频 -->
        <div v-else-if="mediaType === 'video'" style="position: relative;">
          <Video
              :src="mediaList[currentMediaIndex]"
              autoplay
              controls
              style="max-width: 90vw; max-height: 80vh;"
          />
        </div>
      </div>
    </div>
  </div>
</template>
 
<script setup>
// 控制弹窗显示
import VueEasyLightbox from "vue-easy-lightbox";
 
const dialogVisitable = ref(false);
// 图片数组
const beforeProductionImgs = ref([]);
// 视频数组
const beforeProductionVideos = ref([]);
// 媒体查看器状态
const isMediaViewerVisible = ref(false);
const currentMediaIndex = ref(0);
const mediaList = ref([]); // 存储当前要查看的媒体列表(含图片和视频对象)
const mediaType = ref('image'); // image | video
 
// 打开弹窗并加载数据
const openDialog = async (row) => {
  const { images: beforeImgs, videos: beforeVids } = processItems(row.storageBlobDTO);
  
  beforeProductionImgs.value = beforeImgs;
  beforeProductionVideos.value = beforeVids;
  dialogVisitable.value = true;
};
// 显示媒体(图片 or 视频)
function showMedia(mediaArray, index, type) {
  mediaList.value = mediaArray;
  currentMediaIndex.value = index;
  mediaType.value = type;
  isMediaViewerVisible.value = true;
}
// 关闭媒体查看器
function closeMediaViewer() {
  isMediaViewerVisible.value = false;
  mediaList.value = [];
  mediaType.value = 'image';
}
// 表单关闭方法
const cancel = () => {
  dialogVisitable.value = false;
};
// 处理每一类数据:分离图片和视频
function processItems(items) {
  const images = [];
  const videos = [];
  items.forEach(item => {
    if (item.contentType?.startsWith('image/')) {
      images.push(item.url);
    } else if (item.contentType?.startsWith('video/')) {
      videos.push(item.url);
    }
  });
  return { images, videos };
}
defineExpose({ openDialog });
</script>
 
<style scoped lang="scss">
.upload-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  border: 1px solid #dcdfe6;
  box-sizing: border-box;
  
  .form-container {
    flex: 1;
    width: 100%;
    margin-bottom: 20px;
  }
}
 
.title {
  font-size: 14px;
  color: #165dff;
  line-height: 20px;
  font-weight: 600;
  padding-left: 10px;
  position: relative;
  margin: 6px 0;
  
  &::before {
    content: "";
    position: absolute;
    left: 0;
    top: 3px;
    width: 4px;
    height: 14px;
    background-color: #165dff;
  }
}
 
.media-viewer-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}
 
.media-viewer-content {
  position: relative;
  max-width: 90vw;
  max-height: 90vh;
  overflow: hidden;
}
</style>