From ec00255aab24865cd785e181704e502354b9c8f6 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期五, 13 三月 2026 13:52:49 +0800
Subject: [PATCH] Merge branch 'dev_KT' of http://114.132.189.42:9002/r/product-inventory-APP-before into dev_KT

---
 src/pages/inspectionManagement/components/viewFiles.vue |  296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 296 insertions(+), 0 deletions(-)

diff --git a/src/pages/inspectionManagement/components/viewFiles.vue b/src/pages/inspectionManagement/components/viewFiles.vue
new file mode 100644
index 0000000..f39d9a4
--- /dev/null
+++ b/src/pages/inspectionManagement/components/viewFiles.vue
@@ -0,0 +1,296 @@
+<template>
+  <u-popup :show="dialogVisitable"
+           mode="bottom"
+           :round="16"
+           @close="cancel">
+    <view class="popup-content">
+      <view class="popup-header">
+        <text class="popup-title">鏌ョ湅闄勪欢</text>
+        <view class="close-icon"
+              @click="cancel">
+          <u-icon name="close"
+                  size="14"
+                  color="#666" />
+        </view>
+      </view>
+      <view class="popup-body">
+        <view class="tabs">
+          <view v-for="tab in tabs"
+                :key="tab.key"
+                class="tab-item"
+                :class="{ active: currentType === tab.key }"
+                @click="currentType = tab.key">
+            {{ tab.label }} ({{ getCurrentList(tab.key).length }})
+          </view>
+        </view>
+        <view class="file-list"
+              v-if="getCurrentList(currentType).length">
+          <view v-for="(file, index) in getCurrentList(currentType)"
+                :key="index"
+                class="file-item"
+                @click="previewFile(file)">
+            <image v-if="isImageFile(file)"
+                   :src="file.url"
+                   class="thumb"
+                   mode="aspectFill" />
+            <view v-else
+                  class="video-thumb">
+              <u-icon name="video"
+                      size="28"
+                      color="#1677ff" />
+              <text class="video-text">瑙嗛</text>
+            </view>
+            <text class="name">{{ file.name || "闄勪欢" }}</text>
+          </view>
+        </view>
+        <view v-else
+              class="empty">
+          <text>鏆傛棤闄勪欢</text>
+        </view>
+      </view>
+    </view>
+  </u-popup>
+  <u-popup :show="showVideoPopup"
+           mode="center"
+           :round="10"
+           @close="closeVideoPopup">
+    <view class="video-container">
+      <video :src="videoUrl"
+             controls
+             autoplay
+             class="video-player" />
+    </view>
+  </u-popup>
+</template>
+
+<script setup>
+  import { ref } from "vue";
+  import config from "@/config";
+
+  const dialogVisitable = ref(false);
+  const currentType = ref("before");
+  const showVideoPopup = ref(false);
+  const videoUrl = ref("");
+  const filesMap = ref({
+    before: [],
+    after: [],
+    issue: [],
+  });
+
+  const tabs = [
+    { key: "before", label: "鐢熶骇鍓�" },
+    { key: "after", label: "鐢熶骇涓�" },
+    { key: "issue", label: "鐢熶骇鍚�" },
+  ];
+
+  const normalizeUrl = raw => {
+    if (!raw) return "";
+    const url = String(raw).trim();
+    if (!url) return "";
+    if (/^https?:\/\//i.test(url)) return url;
+    if (url.startsWith("/")) return `${config.fileUrl}${url}`;
+    if (/^[a-zA-Z]:\\/.test(url)) {
+      const normalized = url.replace(/\\/g, "/");
+      const idx = normalized.indexOf("/prod/");
+      if (idx >= 0) {
+        const relative = normalized.slice(idx + "/prod/".length);
+        return `${config.fileUrl}/${relative}`;
+      }
+      return normalized;
+    }
+    return `${config.fileUrl}/${url.replace(/^\//, "")}`;
+  };
+
+  const isImageFile = file => {
+    if (file?.contentType?.startsWith("image/")) return true;
+    const name = String(file?.name || file?.bucketFilename || "").toLowerCase();
+    return /\.(jpg|jpeg|png|gif|bmp|webp)$/.test(name);
+  };
+
+  const normalizeFile = (file, type) => ({
+    ...file,
+    type,
+    url: normalizeUrl(file?.url || file?.downloadUrl),
+    name: file?.originalFilename || file?.bucketFilename || file?.name,
+  });
+
+  const getCurrentList = type => filesMap.value[type] || [];
+
+  const previewFile = file => {
+    if (isImageFile(file)) {
+      const urls = getCurrentList(currentType.value)
+        .filter(item => isImageFile(item))
+        .map(item => item.url);
+      uni.previewImage({
+        urls,
+        current: file.url,
+      });
+      return;
+    }
+    videoUrl.value = file.url;
+    showVideoPopup.value = true;
+  };
+
+  const closeVideoPopup = () => {
+    showVideoPopup.value = false;
+    videoUrl.value = "";
+  };
+
+  const openDialog = row => {
+    const allList = Array.isArray(row?.commonFileList) ? row.commonFileList : [];
+    const beforeList = Array.isArray(row?.commonFileListBefore)
+      ? row.commonFileListBefore
+      : allList.filter(item => item?.type === 10);
+    const afterList = Array.isArray(row?.commonFileListAfter)
+      ? row.commonFileListAfter
+      : allList.filter(item => item?.type === 11);
+    const issueList = Array.isArray(row?.commonFileListIssue)
+      ? row.commonFileListIssue
+      : allList.filter(item => item?.type === 12);
+    filesMap.value = {
+      before: beforeList.map(item => normalizeFile(item, "before")).filter(item => item.url),
+      after: afterList.map(item => normalizeFile(item, "after")).filter(item => item.url),
+      issue: issueList.map(item => normalizeFile(item, "issue")).filter(item => item.url),
+    };
+    currentType.value = "before";
+    dialogVisitable.value = true;
+  };
+
+  const cancel = () => {
+    dialogVisitable.value = false;
+    closeVideoPopup();
+    filesMap.value = {
+      before: [],
+      after: [],
+      issue: [],
+    };
+  };
+
+  defineExpose({ openDialog });
+</script>
+
+<style scoped lang="scss">
+  .popup-content {
+    width: 100vw;
+    max-height: 82vh;
+    background: #fff;
+    border-radius: 24rpx 24rpx 0 0;
+    overflow: hidden;
+    padding-bottom: env(safe-area-inset-bottom);
+  }
+
+  .popup-header {
+    padding: 24rpx 20rpx;
+    border-bottom: 1rpx solid #f0f0f0;
+    text-align: center;
+    position: relative;
+  }
+
+  .popup-title {
+    font-size: 32rpx;
+    color: #1f1f1f;
+    font-weight: 600;
+  }
+
+  .popup-body {
+    padding: 20rpx 20rpx 26rpx;
+    max-height: 68vh;
+    overflow-y: auto;
+  }
+
+  .tabs {
+    display: flex;
+    background: #f4f5f8;
+    border-radius: 12rpx;
+    padding: 6rpx;
+    margin-bottom: 20rpx;
+  }
+
+  .tab-item {
+    flex: 1;
+    text-align: center;
+    padding: 12rpx 0;
+    color: #666;
+    font-size: 24rpx;
+    border-radius: 10rpx;
+  }
+
+  .tab-item.active {
+    background: #1677ff;
+    color: #fff;
+    font-weight: 600;
+  }
+
+  .file-list {
+    display: grid;
+    grid-template-columns: repeat(2, 1fr);
+    gap: 16rpx;
+  }
+
+  .file-item {
+    background: #fafafa;
+    border-radius: 12rpx;
+    padding: 10rpx;
+  }
+
+  .thumb {
+    width: 100%;
+    height: 180rpx;
+    border-radius: 8rpx;
+  }
+
+  .video-thumb {
+    width: 100%;
+    height: 180rpx;
+    border-radius: 8rpx;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    background: #edf3ff;
+  }
+
+  .video-text {
+    font-size: 22rpx;
+    color: #1677ff;
+    margin-top: 6rpx;
+  }
+
+  .name {
+    margin-top: 8rpx;
+    font-size: 22rpx;
+    color: #333;
+    display: block;
+    word-break: break-all;
+  }
+
+  .empty {
+    text-align: center;
+    color: #999;
+    padding: 40rpx 0;
+  }
+
+  .video-container {
+    width: 94vw;
+    background: #000;
+  }
+
+  .video-player {
+    width: 94vw;
+    height: 55vw;
+  }
+
+  .close-icon {
+    position: absolute;
+    right: 24rpx;
+    top: 50%;
+    transform: translateY(-50%);
+    width: 44rpx;
+    height: 44rpx;
+    border-radius: 50%;
+    background: #f5f5f5;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+</style>

--
Gitblit v1.9.3