From 6f3fac4493995e16ee0f37c6cf2b06e5de2a6a72 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期三, 02 七月 2025 16:27:37 +0800
Subject: [PATCH] 1. 将场景图片的分类修改为从服务端动态获取; 2. 问题整改节目中的问题复现功能修改为可拖动对话框且移除背景模态框;

---
 src/views/fysp/check/components/ArbitraryPhoto.vue |  564 ++++++++++++++++++++++++-------------------------------
 1 files changed, 248 insertions(+), 316 deletions(-)

diff --git a/src/views/fysp/check/components/ArbitraryPhoto.vue b/src/views/fysp/check/components/ArbitraryPhoto.vue
index 7170d11..29c5a4e 100644
--- a/src/views/fysp/check/components/ArbitraryPhoto.vue
+++ b/src/views/fysp/check/components/ArbitraryPhoto.vue
@@ -1,359 +1,291 @@
 <template>
-  <div class="main">
-    <div class="filters" v-if="false">
-      <el-select
-        v-for="(key_select, index_select) of filters.keys()"
-        :placeholder="key_select.text"
-      >
-        <el-option
-          v-for="(key_option, index_option) in filters.get(key_select.key)"
-          :key="key_option.key"
-          :value="key_option.value"
-          :label="key_option.label"
+  <FYImageSelectDialog
+    v-bind="$attrs"
+    v-loading="loading"
+    title="鍦烘櫙鍥剧墖"
+    :typeList="typesList"
+    :typeImgMap="typesMap"
+    :onContextMenu="showContextMenu"
+    contextMenuStr="鍙抽敭鐐瑰嚮鍥剧墖淇敼鍒嗙被"
+  ></FYImageSelectDialog>
+  <!-- <div
+    
+    @click="closeContextMenu"
+    @contextmenu="closeContextMenu"
+    class="container"
+  > -->
+  <div
+    v-if="showMenu && !menuLoading"
+    ref="menu"
+    :style="menuStyle"
+    class="context-menu"
+  >
+    <template v-for="(item, index) in menuItems" :key="index">
+      <el-popover v-if="item.children" placement="right-start" trigger="hover">
+        <template #reference>
+          <el-row justify="space-between" class="menu-item">
+            <span>{{ item.label }}</span>
+            <el-icon><ArrowRight /></el-icon>
+          </el-row>
+        </template>
+        <div
+          v-for="(item1, index1) in item.children"
+          :key="index1"
+          class="menu-item"
+          @click.stop="handleMenuItem(item1)"
         >
-        </el-option>
-      </el-select>
-    </div>
-    <div class="btns" v-if="!readonly">
-      <el-button size="small" type="primary" @click="sendSelectedImg(true)">纭畾</el-button>
-      <el-button size="small" type="primary" @click="sendSelectedImg(false)">鍙栨秷</el-button>
-    </div>
+          {{ item1.label }}
+        </div>
+      </el-popover>
 
-    <div class="center">
-      <el-descriptions>
-        <el-descriptions-item label="鎬绘暟">
-          <span>{{ this.imgUrlList.length }}</span>
-        </el-descriptions-item>
-      </el-descriptions>
-      <el-tabs v-model="activeId" type="card">
-        <el-tab-pane
-          v-for="item in typeList"
-          :label="item.businesstype"
-          :name="item.businesstypeid"
-        >
-        </el-tab-pane>
-      </el-tabs>
-      <el-empty v-if="isEmpty" description="鏆傛棤璁板綍" />
-      <div class="imgs">
-        <el-image
-          v-for="(img, i) in typeImgMap.get(activeId)"
-          :class="[Boolean(img.isSelect) ? 'selected' : 'noActive', 'image']"
-          fit="cover"
-          :src="img.url"
-          lazy
-          @click="onSelect(img, i)"
-        />
+      <div class="menu-item" @click.stop="handleMenuItem(item)" v-else>
+        {{ item.label }}
       </div>
-    </div>
+    </template>
   </div>
+  <!-- </div> -->
 </template>
 <script>
-import problemApi from '@/api/fysp/problemApi.js';
 import mediafileApi from '@/api/fysp/mediafileApi.js';
 import { $fysp } from '@/api/index.js';
+import { enumMediaFile } from '@/enum/mediaFile.js';
+
 export default {
   props: {
-    filters: Map,
-    // 鏄惁浠ュ彧璇荤殑褰㈠紡鏌ョ湅褰撳墠椤甸潰
-    readonly: {
-      type: Boolean,
-      default: false
-    },
     subtask: {
-      type: Object,
-      efault: {}
-    },
-    inspectionGuid: {
-      type: String,
-      default: ''
-    },
-    defaultFile: {
-      type: Array,
-      default: () => []
+      type: Object
     }
   },
   data() {
     return {
-      // 鏃犳暟鎹�
-      isEmpty: false,
-      isClose: false,
-      isAll: false,
-      activeId: '',
-      typeList: [
-        // { businesstypeid: 5, businesstype: '甯歌璁板綍' },
-        // { businesstypeid: 3, businesstype: '鐩戞祴璁惧' },
-        // { businesstypeid: 7, businesstype: '閾墝' },
-        // { businesstypeid: 51, businesstype: '鎵╁睍绫讳竴' },
-        // { businesstypeid: 52, businesstype: '鎵╁睍绫讳簩' },
-        // { businesstypeid: 53, businesstype: '鎵╁睍绫讳笁' },
-        // { businesstypeid: 54, businesstype: '鎵╁睍绫诲洓' },
-        // { businesstypeid: 55, businesstype: '鎵╁睍绫讳簲' },
-        // { businesstypeid: 56, businesstype: '鎵╁睍绫诲叚' },
-        // { businesstypeid: 57, businesstype: '鎵╁睍绫讳竷' },
-        // { businesstypeid: 58, businesstype: '鎵╁睍绫诲叓' },
-        // { businesstypeid: 59, businesstype: '鎵╁睍绫讳節' },
-        // { businesstypeid: 60, businesstype: '鎵╁睍绫诲崄' }
-      ],
-      typeImgMap: new Map(),
-      imgUrlList: []
+      typesList: [],
+      typesMap: new Map(),
+      loading: true,
+      // 鍙抽敭鍥剧墖寮瑰嚭鑿滃崟鎺у埗
+      showMenu: false,
+      menuLoading: true,
+      menuStyle: undefined,
+      allMoveActions: [],
+      closeContextMenuListenr: undefined,
+      // 鍙抽敭閫変腑鐨勫浘鐗�
+      selectedFileElement: undefined,
+      selectedFile: undefined,
+      selectedIndex: undefined,
+      selectedTypeId: undefined
     };
   },
-  watch: {
-    defaultFile: {
-      handler(newFileList, oldFileList) {
-        if (this.isClose) {
-          return;
+  computed: {
+    menuItems() {
+      return [
+        // { label: '澶嶅埗鍒板壀璐存澘', action: 'copy' },
+        {
+          label: '绉诲姩鍒�',
+          children: this.allMoveActions.filter((v) => {
+            return v.value != this.selectedTypeId;
+          })
         }
-      },
-      deep: true
-    },
-    typeImgMap: {
-      handler(newMap, oldMap) {
-        if (this.isClose || newMap.get(this.activeId) == undefined) {
-          return;
-        }
-        newMap.get(this.activeId).forEach((i) => {
-          if (i.isSelect == true) {
-            return;
-          }
-          this.defaultFile.forEach((imgItem) => {
-            if (imgItem.url == i.url) {
-              i.isSelect = true;
-            }
-          });
-        });
-      },
-
-      deep: true
+      ];
     }
   },
   mounted() {
-    if (this.defaultFile == undefined || this.defaultFile == null) {
-      this.defaultFile = [];
-    }
-    if (this.subtask) {
-      this.getAllImgList();
-    }
+    this.getGroupImgs();
+    this.closeContextMenuListenr = (event) => {
+      if (
+        this.$refs.menu &&
+        !this.$refs.menu.contains(event.target) &&
+        this.showMenu
+      ) {
+        // 濡傛灉鐐瑰嚮涓嶆槸鍦ㄨ彍鍗曞唴閮ㄤ笖鑿滃崟鏄彲瑙佺殑
+        this.showMenu = false; // 闅愯棌鑿滃崟
+      }
+    };
+    document.addEventListener('click', this.closeContextMenuListenr);
+
+    this.initMenuItems();
+  },
+  unmounted() {
+    document.removeEventListener('click', this.closeContextMenuListenr);
   },
   methods: {
-    // 鍒濆鍖栧垰寮�濮嬮�変腑鐨勬爣绛�
-    initSelectedTab() {
-      if (this.typeList.length > 0) {
-        this.activeId = this.typeList[0].businesstypeid;
+    // 鍥剧墖鍒嗙被
+    getGroupImgs() {
+      mediafileApi
+        .getRoutineByStGuid(this.subtask.stGuid)
+        .then((res) => {
+          this.loading = true;
+          let typeList = [];
+          let typeMap = new Map();
+          const data = res.data;
+          for (const e of data) {
+            let img = {
+              url: $fysp.imgUrl + e.extension1 + e.guid + '.jpg',
+              data: e
+            };
+            const businesstype = e.businesstype;
+            const businesstypeid = e.businesstypeid;
+            if (
+              typeList.find((item) => item.typeId == businesstypeid) !=
+              undefined
+            ) {
+              typeMap.get(businesstypeid).push(img);
+            } else {
+              typeList.push({
+                typeId: businesstypeid,
+                typeName: businesstype
+              });
+              typeMap.set(businesstypeid, [img]);
+            }
+          }
+          this.typesList = typeList;
+          this.typesMap = typeMap;
+        })
+        .finally(() => (this.loading = false));
+    },
+    // 鍥剧墖鍙抽敭鐐瑰嚮浜嬩欢
+    showContextMenu(event, typeId, index) {
+      this.showMenu = true;
+      this.menuStyle = {
+        left: `${event.clientX}px`,
+        top: `${event.clientY}px`
+      };
+      this.selectedFileElement = event.target;
+      this.selectedTypeId = typeId;
+      this.selectedIndex = index;
+      this.selectedFile = this.typesMap.get(typeId)[index];
+    },
+    closeContextMenu() {
+      this.showMenu = false;
+    },
+    handleMenuItem(item) {
+      switch (item.action) {
+        case 'copy':
+          this.drawImageToCanvas();
+          break;
+        case 'move':
+          this.selectedFile.data.businesstypeid = item.value;
+          this.selectedFile.data.businesstype = item.label;
+          this.changeMediaFileType(this.selectedFile);
+          break;
+        default:
+          break;
       }
+      this.closeContextMenu();
     },
-    async getAllImgList() {
-      // for(var k of this.typeImgMap.keys()) {
-      //     this.typeImgMap.set(k, [])
-      // }
-      await mediafileApi.getRoutineByStGuid(this.subtask.stGuid).then((res) => {
-        this.isEmpty = false;
-        let data = res.data;
-        if (data.length == 0) {
-          this.isEmpty = true;
-        }
-        for (const e of data) {
-          let list;
-          let businesstypeid = e.businesstypeid;
-          let businesstype = e.businesstype;
-          let hasThisType = false;
-          this.typeImgMap.forEach((v, k, m) => {
-            if (k == businesstypeid) {
-              hasThisType = true;
-              var isAlreadyHas = false;
-              if (v != undefined && v != null) {
-                for (let index = 0; index < v.length; index++) {
-                  const element = v[index];
-                  if (element.guid == e.guid) {
-                    isAlreadyHas = true;
-                    break;
-                  }
-                }
-              }
-              if (!isAlreadyHas) {
-                v.push(e);
-              }
+    changeMediaFileType() {
+      this.selectedFile.loading = true;
+      const file = this.selectedFile.data;
+      return mediafileApi
+        .updateMediaFile(file)
+        .then((res) => {
+          if (res == 1) {
+            const m = this.typesMap
+              .get(this.selectedTypeId)
+              .splice(this.selectedIndex, 1);
+            if (!this.typesMap.has(file.businesstypeid)) {
+              this.typesList.push({
+                typeId: file.businesstypeid,
+                typeName: file.businesstype
+              });
+              this.typesMap.set(file.businesstypeid, m);
+            } else {
+              this.typesMap.get(file.businesstypeid).push(m[0]);
             }
-          });
-          if (!hasThisType) {
-            this.typeImgMap.set(businesstypeid, Array.of(e));
-            this.typeList.push(e);
           }
-          this.imgUrlList.push(e);
-          // TODO imgUrl鍏ㄥ眬閰嶇疆
-          e.url = $fysp.imgUrl + e.extension1 + e.guid + '.jpg';
-          // e.url = "http://47.100.191.150:9005/images/" + e.extension1 + e.guid + '.jpg'
-          e.isSelect = false;
-        }
-        this.initSelectedTab();
-      });
-    },
-    getInitImgList() {
-      mediafileApi.getRoutineByStGuid(this.subtask.stGuid).then((res) => {
-        let data = res.data;
-        for (const e of data) {
-          let list;
-          let businesstypeid = e.businesstypeid;
-          let businesstype = e.businesstype;
-          let hasThisType = false;
-          this.typeImgMap.forEach((v, k, m) => {
-            if (k == businesstypeid) {
-              hasThisType = true;
-              if (v.length < 3) {
-                v.push(e);
-              }
-            }
-          });
-          if (!hasThisType) {
-            this.typeImgMap.set(businesstypeid, Array.of(e));
-            this.typeList.push(e);
-          }
-          this.imgUrlList.push(e);
-          // TODO imgUrl鍏ㄥ眬閰嶇疆
-          e.url = $fysp.imgUrl + e.extension1 + e.guid + '.jpg';
-          // e.url = "http://47.100.191.150:9005/images/" + e.extension1 + e.guid + '.jpg'
-          e.isSelect = false;
-        }
-        if (this.typeList.length > 0) {
-          this.activeId = this.typeList[0].businesstypeid;
-        }
-      });
-    },
-    onSelect(img, i) {
-      // if (i == 2 && !this.isAll) {
-      //   this.getAllImgList();
-      //   this.isAll = true;
-      // } else {
-      //   if (this.readonly) {
-      //     return;
-      //   }
-      //   img.isSelect = !Boolean(img.isSelect);
-      // }
+        })
+        .finally(() => (this.selectedFile.loading = false));
 
-      if (this.readonly) {
-        return;
-      }
-      img.isSelect = !Boolean(img.isSelect);
+      // setTimeout(() => {
+      //   const m = this.typesMap
+      //     .get(this.selectedTypeId)
+      //     .splice(this.selectedIndex, 1);
+      //   if (!this.typesMap.has(file.businesstypeid)) {
+      //     this.typesList.push({
+      //       typeId: file.businesstypeid,
+      //       typeName: file.businesstype
+      //     });
+      //     this.typesMap.set(file.businesstypeid, m);
+      //   } else {
+      //     this.typesMap.get(file.businesstypeid).push(m[0]);
+      //   }
+      //   this.selectedFile.loading = false;
+      // }, 2000);
     },
-    sendSelectedImg(isOk) {
-      let result = [];
-      if (!Boolean(isOk)) {
-        this.$emit('selectByAnyPhonoEvent', result);
-      }
-      for (const item of this.imgUrlList) {
-        if (item.isSelect == true) {
-          result.push(item);
-        }
-      }
-      this.isClose = true;
-      this.$emit('selectByAnyPhonoEvent', result);
+    drawImageToCanvas() {
+      const canvas = document.createElement('canvas');
+      const ctx = canvas.getContext('2d');
+      const img = this.selectedFileElement; // 鑾峰彇DOM寮曠敤
+      // img.crossOrigin = 'Anonymous';
+      canvas.width = img.naturalWidth;
+      canvas.height = img.naturalHeight;
+      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
+      // this.copyCanvasToClipboard(canvas);
+      const dataUrl = canvas.toDataURL('image/png'); // 鍙互閫夋嫨鍏朵粬鏍煎紡濡�'image/jpeg'
+      // 鍒涘缓涓�涓复鏃剁殑textarea鍏冪礌鏉ュ鍒舵枃鏈�
+      const tempTextArea = document.createElement('textarea');
+      document.body.appendChild(tempTextArea);
+      tempTextArea.value = dataUrl;
+      tempTextArea.select();
+      document.execCommand('copy');
+      document.body.removeChild(tempTextArea);
+    },
+    copyCanvasToClipboard(canvas) {
+      canvas.toBlob((blob) => {
+        const item = new ClipboardItem({ 'image/png': blob }); // 浣犲彲浠ユ牴鎹渶瑕佹敼鍙樻牸寮忥紝濡� "image/jpeg"
+        navigator.clipboard.write([item]).then(
+          () => {
+            console.log('Image copied to clipboard');
+          },
+          (err) => {
+            console.error('Could not copy image: ', err);
+          }
+        );
+      }, 'image/png'); // 鍚屾牱锛岃繖閲屼篃鍙互鎸囧畾鍏朵粬鏍煎紡锛屽 'image/jpeg'
+    },
+    // 鍒濆鍖栧満鏅浘鐗囩殑绫诲瀷鑿滃崟
+    initMenuItems() {
+      this.menuLoading = true;
+      const sceneTypeId = this.subtask.sceneTypeId;
+      enumMediaFile(sceneTypeId, false)
+        .then((res) => {
+          this.allMoveActions = res.map((v) => {
+            return {
+              action: 'move',
+              label: v.label,
+              value: v.value
+            };
+          });
+        })
+        .finally(() => (this.menuLoading = false));
     }
   }
 };
 </script>
 <style scoped>
-.center {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
+.container {
+  /* background-color: rgba(19, 211, 67, 0.514); */
+  position: fixed;
+  left: 0;
+  top: 0;
+  height: 100vh;
+  width: 100vw;
+  z-index: 10000;
 }
-.text {
-  padding: 20px;
-}
-
-.main {
-  margin: 0 auto; /* 浣跨埗鍏冪礌灞呬腑 */
-  height: 100%;
-  width: 100%;
-}
-
-.btns {
-  /* height: 10%; */
-}
-/* 
-.img_types {
-  margin: 0 auto;
-  height: 440px;
-  width: 900px;
-  flex-grow: 1;
-  overflow-y: hidden ;
-  padding: 3%;
-  flex-wrap: wrap;
-  overflow: hidden;
-} */
-
-.imgs {
-  height: 650px;
-  width: 90%;
-  min-height: 100px !important;
-  /* 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 {
-  height: 210px;
-  width: 200px;
+.context-menu {
+  position: fixed;
+  background: white;
   border-radius: 4px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+  min-width: 200px;
+  z-index: 10001;
 }
 
-.active {
-  padding: 5px;
-  width: 20%;
-  height: 200px;
-  border: 0.5rem outset rgb(52, 155, 4);
+.menu-item {
+  padding: 8px 16px;
+  cursor: pointer;
+  transition: background 0.2s;
 }
 
-.selected {
-  padding: 5px;
-  color: #4abe84;
-  box-shadow: 0 2px 7px 0 rgba(85, 110, 97, 0.35);
-  border: 1px 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 {
-  height: 60vh;
-  padding: 10px calc(var(--el-dialog-padding-primary) + 10px) !important;
+.menu-item:hover {
+  background-color: #f0f0f0;
 }
 </style>

--
Gitblit v1.9.3