Kaynağa Gözat

feat: 实现Download Attachment页面summary部分样式

Jack Zhou 2 ay önce
ebeveyn
işleme
739d625316

+ 1 - 0
src/components/VEllipsisTooltip/index.ts

@@ -0,0 +1 @@
+export { default } from './src/VEllipsisTooltip.vue'

+ 211 - 0
src/components/VEllipsisTooltip/src/VEllipsisTooltip.vue

@@ -0,0 +1,211 @@
+<template>
+  <el-tooltip
+    :disabled="!shouldShowTooltip"
+    :content="tooltipContent"
+    :popper-class="popperClass"
+    :placement="placement"
+    v-bind="tooltipProps"
+    ref="tooltipRef"
+  >
+    <div
+      ref="containerRef"
+      class="ellipsis-container"
+      :class="{ 'is-clamp-multi': lineClamp > 1 }"
+      :style="finalContainerStyle"
+      @mouseenter="handleMouseEnter"
+      @mouseleave="handleMouseLeave"
+    >
+      <slot>
+        <span ref="textRef" class="ellipsis-text" :style="textStyle">
+          {{ content }}
+        </span>
+      </slot>
+    </div>
+  </el-tooltip>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
+
+const props = defineProps({
+  content: String,
+  maxWidth: {
+    type: Number,
+    default: 200
+  },
+  maxHeight: {
+    type: [Number, String],
+    default: ''
+  },
+  lineClamp: {
+    type: Number,
+    default: 1
+  },
+  tooltipProps: {
+    type: Object,
+    default: () => ({})
+  },
+  popperClass: {
+    type: String,
+    default: 'ellipsis-tooltip'
+  },
+  placement: {
+    type: String,
+    default: 'top'
+  },
+  containerStyle: {
+    type: Object,
+    default: () => ({})
+  },
+  textStyle: {
+    type: Object,
+    default: () => ({})
+  }
+})
+
+// --- DOM refs ---
+const containerRef = ref(null)
+const textRef = ref(null)
+const tooltipRef = ref(null)
+
+// --- 是否应显示 tooltip ---
+const shouldShowTooltip = ref(false)
+
+// --- 动态计算样式类 ---
+const containerClasses = computed(() => ({
+  'is-clamp-multi': props.lineClamp > 1
+}))
+
+// --- 实际用于 Tooltip 显示的内容 ---
+const tooltipContent = computed(() => props.content || '')
+
+// --- 容器样式(max-width / max-height)---
+const finalContainerStyle = computed(() => ({
+  maxWidth: props.maxWidth + 'px',
+  maxHeight: props.maxHeight
+    ? typeof props.maxHeight === 'number'
+      ? props.maxHeight + 'px'
+      : props.maxHeight
+    : 'none',
+  ...props.containerStyle
+}))
+
+// --- 文本样式(根据 lineClamp 应用不同 CSS)---
+const finalTextStyle = computed(() => {
+  const style = { ...props.textStyle }
+  if (props.lineClamp <= 1) {
+    return {
+      display: 'block',
+      overflow: 'hidden',
+      textOverflow: 'ellipsis',
+      whiteSpace: 'nowrap',
+      ...style
+    }
+  } else {
+    return {
+      display: '-webkit-box',
+      WebkitBoxOrient: 'vertical',
+      WebkitLineClamp: props.lineClamp,
+      overflow: 'hidden',
+      textOverflow: 'ellipsis',
+      wordBreak: 'break-all', // 多行建议启用
+      ...style
+    }
+  }
+})
+
+// --- 检查是否溢出 ---
+const checkOverflow = async () => {
+  await nextTick() // 确保 DOM 更新
+  const container = containerRef.value
+  const textEl = textRef.value || container?.querySelector('.ellipsis-text')
+
+  if (!container || !textEl) return
+
+  let isOverflowing = false
+
+  if (props.lineClamp <= 1) {
+    isOverflowing = textEl.scrollWidth > container.clientWidth
+  } else {
+    // 多行看高度是否溢出(line-clamp 截断)
+    isOverflowing = textEl.scrollHeight > container.clientHeight
+  }
+
+  shouldShowTooltip.value = isOverflowing
+}
+
+// --- 鼠标事件用于手动触发检查(防抖)---
+let resizeTimer
+const handleMouseEnter = () => {
+  clearTimeout(resizeTimer)
+  resizeTimer = setTimeout(checkOverflow, 50)
+}
+
+// 可选:也可监听 resize
+onMounted(() => {
+  window.addEventListener('resize', checkOverflow)
+  checkOverflow()
+})
+
+onUnmounted(() => {
+  window.removeEventListener('resize', checkOverflow)
+  clearTimeout(resizeTimer)
+})
+
+// 监听 props 变化
+watch(
+  () => [props.content, props.lineClamp, props.maxWidth, props.maxHeight],
+  () => {
+    checkOverflow()
+  },
+  { immediate: true }
+)
+</script>
+
+<style lang="scss" scoped>
+.ellipsis-container {
+  display: inline-block;
+  max-width: v-bind('finalContainerStyle.maxWidth');
+  max-height: v-bind('finalContainerStyle.maxHeight');
+  overflow: hidden;
+  vertical-align: top;
+  line-height: 32px;
+}
+
+.ellipsis-text {
+  width: 100%; // 利用父容器宽度
+}
+.ellipsis-container {
+  display: inline-block;
+  max-width: v-bind('finalContainerStyle.maxWidth');
+  max-height: v-bind('finalContainerStyle.maxHeight');
+  overflow: hidden;
+  line-height: 1.5;
+}
+
+.ellipsis-text {
+  width: 100%;
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.ellipsis-container.is-clamp-multi .ellipsis-text {
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: v-bind('lineClamp');
+  white-space: normal;
+  word-break: break-all;
+}
+</style>
+
+<!-- 全局样式建议提取到全局 SCSS 文件 -->
+<style>
+.ellipsis-tooltip {
+  max-width: 200px;
+  word-break: break-word;
+  white-space: pre-line;
+  margin-bottom: -15px;
+}
+</style>

+ 40 - 35
src/views/Tracking/src/components/DownloadAttachment/src/DownloadAttachment.vue

@@ -60,7 +60,7 @@ const summaryList = [
     number: 8,
     attachmentList: [
       {
-        name: 'Commercial Invoice.pdf'
+        name: 'Commercial InvoiceCommercial InvoiceCommercial InvoiceCommercial Invoice.pdf'
       },
       {
         name: 'Packing List.pdf'
@@ -114,42 +114,48 @@ const activeNames = ref(['1'])
     <div class="right-summary-section">
       <div class="title">Attachment Summary</div>
       <div class="summary-content">
-        <el-button class="el-button--main el-button--pain-theme" style="width: 100%">
+        <el-button
+          class="el-button--main el-button--pain-theme"
+          style="width: 100%; margin-bottom: 8px"
+        >
           <span class="font_family icon-icon_download_b"></span> <span>Download Selected (12)</span>
         </el-button>
-        <div class="type-collapse">
-          <el-collapse
-            style="margin: 5px 0"
-            expand-icon-position="left"
-            v-for="(typeItem, index) in summaryList"
-            :key="index"
-          >
-            <div class="right-download">
-              <div class="count">
-                <span>12</span>
-              </div>
-              <span class="font_family icon-icon_download_b"></span>
+        <el-collapse
+          style="margin: 8px 0"
+          expand-icon-position="left"
+          v-for="(typeItem, index) in summaryList"
+          :key="index"
+        >
+          <div class="right-download">
+            <div class="count">
+              <span>12</span>
             </div>
-            <el-collapse-item :title="typeItem.label" :name="index.toString()">
-              <template #icon="{ isActive }">
-                <span
-                  :class="{ 'is-active': isActive }"
-                  class="font_family icon-icon_up_b custom-arrow"
-                ></span>
-              </template>
+            <span class="font_family icon-icon_download_b"></span>
+          </div>
+          <el-collapse-item :title="typeItem.label" :name="index.toString()">
+            <template #icon="{ isActive }">
+              <span
+                :class="{ 'is-active': isActive }"
+                class="font_family icon-icon_up_b custom-arrow"
+              ></span>
+            </template>
 
-              <div class="attachment-list">
-                <div
-                  class="attachment-item"
-                  v-for="attItem in typeItem.attachmentList"
-                  :key="attItem.name"
-                >
-                  <span>{{ attItem.name }}</span>
-                </div>
+            <div class="attachment-list">
+              <div
+                class="attachment-item"
+                v-for="attItem in typeItem.attachmentList"
+                :key="attItem.name"
+              >
+                <v-ellipsis-tooltip
+                  :max-width="246"
+                  :max-height="32"
+                  :line-clamp="1"
+                  :content="attItem.name"
+                ></v-ellipsis-tooltip>
               </div>
-            </el-collapse-item>
-          </el-collapse>
-        </div>
+            </div>
+          </el-collapse-item>
+        </el-collapse>
       </div>
     </div>
   </div>
@@ -325,13 +331,12 @@ const activeNames = ref(['1'])
     }
   }
   .attachment-list {
-    margin: 8px 0;
+    margin-bottom: 8px;
     border-radius: 8px;
     overflow: hidden;
     .attachment-item {
       height: 32px;
-      line-height: 32px;
-      padding: 0 8px;
+      padding: 7px 8px 0;
       border-bottom: 1px solid var(--color-border);
       background-color: var(--color-personal-preference-bg);
       &:last-child {