From d1ce79c837650689ab47bbf587d076743fcb3a5f Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期一, 19 五月 2025 17:25:38 +0800
Subject: [PATCH] 1. 问题审核界面新增场景信息编辑入口 2. 问题审核界面场景图片查询新增图片类型修改功能

---
 src/components/FYImageSelectDialog.vue |  282 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 235 insertions(+), 47 deletions(-)

diff --git a/src/components/FYImageSelectDialog.vue b/src/components/FYImageSelectDialog.vue
index f9f249c..6e283c3 100644
--- a/src/components/FYImageSelectDialog.vue
+++ b/src/components/FYImageSelectDialog.vue
@@ -1,99 +1,287 @@
 <template>
   <el-dialog
-    v-model="anyPhotoDialog"
-    width="66%"
-    title="浠绘剰鍥剧墖"
+    :model-value="dialogVisible"
+    @opened="handleOpen"
+    @closed="handleClose"
+    top="5vh"
+    width="68%"
     destroy-on-close
+    :close-on-press-escape="false"
   >
-    <div class="main">
-      <el-row justify="end" class="btns" v-if="!readonly">
+    <el-row justify="end">
+      <el-text v-if="onContextMenu != undefined" size="small" type="info">{{
+        `锛�${contextMenuStr}锛塦
+      }}</el-text>
+      <div v-if="!readonly">
         <el-text size="small" type="info" class="m-r-8"
           >鏈�澶氶�夋嫨{{ maxSelect }}寮犲浘鐗�</el-text
         >
         <el-button
           size="small"
           type="primary"
-          @click="sendSelectedImg(true)"
+          @click="handleSubmit"
           :disabled="selectedImgUrlList.length == 0"
           >纭畾</el-button
         >
-        <el-button size="small" type="primary" @click="sendSelectedImg(false)"
+        <el-button size="small" type="primary" @click="handleCancel"
           >鍙栨秷</el-button
         >
-      </el-row>
+      </div>
+    </el-row>
 
-      <div class="center">
-        <el-tabs v-if="typeList.length > 0" v-model="activeId" type="card">
-          <el-tab-pane
-            v-for="item in typeList"
-            :key="item.typeId"
-            :label="
-              item.typeName + ' (' + typeImgMap.get(activeId).length + ')'
-            "
-            :name="item.typeId"
-          >
-          </el-tab-pane>
-        </el-tabs>
-        <el-empty v-if="isEmpty" description="鏆傛棤璁板綍" />
-        <el-scrollbar class="imgs">
+    <div class="center">
+      <el-tabs v-if="typeList.length > 0" v-model="activeId" type="card">
+        <el-tab-pane
+          v-for="item in typeList"
+          :key="item.typeId"
+          :label="
+            item.typeName + ' (' + typeImgMap.get(item.typeId).length + ')'
+          "
+          :name="item.typeId"
+        >
+        </el-tab-pane>
+      </el-tabs>
+      <el-scrollbar height="70vh">
+        <div
+          v-if="typeImgMap.get(activeId) && typeImgMap.get(activeId).length > 0"
+          class="imgs"
+        >
           <el-image
+            v-loading="img.loading"
             v-for="(img, i) in typeImgMap.get(activeId)"
             :key="i"
             :class="[img.isSelect ? 'selected' : 'noActive', 'image']"
             fit="cover"
             :src="img.url"
-            lazy
+            :preview-src-list="
+              readonly ? typeImgMap.get(activeId).map((v) => v.url) : []
+            "
+            :initial-index="i"
+            @contextmenu="(e) => showContextMenu(e, i)"
             @click="onSelect(img, i)"
+            @load="onOneImgLoadSuccess(img)"
+            @error="onOneImgLoadError(img)"
           />
-        </el-scrollbar>
-      </div>
+        </div>
+        <el-row v-else justify="space-between">
+          <el-empty description="鏆傛棤璁板綍" />
+        </el-row>
+      </el-scrollbar>
     </div>
   </el-dialog>
 </template>
 <script setup>
-import { ref, watch } from 'vue';
+import { ref, watch, computed, onMounted, onUnmounted } from 'vue';
 
 const props = defineProps({
+  dialogVisible: Boolean,
+  /**
+   * 鍥剧墖鍒嗙被
+   * 缁撴瀯{ typeId, typeName }
+   */
   typeList: {
     type: Array,
     default: () => []
+  },
+  typeImgMap: {
+    type: Array,
+    default: () => new Map()
   },
   // 鏄惁浠ュ彧璇荤殑褰㈠紡鏌ョ湅褰撳墠椤甸潰
   readonly: {
     type: Boolean,
     default: false
   },
-  defaultFile: {
-    type: Array,
-    default: () => []
-  },
   // 鍥剧墖鍙�夋暟閲忥紝褰撲紶鍏ユ暟瀛楁椂锛屼唬琛ㄥ浘鐗囨暟閲�
   maxSelect: {
     type: Number,
     default: 3
+  },
+  // 鍥剧墖鍙抽敭鐐瑰嚮浜嬩欢
+  onContextMenu: {
+    type: Function
+  },
+  contextMenuStr: {
+    type: String,
+    default: '鍙抽敭鐐瑰嚮鍥剧墖瑙﹀彂棰濆鎿嶄綔'
   }
 });
+
+const emit = defineEmits(['submit', 'cancel', 'update:dialogVisible']);
 
 const activeId = ref('');
-const typeImgMap = ref(new Map());
-const selectedImgList = ref([]);
 
-watch(typeImgMap, (newMap, oldMap) => {
-  if (newMap.get(activeId.value) == undefined) {
-    return;
+const selectedImgUrlList = ref([]);
+
+let loadedImgCount = ref(0);
+// 鍔犺浇鐘舵��
+const loading = computed(() => {
+  if (activeId.value == '') {
+    return false;
   }
-  newMap.get(activeId.value).forEach(
-    (i) => {
-      if (i.isSelect == true) {
-        return;
-      }
-      props.defaultFile.forEach((imgItem) => {
-        if (imgItem.url == i.url) {
-          i.isSelect = true;
-        }
-      });
-    },
-    { deep: true }
+  // 淇濊瘉鏈�寮�濮嬫槸鍔犺浇鐘舵�侊紝涓夊垎涔嬩竴鍔犺浇涔嬪悗鍋滄灞曠ず鍔犺浇鐘舵��
+  return !(
+    props.typeImgMap.get(activeId.value).length / 3 <=
+    loadedImgCount.value
   );
 });
+function onOneImgLoadError(img) {
+  img.loading = false;
+  loadedImgCount.value++;
+}
+function onOneImgLoadSuccess(img) {
+  img.loading = false;
+  loadedImgCount.value++;
+}
+watch(
+  () => activeId.value,
+  (nV, oV) => {
+    loadedImgCount.value = 0;
+  },
+  { immediate: true }
+);
+
+function onSelect(img, i) {
+  if (props.readonly) {
+    return;
+  }
+  const imgList = selectedImgUrlList.value;
+  const index = imgList.indexOf(img);
+  if (index == -1) {
+    if (props.maxSelect == 1) {
+      img.isSelect = true;
+      imgList.push(img);
+      if (imgList.length > 1) {
+        imgList.splice(0, 1).forEach((e) => {
+          e.isSelect = false;
+        });
+      }
+    } else if (props.maxSelect > 1) {
+      if (imgList.length < props.maxSelect) {
+        img.isSelect = true;
+        imgList.push(img);
+      }
+    }
+  } else {
+    imgList.splice(index, 1);
+    img.isSelect = false;
+  }
+}
+function handleOpen() {
+  emit('update:dialogVisible', true);
+}
+function handleClose() {
+  selectedImgUrlList.value.forEach((item) => (item.isSelect = false));
+  selectedImgUrlList.value = [];
+  emit('update:dialogVisible', false);
+}
+function handleSubmit() {
+  emit('submit', selectedImgUrlList.value);
+  emit('update:dialogVisible', false);
+}
+
+function handleCancel() {
+  emit('cancel');
+  emit('update:dialogVisible', false);
+}
+
+// 鍥剧墖鍙抽敭鐐瑰嚮鏃堕棿
+function showContextMenu(event, index) {
+  if (props.onContextMenu) {
+    event.preventDefault();
+    props.onContextMenu(event, activeId.value, index);
+  }
+}
+
+watch(
+  () => props.typeList,
+  (nV, oV) => {
+    if (nV != oV && nV.length > 0) {
+      activeId.value = nV[0].typeId;
+    }
+  },
+  { immediate: true }
+);
 </script>
+<style scoped>
+.center {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.text {
+  padding: 20px;
+}
+
+.main {
+  /* 浣跨埗鍏冪礌灞呬腑 */
+  /* margin: 0 auto;  */
+  /* width: 100%; */
+}
+
+.imgs {
+  width: 100%;
+  /* border-style:solid;
+    border-radius: 1px; */
+  /* height: 100%; */
+  flex-grow: 1 !important;
+  overflow-y: auto !important;
+  /* 鍐呭鐨勫唴杈硅窛 */
+  display: flex !important;
+  flex-wrap: wrap !important;
+  /* overflow: hidden; */
+}
+
+.image {
+  margin: 5px;
+  height: 250px;
+  width: 240px;
+  border-radius: 4px;
+}
+
+.selected {
+  margin: 3px;
+  color: #4abe84;
+  box-shadow: 0 2px 7px 0 rgba(85, 110, 97, 0.35);
+  border: 2px solid rgba(74, 190, 132, 1);
+}
+
+.selected:before {
+  content: '';
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  border: 17px solid #4abe84;
+  border-top-color: transparent;
+  border-left-color: transparent;
+}
+
+.selected:after {
+  content: '';
+  width: 5px;
+  height: 12px;
+  position: absolute;
+  right: 6px;
+  bottom: 6px;
+  border: 2px solid #fff;
+  border-top-color: transparent;
+  border-left-color: transparent;
+  transform: rotate(45deg);
+}
+
+.noActive {
+  /* padding: 5px; */
+}
+
+.blurry {
+  filter: blur(3px);
+}
+.filters {
+  display: flex;
+  padding: 5px;
+}
+
+::v-deep .el-dialog__body {
+  padding: 10px calc(var(--el-dialog-padding-primary) + 10px) !important;
+}
+</style>

--
Gitblit v1.9.3