Răsfoiți Sursa

增加查看大图功能

asuka-4908 3 săptămâni în urmă
părinte
comite
e26c3e834b
1 a modificat fișierele cu 209 adăugiri și 4 ștergeri
  1. 209 4
      src/views/tips_report.vue

+ 209 - 4
src/views/tips_report.vue

@@ -162,11 +162,19 @@
                   :key="`${group.id}-${index}`"
                   class="checklist-row"
                 >
-                  <div class="checklist-item">
+                  <button
+                    type="button"
+                    :class="['checklist-item', { collapsed: isCaseCollapsed(group.id, index) }]"
+                    @click="toggleCase(group.id, index)"
+                  >
                     <span class="item-index">{{ index + 1 }}</span>
                     <span class="item-text">{{ item.text }}</span>
-                  </div>
-                  <div class="case-examples">
+                    <span class="item-caret">▼</span>
+                  </button>
+                  <div v-show="!isCaseCollapsed(group.id, index)" class="case-examples">
+                    <button class="case-view-btn" type="button" @click="openCaseViewer">
+                      查看大图
+                    </button>
                     <div class="case-card positive">
                       <div class="case-title">正确示例</div>
                       <img src="/case-positive.png" alt="正确示例" />
@@ -183,6 +191,25 @@
         </div>
       </div>
     </div>
+
+    <div v-if="showCaseViewer" class="case-viewer" @click.self="closeCaseViewer">
+      <div class="case-viewer-panel">
+        <div class="case-viewer-header">
+          <span>正反案例对比</span>
+          <button type="button" class="case-viewer-close" @click="closeCaseViewer">×</button>
+        </div>
+        <div class="case-viewer-body">
+          <div class="case-viewer-card positive">
+            <div class="case-viewer-title">正确示例</div>
+            <img src="/case-positive.png" alt="正确示例" />
+          </div>
+          <div class="case-viewer-card negative">
+            <div class="case-viewer-title">错误示例</div>
+            <img src="/case-negative.png" alt="错误示例" />
+          </div>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -390,9 +417,13 @@ const detectionGroups = computed(() => [
 ])
 
 const expandedGroupId = ref(null)
+const collapsedCaseKeys = ref([])
+const showCaseViewer = ref(false)
+
 const selectTask = (task) => {
   currentTaskId.value = task.id
   expandedGroupId.value = null
+  collapsedCaseKeys.value = []
 }
 
 const selectTag = (tag) => {
@@ -407,6 +438,30 @@ const toggleCheck = (index) => {
 
 const toggleGroup = (groupId) => {
   expandedGroupId.value = expandedGroupId.value === groupId ? null : groupId
+  collapsedCaseKeys.value = []
+}
+
+const getCaseKey = (groupId, itemIndex) => `${groupId}-${itemIndex}`
+
+const isCaseCollapsed = (groupId, itemIndex) => {
+  return collapsedCaseKeys.value.includes(getCaseKey(groupId, itemIndex))
+}
+
+const toggleCase = (groupId, itemIndex) => {
+  const key = getCaseKey(groupId, itemIndex)
+  if (collapsedCaseKeys.value.includes(key)) {
+    collapsedCaseKeys.value = collapsedCaseKeys.value.filter(item => item !== key)
+  } else {
+    collapsedCaseKeys.value = [...collapsedCaseKeys.value, key]
+  }
+}
+
+const openCaseViewer = () => {
+  showCaseViewer.value = true
+}
+
+const closeCaseViewer = () => {
+  showCaseViewer.value = false
 }
 </script>
 
@@ -936,14 +991,30 @@ const toggleGroup = (groupId) => {
 
     .checklist-item {
       display: grid;
-      grid-template-columns: 22px minmax(0, 1fr);
+      grid-template-columns: 22px minmax(0, 1fr) 14px;
       gap: 10px;
       align-items: flex-start;
       width: calc(100% - 28px);
       margin: 0 14px;
       padding: 9px 14px;
+      border: 0;
       border-radius: 7px;
       background: #fff;
+      text-align: left;
+      cursor: pointer;
+
+      &:focus,
+      &:focus-visible,
+      &:active {
+        outline: none;
+        box-shadow: none;
+      }
+
+      &.collapsed {
+        .item-caret {
+          transform: rotate(-90deg);
+        }
+      }
 
       .item-index {
         width: 22px;
@@ -965,9 +1036,17 @@ const toggleGroup = (groupId) => {
         color: #4b5568;
         line-height: 1.55;
       }
+
+      .item-caret {
+        color: #a6afbd;
+        font-size: 12px;
+        line-height: 22px;
+        transition: transform 0.2s ease;
+      }
     }
 
     .case-examples {
+      position: relative;
       display: grid;
       grid-template-columns: repeat(2, minmax(0, 1fr));
       gap: 12px;
@@ -978,6 +1057,27 @@ const toggleGroup = (groupId) => {
       border: 1px solid #e7ecf3;
     }
 
+    .case-view-btn {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      z-index: 1;
+      padding: 4px 10px;
+      border: 1px solid #3f7cff;
+      border-radius: 4px;
+      background: rgba(255, 255, 255, 0.92);
+      color: #3f7cff;
+      font-size: 12px;
+      cursor: pointer;
+
+      &:focus,
+      &:focus-visible,
+      &:active {
+        outline: none;
+        box-shadow: none;
+      }
+    }
+
     .case-card {
       min-width: 0;
 
@@ -1013,4 +1113,109 @@ const toggleGroup = (groupId) => {
     }
   }
 }
+
+.case-viewer {
+  position: fixed;
+  inset: 0;
+  z-index: 1000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 28px;
+  background: rgba(12, 20, 38, 0.72);
+}
+
+.case-viewer-panel {
+  width: min(1500px, 96vw);
+  height: min(860px, 92vh);
+  background: #fff;
+  border-radius: 10px;
+  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.28);
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+}
+
+.case-viewer-header {
+  height: 54px;
+  padding: 0 18px 0 22px;
+  border-bottom: 1px solid #edf0f5;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 18px;
+  font-weight: 700;
+  color: #1f2937;
+  flex-shrink: 0;
+}
+
+.case-viewer-close {
+  width: 34px;
+  height: 34px;
+  border: 0;
+  border-radius: 50%;
+  background: #f3f6fb;
+  color: #4b5568;
+  font-size: 24px;
+  line-height: 1;
+  cursor: pointer;
+
+  &:hover {
+    background: #e7ecf3;
+  }
+
+  &:focus,
+  &:focus-visible,
+  &:active {
+    outline: none;
+    box-shadow: none;
+  }
+}
+
+.case-viewer-body {
+  flex: 1;
+  min-height: 0;
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 18px;
+  padding: 18px;
+  background: #f6f8fb;
+}
+
+.case-viewer-card {
+  min-width: 0;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+
+  .case-viewer-title {
+    font-size: 16px;
+    font-weight: 700;
+  }
+
+  img {
+    flex: 1;
+    min-height: 0;
+    width: 100%;
+    height: 100%;
+    object-fit: contain;
+    border-radius: 8px;
+    border: 1px solid #e2e8f0;
+    background: #fff;
+  }
+
+  &.positive .case-viewer-title {
+    color: #16a34a;
+  }
+
+  &.negative .case-viewer-title {
+    color: #dc2626;
+  }
+}
+
+@media (max-width: 900px) {
+  .case-viewer-body {
+    grid-template-columns: 1fr;
+  }
+}
 </style>