Explorar el Código

fix: 涉及到预览的样式统一

sgc hace 1 día
padre
commit
779b01491b
Se han modificado 26 ficheros con 268 adiciones y 243 borrados
  1. 29 0
      src/components/pcMediaPreview/PcImagePreviewViewer.vue
  2. 49 0
      src/components/pcMediaPreview/PcVideoPreviewDialog.vue
  3. 17 1
      src/views/dynamicManagement/index.vue
  4. 17 2
      src/views/dynamicManagement/myDynamic.vue
  5. 26 14
      src/views/dynamicManagement/publishDynamic.vue
  6. 5 8
      src/views/dynamicManagement/reviewAppeal.vue
  7. 5 8
      src/views/dynamicManagement/reviewAppealDetail.vue
  8. 5 8
      src/views/dynamicManagement/reviewAppealHistory.vue
  9. 17 1
      src/views/dynamicManagement/userDynamic.vue
  10. 3 3
      src/views/groupPackageManagement/newGroup.vue
  11. 3 3
      src/views/home/components/go-flow.vue
  12. 4 4
      src/views/licenseManagement/businessLicense.vue
  13. 4 4
      src/views/licenseManagement/contractManagement.vue
  14. 4 4
      src/views/licenseManagement/entertainmentLicense.vue
  15. 4 4
      src/views/licenseManagement/foodBusinessLicense.vue
  16. 3 3
      src/views/operationManagement/activityList.vue
  17. 8 8
      src/views/operationManagement/caseDetail.vue
  18. 4 4
      src/views/operationManagement/newActivity.vue
  19. 3 3
      src/views/storeDecoration/add.vue
  20. 6 12
      src/views/storeDecoration/decorationCompanyDetail.vue
  21. 22 52
      src/views/storeDecoration/detail.vue
  22. 3 3
      src/views/storeDecoration/facilitiesAndServices/components/FacilityManagement.vue
  23. 6 34
      src/views/storeDecoration/officialPhotoAlbum/index.vue
  24. 12 25
      src/views/storeDecoration/personnelConfig/index.vue
  25. 7 29
      src/views/storeDecoration/storeCoverMap/index.vue
  26. 2 6
      src/views/storeDecoration/storeHeadMap/index.vue

+ 29 - 0
src/components/pcMediaPreview/PcImagePreviewViewer.vue

@@ -0,0 +1,29 @@
+<template>
+  <el-image-viewer
+    v-if="visible && urlList.length"
+    :url-list="urlList"
+    :initial-index="initialIndex"
+    teleported
+    @close="handleClose"
+  />
+</template>
+
+<script setup lang="ts">
+withDefaults(
+  defineProps<{
+    /** 与 v-model:visible 同步 */
+    visible: boolean;
+    urlList: string[];
+    initialIndex?: number;
+  }>(),
+  { initialIndex: 0 }
+);
+
+const emit = defineEmits<{
+  "update:visible": [boolean];
+}>();
+
+function handleClose() {
+  emit("update:visible", false);
+}
+</script>

+ 49 - 0
src/components/pcMediaPreview/PcVideoPreviewDialog.vue

@@ -0,0 +1,49 @@
+<template>
+  <el-dialog
+    v-model="open"
+    :title="title"
+    width="min(92vw, 720px)"
+    class="pc-video-preview-dialog"
+    append-to-body
+    destroy-on-close
+    align-center
+    @closed="onDialogClosed"
+  >
+    <video v-if="src" :key="src" :src="src" class="pc-video-preview-dialog__video" controls playsinline :autoplay="autoplay" />
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+const open = defineModel<boolean>({ required: true });
+
+withDefaults(
+  defineProps<{
+    src: string;
+    title?: string;
+    /** 与旧版各页一致:需要自动播放的页面可传 true */
+    autoplay?: boolean;
+  }>(),
+  {
+    title: "查看",
+    autoplay: false
+  }
+);
+
+const emit = defineEmits<{
+  closed: [];
+}>();
+
+function onDialogClosed() {
+  emit("closed");
+}
+</script>
+
+<style scoped lang="scss">
+.pc-video-preview-dialog__video {
+  display: block;
+  width: 100%;
+  max-height: 72vh;
+  background: #0a0a0a;
+  border-radius: 8px;
+}
+</style>

+ 17 - 1
src/views/dynamicManagement/index.vue

@@ -494,6 +494,11 @@
         </div>
       </template>
     </el-dialog>
+    <PcImagePreviewViewer
+      v-model:visible="reportEvidencePreviewVisible"
+      :url-list="reportEvidencePreviewUrls"
+      :initial-index="reportEvidencePreviewIndex"
+    />
   </div>
 </template>
 
@@ -537,6 +542,7 @@ import {
 import { normalizeCommonCommentListResponse, countTopAndNestedComments } from "@/utils/commonCommentList";
 import { useUserStore } from "@/stores/modules/user";
 import { useWebSocketStore } from "@/stores/modules/websocket";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const router = useRouter();
 const userStore = useUserStore();
@@ -657,6 +663,9 @@ const reportForm = reactive({
   fileList: [] as any[],
   agreed: false
 });
+const reportEvidencePreviewVisible = ref(false);
+const reportEvidencePreviewUrls = ref<string[]>([]);
+const reportEvidencePreviewIndex = ref(0);
 
 // 分享对话框相关
 interface ShareFriend {
@@ -1394,7 +1403,14 @@ const handleReportDynamic = () => {
 
 // 举报图片预览
 const handleReportPreview = (uploadFile: any) => {
-  console.log("预览图片", uploadFile);
+  const list = (reportForm.fileList || []).map((f: any) => String(f.url || "").trim()).filter(Boolean);
+  const url = String(uploadFile?.url || "").trim();
+  const urls = list.length ? list : url ? [url] : [];
+  if (!urls.length) return;
+  const idx = url ? urls.indexOf(url) : 0;
+  reportEvidencePreviewUrls.value = urls;
+  reportEvidencePreviewIndex.value = Math.max(0, idx);
+  reportEvidencePreviewVisible.value = true;
 };
 
 // 移除举报图片

+ 17 - 2
src/views/dynamicManagement/myDynamic.vue

@@ -707,6 +707,11 @@
         </div>
       </template>
     </el-dialog>
+    <PcImagePreviewViewer
+      v-model:visible="reportEvidencePreviewVisible"
+      :url-list="reportEvidencePreviewUrls"
+      :initial-index="reportEvidencePreviewIndex"
+    />
   </div>
 </template>
 
@@ -758,6 +763,7 @@ import { useUserStore } from "@/stores/modules/user";
 import FriendCoupon from "./friendCoupon.vue";
 import { localGet } from "@/utils";
 import { normalizeCommonCommentListResponse, countTopAndNestedComments } from "@/utils/commonCommentList";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 const router = useRouter();
 const userStore = useUserStore();
 
@@ -917,6 +923,9 @@ const reportForm = reactive({
   fileList: [] as any[],
   agreed: false
 });
+const reportEvidencePreviewVisible = ref(false);
+const reportEvidencePreviewUrls = ref<string[]>([]);
+const reportEvidencePreviewIndex = ref(0);
 
 // 分享对话框相关
 interface ShareFriend {
@@ -1525,8 +1534,14 @@ const handleBlockUser = async (skipConfirm: boolean = false) => {
 
 // 举报图片预览
 const handleReportPreview = (uploadFile: any) => {
-  // 可以添加图片预览功能
-  console.log("预览图片", uploadFile);
+  const list = (reportForm.fileList || []).map((f: any) => String(f.url || "").trim()).filter(Boolean);
+  const url = String(uploadFile?.url || "").trim();
+  const urls = list.length ? list : url ? [url] : [];
+  if (!urls.length) return;
+  const idx = url ? urls.indexOf(url) : 0;
+  reportEvidencePreviewUrls.value = urls;
+  reportEvidencePreviewIndex.value = Math.max(0, idx);
+  reportEvidencePreviewVisible.value = true;
 };
 
 // 移除举报图片

+ 26 - 14
src/views/dynamicManagement/publishDynamic.vue

@@ -94,13 +94,18 @@
       </div>
     </div>
 
-    <!-- 图片/视频预览对话框 -->
-    <el-dialog v-model="previewDialogVisible" width="800px" append-to-body>
-      <!-- 视频预览 -->
-      <video v-if="previewIsVideo" :src="previewImageUrl" controls style="width: 100%; max-height: 70vh" />
-      <!-- 图片预览 -->
-      <img v-else :src="previewImageUrl" alt="预览图片" style="width: 100%" />
-    </el-dialog>
+    <PcImagePreviewViewer
+      v-model:visible="previewImageViewerVisible"
+      :url-list="previewImageUrl ? [previewImageUrl] : []"
+      :initial-index="0"
+    />
+    <PcVideoPreviewDialog
+      v-model="previewVideoDialogVisible"
+      :src="previewVideoUrl"
+      title="查看"
+      :autoplay="false"
+      @closed="previewVideoUrl = ''"
+    />
 
     <!-- 位置选择对话框 -->
     <el-dialog v-model="locationDialogVisible" title="选择位置" width="500px" append-to-body>
@@ -137,6 +142,8 @@ import { uploadFilesToOss, isUploadUserCancelledError } from "@/api/upload.js";
 import { useSimpleUploadOverlayStore } from "@/stores/modules/simpleUploadOverlay";
 import { useUserStore } from "@/stores/modules/user";
 import { getUserDraftDynamics, getInputPrompt } from "@/api/modules/newLoginApi";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 
 const router = useRouter();
 const route = useRoute();
@@ -188,9 +195,10 @@ interface LocationItem {
 // 响应式数据
 const formRef = ref<FormInstance>();
 const fileList = ref<UploadUserFile[]>([]);
-const previewDialogVisible = ref(false);
+const previewImageViewerVisible = ref(false);
+const previewVideoDialogVisible = ref(false);
 const previewImageUrl = ref("");
-const previewIsVideo = ref(false); // 预览的是否为视频
+const previewVideoUrl = ref("");
 const locationDialogVisible = ref(false);
 const locationSearch = ref("");
 const locationList = ref<LocationItem[]>([]);
@@ -514,12 +522,16 @@ const checkUploadPermission = (file: File, excludeRawFile?: File): { allowed: bo
   return { allowed: true };
 };
 
-// 图片/视频预览
+// 图片/视频预览(统一 PC 组件)
 const handlePicturePreview = (uploadFile: UploadUserFile) => {
-  previewImageUrl.value = uploadFile.url!;
-  // 判断是否为视频文件
-  previewIsVideo.value = isVideoFile(uploadFile);
-  previewDialogVisible.value = true;
+  const url = uploadFile.url!;
+  if (isVideoFile(uploadFile)) {
+    previewVideoUrl.value = url;
+    previewVideoDialogVisible.value = true;
+  } else {
+    previewImageUrl.value = url;
+    previewImageViewerVisible.value = true;
+  }
 };
 
 // 移除图片/视频(组件回调)

+ 5 - 8
src/views/dynamicManagement/reviewAppeal.vue

@@ -207,17 +207,13 @@
     </el-dialog>
 
     <!-- 视频预览弹窗 -->
-    <el-dialog
+    <PcVideoPreviewDialog
       v-model="videoPreviewVisible"
+      :src="videoPreviewUrl"
       title="视频预览"
-      width="80%"
-      max-width="720px"
-      destroy-on-close
-      align-center
+      :autoplay="true"
       @closed="closeVideoPreview"
-    >
-      <video v-if="videoPreviewUrl" :src="videoPreviewUrl" controls autoplay style="width: 100%; max-height: 70vh" />
-    </el-dialog>
+    />
   </div>
 </template>
 
@@ -231,6 +227,7 @@ import { getList, addAppealNew, saveComment2, getRatingCount } from "@/api/modul
 import { uploadFileToOss } from "@/api/upload.js";
 import { localGet } from "@/utils";
 import { useUserStore } from "@/stores/modules/user";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 
 const router = useRouter();
 const userStore = useUserStore();

+ 5 - 8
src/views/dynamicManagement/reviewAppealDetail.vue

@@ -141,17 +141,13 @@
     </div>
 
     <!-- 视频预览弹窗 -->
-    <el-dialog
+    <PcVideoPreviewDialog
       v-model="videoPreviewVisible"
+      :src="videoPreviewUrl"
       title="视频预览"
-      width="80%"
-      max-width="720px"
-      destroy-on-close
-      align-center
+      :autoplay="true"
       @closed="closeVideoPreview"
-    >
-      <video v-if="videoPreviewUrl" :src="videoPreviewUrl" controls autoplay style="width: 100%; max-height: 70vh" />
-    </el-dialog>
+    />
   </div>
 </template>
 
@@ -161,6 +157,7 @@ import { useRouter, useRoute } from "vue-router";
 import { Clock, User, VideoPlay } from "@element-plus/icons-vue";
 import { ElMessage } from "element-plus";
 import { getAppealDetail } from "@/api/modules/newLoginApi";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 
 const router = useRouter();
 const route = useRoute();

+ 5 - 8
src/views/dynamicManagement/reviewAppealHistory.vue

@@ -107,17 +107,13 @@
     </div>
 
     <!-- 视频预览弹窗 -->
-    <el-dialog
+    <PcVideoPreviewDialog
       v-model="videoPreviewVisible"
+      :src="videoPreviewUrl"
       title="视频预览"
-      width="80%"
-      max-width="720px"
-      destroy-on-close
-      align-center
+      :autoplay="true"
       @closed="closeVideoPreview"
-    >
-      <video v-if="videoPreviewUrl" :src="videoPreviewUrl" controls autoplay style="width: 100%; max-height: 70vh" />
-    </el-dialog>
+    />
   </div>
 </template>
 
@@ -128,6 +124,7 @@ import { User, Clock, CircleCheck, CircleClose, VideoPlay } from "@element-plus/
 import { ElMessage } from "element-plus";
 import { getAppealHistory } from "@/api/modules/newLoginApi";
 import { localGet } from "@/utils";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 
 const router = useRouter();
 

+ 17 - 1
src/views/dynamicManagement/userDynamic.vue

@@ -566,6 +566,11 @@
         </div>
       </template>
     </el-dialog>
+    <PcImagePreviewViewer
+      v-model:visible="reportEvidencePreviewVisible"
+      :url-list="reportEvidencePreviewUrls"
+      :initial-index="reportEvidencePreviewIndex"
+    />
   </div>
 </template>
 
@@ -609,6 +614,7 @@ import {
 import { useUserStore } from "@/stores/modules/user";
 import { localGet } from "@/utils";
 import { normalizeCommonCommentListResponse, countTopAndNestedComments } from "@/utils/commonCommentList";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const route = useRoute();
 const router = useRouter();
@@ -671,6 +677,9 @@ const reportForm = reactive({
   fileList: [] as any[],
   agreed: false
 });
+const reportEvidencePreviewVisible = ref(false);
+const reportEvidencePreviewUrls = ref<string[]>([]);
+const reportEvidencePreviewIndex = ref(0);
 
 // 评论相关
 const commentDrawerVisible = ref(false);
@@ -1455,7 +1464,14 @@ const handleBlockUser = async (skipConfirm: boolean = false) => {
 
 // 举报图片预览
 const handleReportPreview = (uploadFile: any) => {
-  console.log("预览图片", uploadFile);
+  const list = (reportForm.fileList || []).map((f: any) => String(f.url || "").trim()).filter(Boolean);
+  const url = String(uploadFile?.url || "").trim();
+  const urls = list.length ? list : url ? [url] : [];
+  if (!urls.length) return;
+  const idx = url ? urls.indexOf(url) : 0;
+  reportEvidencePreviewUrls.value = urls;
+  reportEvidencePreviewIndex.value = Math.max(0, idx);
+  reportEvidencePreviewVisible.value = true;
 };
 
 // 移除举报图片

+ 3 - 3
src/views/groupPackageManagement/newGroup.vue

@@ -413,11 +413,10 @@
       <el-button type="primary" @click="handleSubmit()" :disabled="hasUnuploadedImages"> 确定 </el-button>
     </div>
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
     <!-- 菜品选择对话框 -->
     <el-dialog v-model="dishDialogVisible" title="菜品" width="600px" :close-on-click-modal="false">
@@ -478,6 +477,7 @@ import { saveDraft, getHolidayList, getMenuByStoreId, getThaliById, saveThali }
 import { useRouter, useRoute } from "vue-router";
 import type { UploadProps, FormInstance, UploadInstance, UploadFile } from "element-plus";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 import {
   validatePositiveInteger,
   validateDateRangeArray,

+ 3 - 3
src/views/home/components/go-flow.vue

@@ -325,11 +325,10 @@
   </el-dialog>
 
   <!-- 图片预览 -->
-  <el-image-viewer
-    v-if="imageViewerVisible"
+  <PcImagePreviewViewer
+    v-model:visible="imageViewerVisible"
     :url-list="imageViewerUrlList"
     :initial-index="imageViewerInitialIndex"
-    @close="imageViewerVisible = false"
   />
 </template>
 
@@ -344,6 +343,7 @@ import GoBusinessHours from "./go-businessHours.vue";
 import { localGet, localSet } from "@/utils/index";
 import { useAuthStore } from "@/stores/modules/auth";
 import { useRouter } from "vue-router";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const authStore = useAuthStore();
 const router = useRouter();

+ 4 - 4
src/views/licenseManagement/businessLicense.vue

@@ -67,11 +67,10 @@
     </el-dialog>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
 
     <!-- 变更记录弹窗 -->
@@ -132,6 +131,7 @@ import {
   ocrRequestUrl
 } from "@/api/modules/licenseManagement";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const userInfo = localGet("geeker-user")?.userInfo || {};
 // 状态映射对象
@@ -504,7 +504,7 @@ const uploadSingleFile = async (file: UploadFile) => {
 };
 
 /**
- * 图片预览 - 使用 el-image-viewer 预览功能
+ * 图片预览 - 使用统一 PcImagePreviewViewer(Element Plus 图集层)
  * @param file 上传文件对象
  */
 const handlePictureCardPreview = (file: any) => {

+ 4 - 4
src/views/licenseManagement/contractManagement.vue

@@ -80,11 +80,10 @@
     </el-dialog>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
 
     <!-- 变更记录弹窗 -->
@@ -137,6 +136,7 @@ import { ElMessage, ElMessageBox } from "element-plus";
 import { Plus, Picture } from "@element-plus/icons-vue";
 import type { UploadProps, UploadFile } from "element-plus";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 import {
   getContractImages,
   uploadContractImage,
@@ -474,7 +474,7 @@ const uploadSingleFile = async (file: UploadFile) => {
 };
 
 /**
- * 图片预览 - 使用 el-image-viewer 预览功能
+ * 图片预览 - 使用统一 PcImagePreviewViewer(Element Plus 图集层)
  * @param file 上传文件对象
  */
 const handlePictureCardPreview = (file: any) => {

+ 4 - 4
src/views/licenseManagement/entertainmentLicense.vue

@@ -67,11 +67,10 @@
     </el-dialog>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
 
     <!-- 变更记录弹窗 -->
@@ -131,6 +130,7 @@ import {
 } from "@/api/modules/licenseManagement";
 import { uploadFileToOss } from "@/api/upload.js";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 // 状态映射对象
 const statusMap: Record<number, { name: string; class: string }> = {
@@ -449,7 +449,7 @@ const uploadSingleFile = async (file: UploadFile) => {
 };
 
 /**
- * 图片预览 - 使用 el-image-viewer 预览功能
+ * 图片预览 - 使用统一 PcImagePreviewViewer(Element Plus 图集层)
  * @param file 上传文件对象
  */
 const handlePictureCardPreview = (file: any) => {

+ 4 - 4
src/views/licenseManagement/foodBusinessLicense.vue

@@ -67,11 +67,10 @@
     </el-dialog>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
 
     <!-- 变更记录弹窗 -->
@@ -132,6 +131,7 @@ import {
   ocrRequestUrl
 } from "@/api/modules/licenseManagement";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const userInfo = localGet("geeker-user")?.userInfo || {};
 // 状态映射对象
@@ -507,7 +507,7 @@ const uploadSingleFile = async (file: UploadFile) => {
 };
 
 /**
- * 图片预览 - 使用 el-image-viewer 预览功能
+ * 图片预览 - 使用统一 PcImagePreviewViewer(Element Plus 图集层)
  * @param file 上传文件对象
  */
 const handlePictureCardPreview = (file: any) => {

+ 3 - 3
src/views/operationManagement/activityList.vue

@@ -160,11 +160,10 @@
     </el-drawer>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="resultImageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="resultImageViewerVisible"
       :url-list="resultImageViewerUrlList"
       :initial-index="resultImageViewerInitialIndex"
-      @close="resultImageViewerVisible = false"
     />
   </div>
 </template>
@@ -180,6 +179,7 @@ import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
 import { getActivityList, deleteActivity, updateActivityStatus, uploadActivityResult } from "@/api/modules/operationManagement";
 import { uploadContractImage } from "@/api/modules/licenseManagement";
 import { localGet, usePermission } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const router = useRouter();
 const proTable = ref<ProTableInstance>();

+ 8 - 8
src/views/operationManagement/caseDetail.vue

@@ -91,9 +91,13 @@
       <el-empty v-else-if="!loading" description="暂无数据" />
     </el-card>
 
-    <el-dialog v-model="videoDialogVisible" title="视频预览" width="640px" destroy-on-close @close="previewVideo = ''">
-      <video v-if="previewVideo" :src="previewVideo" controls autoplay class="dialog-video" />
-    </el-dialog>
+    <PcVideoPreviewDialog
+      v-model="videoDialogVisible"
+      :src="previewVideo"
+      title="视频预览"
+      :autoplay="true"
+      @closed="previewVideo = ''"
+    />
   </div>
 </template>
 
@@ -102,6 +106,7 @@ import { ref, onMounted, computed } from "vue";
 import { useRoute, useRouter } from "vue-router";
 import { Picture, VideoPlay } from "@element-plus/icons-vue";
 import { getPersonCaseDetail } from "@/api/modules/operationManagement";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 
 const route = useRoute();
 const router = useRouter();
@@ -418,9 +423,4 @@ onMounted(async () => {
   color: #909399;
   background: #f5f7fa;
 }
-.dialog-video {
-  display: block;
-  width: 100%;
-  max-height: 70vh;
-}
 </style>

+ 4 - 4
src/views/operationManagement/newActivity.vue

@@ -339,11 +339,10 @@
     </el-form>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
-      :initial-index="imageViewerInitialIndex"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
-      @close="imageViewerVisible = false"
+      :initial-index="imageViewerInitialIndex"
     />
   </div>
 </template>
@@ -367,6 +366,7 @@ import {
 } from "@/api/modules/operationManagement";
 import { uploadFileToOss } from "@/api/upload.js";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 // ==================== 响应式数据定义 ====================
 

+ 3 - 3
src/views/storeDecoration/add.vue

@@ -188,11 +188,10 @@
     </el-dialog>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
 
     <!-- 用户服务协议弹窗 -->
@@ -564,6 +563,7 @@ import { saveOrUpdateDecoration, getDistrict } from "@/api/modules/storeDecorati
 import { uploadFileToOss } from "@/api/upload.js";
 import { useSimpleUploadOverlayStore } from "@/stores/modules/simpleUploadOverlay";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const route = useRoute();
 const router = useRouter();

+ 6 - 12
src/views/storeDecoration/decorationCompanyDetail.vue

@@ -133,15 +133,13 @@
       </div>
     </div>
 
-    <el-dialog
+    <PcVideoPreviewDialog
       v-model="videoDialogVisible"
+      :src="previewVideoUrl"
       title="视频预览"
-      width="min(640px, 92vw)"
-      destroy-on-close
-      @close="previewVideoUrl = ''"
-    >
-      <video v-if="previewVideoUrl" :src="previewVideoUrl" controls autoplay class="dialog-video" />
-    </el-dialog>
+      :autoplay="true"
+      @closed="previewVideoUrl = ''"
+    />
   </div>
 </template>
 
@@ -151,6 +149,7 @@ import { useRoute, useRouter } from "vue-router";
 import { ElMessage } from "element-plus";
 import { Plus, Close, VideoPlay } from "@element-plus/icons-vue";
 import { getDecorationDetail } from "@/api/modules/storeDecoration";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 
 const route = useRoute();
 const router = useRouter();
@@ -403,11 +402,6 @@ onMounted(() => {
     font-size: 28px;
     color: #ffffff;
   }
-  .dialog-video {
-    display: block;
-    width: 100%;
-    max-height: 70vh;
-  }
   .detail-footer {
     padding: 20px 0 0;
     margin-top: 20px;

+ 22 - 52
src/views/storeDecoration/detail.vue

@@ -17,9 +17,9 @@
 
             <el-form-item label="装修类型">
               <el-radio-group v-model="formData.renovationType" disabled>
-                <el-radio :label="1">新房装修</el-radio>
-                <el-radio :label="2">旧房改造</el-radio>
-                <el-radio :label="3">局部装修</el-radio>
+                <el-radio :label="1"> 新房装修 </el-radio>
+                <el-radio :label="2"> 旧房改造 </el-radio>
+                <el-radio :label="3"> 局部装修 </el-radio>
               </el-radio-group>
             </el-form-item>
 
@@ -32,13 +32,7 @@
             </el-form-item>
 
             <el-form-item label="详细需求">
-              <el-input
-                v-model="formData.detailedRequirement"
-                type="textarea"
-                :rows="4"
-                placeholder="请输入"
-                disabled
-              />
+              <el-input v-model="formData.detailedRequirement" type="textarea" :rows="4" placeholder="请输入" disabled />
             </el-form-item>
 
             <el-form-item label="期望装修时间" required>
@@ -80,13 +74,7 @@
             </el-form-item>
 
             <el-form-item label="详细地址">
-              <el-input
-                v-model="formData.detailedAddress"
-                type="textarea"
-                :rows="3"
-                placeholder="请输入"
-                disabled
-              />
+              <el-input v-model="formData.detailedAddress" type="textarea" :rows="3" placeholder="请输入" disabled />
             </el-form-item>
           </el-col>
 
@@ -105,13 +93,7 @@
             </el-form-item>
 
             <el-form-item v-if="formData.auditStatus === 2" label="拒绝原因">
-              <el-input
-                v-model="formData.rejectionReason"
-                type="textarea"
-                :rows="4"
-                placeholder="请输入"
-                disabled
-              />
+              <el-input v-model="formData.rejectionReason" type="textarea" :rows="4" placeholder="请输入" disabled />
               <div class="form-tip">根据审核状态 对应展示</div>
             </el-form-item>
           </el-col>
@@ -119,17 +101,16 @@
       </el-form>
 
       <div class="detail-footer">
-        <el-button @click="handleClose">取消</el-button>
-        <el-button type="primary" @click="handleConfirm">确定</el-button>
+        <el-button @click="handleClose"> 取消 </el-button>
+        <el-button type="primary" @click="handleConfirm"> 确定 </el-button>
       </div>
     </div>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
   </div>
 </template>
@@ -141,6 +122,7 @@ import { ElMessage } from "element-plus";
 import { Plus, Close } from "@element-plus/icons-vue";
 import type { UploadFile } from "element-plus";
 import { getDecorationDetail } from "@/api/modules/storeDecoration";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 const route = useRoute();
 const router = useRouter();
@@ -272,79 +254,67 @@ onMounted(() => {
   width: 100%;
   min-height: 100%;
   background-color: white;
-
   .content-box {
     padding: 20px;
   }
-
   .detail-header {
     display: flex;
-    justify-content: space-between;
     align-items: center;
-    margin-bottom: 20px;
+    justify-content: space-between;
     padding-bottom: 15px;
+    margin-bottom: 20px;
     border-bottom: 1px solid #ebeef5;
-
     h3 {
       margin: 0;
       font-size: 18px;
       font-weight: 500;
     }
   }
-
   :deep(.el-form-item) {
     margin-bottom: 20px;
   }
-
   :deep(.el-radio-group) {
     display: flex;
     gap: 20px;
   }
-
   .upload-tip {
-    font-size: 12px;
-    color: #999;
     margin-top: 5px;
+    font-size: 12px;
+    color: #999999;
   }
-
   .form-tip {
-    font-size: 12px;
-    color: #999;
     margin-top: 5px;
+    font-size: 12px;
+    color: #999999;
     text-align: right;
   }
-
   .detail-footer {
-    text-align: center;
     padding: 20px 0 0;
     margin-top: 20px;
+    text-align: center;
     border-top: 1px solid #ebeef5;
   }
-
   .upload-wrapper {
     :deep(.el-upload) {
       display: inline-block;
     }
-
     :deep(.el-upload-list--picture-card) {
       display: grid;
       grid-template-columns: repeat(3, 1fr);
       gap: 10px;
-      margin: 0;
       width: 100%;
+      margin: 0;
     }
-
     :deep(.el-upload--picture-card) {
+      display: none; // 禁用状态下隐藏上传按钮
       width: 100%;
       margin: 0;
-      display: none; // 禁用状态下隐藏上传按钮
     }
-
     :deep(.el-upload-list--picture-card .el-upload-list__item) {
       width: 100%;
-      margin: 0;
-      aspect-ratio: 1;
       height: auto;
+      aspect-ratio: 1;
+      margin: 0;
     }
 
     // 确保图片缩略图正确显示

+ 3 - 3
src/views/storeDecoration/facilitiesAndServices/components/FacilityManagement.vue

@@ -205,11 +205,10 @@
     </el-dialog>
 
     <!-- 图片预览 -->
-    <el-image-viewer
-      v-if="imageViewerVisible"
+    <PcImagePreviewViewer
+      v-model:visible="imageViewerVisible"
       :url-list="imageViewerUrlList"
       :initial-index="imageViewerInitialIndex"
-      @close="imageViewerVisible = false"
     />
   </div>
 </template>
@@ -221,6 +220,7 @@ import type { FormInstance, FormRules, UploadRequestOptions, UploadUserFile } fr
 import { Plus, Picture, Delete, ArrowDown } from "@element-plus/icons-vue";
 import UploadImg from "@/components/Upload/Img.vue";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 import { uploadFileToOss, uploadFormDataToOss } from "@/api/upload.js";
 import {
   getSportsFacilityAreaList,

+ 6 - 34
src/views/storeDecoration/officialPhotoAlbum/index.vue

@@ -95,12 +95,11 @@
       </template>
     </el-dialog>
 
-    <!-- 图片预览 -->
-    <el-dialog v-model="previewVisible" width="600px" align-center class="preview-dialog">
-      <div class="preview-content">
-        <img v-if="previewImageUrl" :src="previewImageUrl" alt="预览" class="preview-image" />
-      </div>
-    </el-dialog>
+    <PcImagePreviewViewer
+      v-model:visible="previewVisible"
+      :url-list="previewImageUrl ? [previewImageUrl] : []"
+      :initial-index="0"
+    />
   </div>
 </template>
 
@@ -121,6 +120,7 @@ import {
   deleteOfficialImg
 } from "@/api/modules/storeDecoration";
 import { uploadFileToOssWithDownloadMeta } from "@/api/upload.js";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 /** 普通官方相册图 */
 const OFFICIAL_IMG_TYPE_ALBUM = 2;
@@ -1035,32 +1035,4 @@ onMounted(async () => {
   display: flex;
   justify-content: flex-end;
 }
-
-// 预览弹窗样式
-:deep(.preview-dialog) {
-  .el-dialog {
-    max-width: 90vw;
-    margin: 5vh auto;
-  }
-  .el-dialog__body {
-    max-height: 80vh;
-    padding: 20px;
-    overflow: auto;
-  }
-  .preview-content {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    max-width: 100%;
-    max-height: 70vh;
-    overflow: hidden;
-  }
-  .preview-image {
-    width: auto;
-    max-width: 100%;
-    height: auto;
-    max-height: 70vh;
-    object-fit: contain;
-  }
-}
 </style>

+ 12 - 25
src/views/storeDecoration/personnelConfig/index.vue

@@ -217,22 +217,19 @@
     </el-dialog>
 
     <!-- 背景图片预览弹窗 -->
-    <el-image-viewer v-if="previewImageVisible" :url-list="[previewImageUrl]" @close="previewImageVisible = false" />
+    <PcImagePreviewViewer
+      v-model:visible="previewImageVisible"
+      :url-list="previewImageUrl ? [previewImageUrl] : []"
+      :initial-index="0"
+    />
 
-    <!-- 背景视频放大预览弹窗 -->
-    <el-dialog
+    <PcVideoPreviewDialog
       v-model="previewVideoVisible"
+      :src="previewVideoUrl"
       title="视频预览"
-      width="70%"
-      top="5vh"
-      destroy-on-close
-      align-center
-      @close="previewVideoUrl = ''"
-    >
-      <div class="video-preview-wrap">
-        <video v-if="previewVideoUrl" :src="previewVideoUrl" controls autoplay class="video-preview-player" />
-      </div>
-    </el-dialog>
+      :autoplay="true"
+      @closed="previewVideoUrl = ''"
+    />
 
     <!-- 新建/编辑人员弹窗 -->
     <el-dialog v-model="dialogVisible" :title="dialogTitle" width="720px" @close="resetForm">
@@ -336,6 +333,8 @@ import UploadImgs from "@/components/Upload/Imgs.vue";
 import { uploadFileToOss, uploadFilesToOss } from "@/api/upload.js";
 import type { UploadUserFile } from "element-plus";
 import { localGet } from "@/utils";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 import {
   getPersonnelList,
   getStaffConfigList,
@@ -2419,16 +2418,4 @@ onMounted(async () => {
     display: contents;
   }
 }
-.video-preview-wrap {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  min-height: 200px;
-  background: #000000;
-  .video-preview-player {
-    width: 100%;
-    max-width: 100%;
-    max-height: 75vh;
-  }
-}
 </style>

+ 7 - 29
src/views/storeDecoration/storeCoverMap/index.vue

@@ -112,32 +112,17 @@
       </div>
     </div>
 
-    <!-- 图片预览:与 storeHeadMap 一致(根级挂载,同级于内容区) -->
-    <el-image-viewer
-      v-if="coverImagePreviewVisible"
+    <PcImagePreviewViewer
+      v-model:visible="coverImagePreviewVisible"
       :url-list="coverImagePreviewUrls"
       :initial-index="coverImagePreviewInitialIndex"
-      @close="coverImagePreviewVisible = false"
     />
 
-    <!-- 视频无法用 image-viewer,保留弹窗 -->
-    <el-dialog
+    <PcVideoPreviewDialog
       v-model="coverVideoPreviewVisible"
-      title="查看"
-      width="min(92vw, 720px)"
-      class="cover-preview-dialog"
-      destroy-on-close
-      append-to-body
+      :src="previewTarget?.url || ''"
       @closed="onCoverVideoPreviewClosed"
-    >
-      <video
-        v-if="previewTarget?.url"
-        :src="previewTarget.url"
-        class="cover-preview-dialog__media cover-preview-dialog__video"
-        controls
-        playsinline
-      />
-    </el-dialog>
+    />
   </div>
 </template>
 
@@ -151,6 +136,8 @@ import { localGet } from "@/utils";
 import { uploadFilesToOss, isUploadUserCancelledError, isUploadApiErrorAlreadyMessaged } from "@/api/upload.js";
 import { getCoverAuditData } from "@/api/modules/coverAudit";
 import previewDemoImg from "@/assets/images/uDianShiImg4.svg";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
+import PcVideoPreviewDialog from "@/components/pcMediaPreview/PcVideoPreviewDialog.vue";
 
 /** 与商户端封面 imgType 一致 */
 const IMG_TYPE_COVER = 38;
@@ -811,15 +798,6 @@ onMounted(async () => {
   cursor: not-allowed !important;
   opacity: 1 !important;
 }
-.cover-preview-dialog__media {
-  display: block;
-  width: 100%;
-  max-height: 70vh;
-  object-fit: contain;
-}
-.cover-preview-dialog__video {
-  background: #000000;
-}
 
 @media screen and (width <= 640px) {
   .upload-layout {

+ 2 - 6
src/views/storeDecoration/storeHeadMap/index.vue

@@ -47,12 +47,7 @@
       </div>
     </div>
 
-    <el-image-viewer
-      v-if="headPreviewVisible"
-      :url-list="imageUrls"
-      :initial-index="headPreviewInitialIndex"
-      @close="headPreviewVisible = false"
-    />
+    <PcImagePreviewViewer v-model:visible="headPreviewVisible" :url-list="imageUrls" :initial-index="headPreviewInitialIndex" />
   </div>
 </template>
 
@@ -63,6 +58,7 @@ import { getStoreHeadImg } from "@/api/modules/storeDecoration";
 import { getDetail } from "@/api/modules/homeEntry";
 import { localGet } from "@/utils";
 import previewDemoImg from "@/assets/images/uDianShiImg4.svg";
+import PcImagePreviewViewer from "@/components/pcMediaPreview/PcImagePreviewViewer.vue";
 
 /** 与商户端头图 imgType 一致 */
 const IMG_TYPE_HEAD = 22;