Browse Source

报表表格放大浏览功能

刘洋 1 year ago
parent
commit
a365a77a09

+ 209 - 0
src/components/common/table-loop/big-table-loop-dialog.vue

@@ -0,0 +1,209 @@
+<template>
+  <my-dialog
+    :visible="visible"
+    header=""
+    :width="(width || 0) + 68"
+    attach="body"
+    :closeOnOverlayClick="false"
+    :footer="false"
+    @close="onClose"
+  >
+    <div class="table-loop" ref="tableLoop">
+      <div class="thead" ref="thead" :style="{ width: width + 'px' }">
+        <div class="td index">排名</div>
+        <div
+          class="td"
+          v-for="(item, index) in columns"
+          :key="index"
+          :style="createStyle(item.style)"
+        >
+          {{ item.label }}
+        </div>
+      </div>
+      <swiper
+        v-if="hasData"
+        :key="swiperKey"
+        :style="{ height: 36 * rowNum + 'px', width: width + 'px' }"
+        :modules="modules"
+        direction="vertical"
+        :slides-per-view="rowNum"
+        :space-between="0"
+        :mousewheel="true"
+        :autoplay="{ delay: 1500 }"
+      >
+        <swiper-slide
+          class="slide"
+          v-for="(item, index) in data || []"
+          :key="index"
+          @click="rowClick(item)"
+        >
+          <div class="td index">
+            <div class="cell" v-if="index == 0"
+              ><img class="index" src="../../../assets/imgs/No1.png"
+            /></div>
+            <div class="cell" v-else-if="index == 1"
+              ><img class="index" src="../../../assets/imgs/No2.png"
+            /></div>
+            <div class="cell" v-else-if="index == 2"
+              ><img class="index" src="../../../assets/imgs/No3.png"
+            /></div>
+            <div class="cell" v-else>{{ index + 1 }}</div>
+          </div>
+          <div
+            class="td"
+            v-for="(v, i) in columns"
+            :key="i"
+            :style="createStyle(v.style)"
+          >
+            <div class="cell">
+              <t-tooltip
+                v-if="v.prop !== 'rate'"
+                placement="top"
+                :content="item[v.prop] + ''"
+              >
+                <span>{{ item[v.prop] }}</span>
+              </t-tooltip>
+              <div class="process-box" v-else>
+                <div class="process" :style="{ width: item.rate }"></div>
+              </div>
+            </div>
+          </div>
+        </swiper-slide>
+      </swiper>
+      <div v-else class="none-data">暂无数据</div>
+    </div>
+  </my-dialog>
+</template>
+
+<script setup name="BigTableLoopDialog">
+import { ref, onMounted, computed, watch } from 'vue';
+import { Navigation, Mousewheel, Autoplay } from 'swiper';
+import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
+import 'swiper/css';
+import 'swiper/css/autoplay';
+const visible = ref(false);
+const emits = defineEmits(['rowClick', 'close']);
+const props = defineProps({
+  data: Object,
+  columns: Array,
+  width: Number,
+});
+const modules = ref([Navigation, Mousewheel, Autoplay]);
+const swiperKey = ref(Date.now() + '');
+const tableLoop = ref();
+const tbodyHeight = ref(1);
+const rowNum = computed(() => {
+  return parseInt(tbodyHeight.value / 36);
+});
+const swiperWidth = ref(0);
+const thead = ref();
+const onClose = () => {
+  emits('close');
+};
+onMounted(() => {
+  visible.value = true;
+  setTimeout(() => {
+    let w = 0;
+    for (let i = 0; i < thead.value.children.length; i++) {
+      let node = thead.value.children[i];
+      w += node.offsetWidth;
+    }
+    swiperWidth.value = w;
+  }, 0);
+});
+const hasData = computed(() => {
+  return !!props.data?.length;
+});
+watch(hasData, () => {
+  swiperKey.value = Date.now() + '';
+});
+onMounted(() => {
+  setTimeout(() => {
+    tbodyHeight.value = tableLoop.value.offsetHeight - 46;
+    setTimeout(() => {
+      swiperKey.value = Date.now() + '';
+    });
+  }, 0);
+});
+
+const rowClick = (item) => {
+  console.log('item:', item);
+  emits('rowClick', item);
+};
+const createStyle = (styleObj) => {
+  let w = parseFloat(styleObj.width) * 2;
+  return { ...styleObj, width: w + 'px' };
+};
+</script>
+
+<style lang="less" scoped>
+.table-loop {
+  height: 400px;
+  overflow: auto;
+  .none-data {
+    height: calc(100% - 36px);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    color: #ccc;
+    font-size: 14px;
+  }
+  .thead {
+    height: 36px;
+    font-size: 12px;
+    .td {
+      text-align: center;
+      line-height: 36px;
+      color: #8c8c8c !important;
+      background-color: #f7f7f7;
+    }
+  }
+  .slide {
+    cursor: pointer;
+    &:hover {
+      background-color: #f7f7f7;
+    }
+    .td {
+      color: #262626;
+      .cell {
+        height: 100%;
+        width: 100%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        img.index {
+          height: 14px;
+        }
+        > span {
+          overflow: hidden;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+        }
+      }
+    }
+  }
+  .thead,
+  .slide {
+    white-space: nowrap;
+  }
+  .td {
+    display: inline-block;
+
+    height: 100%;
+    &.index {
+      width: 34px;
+    }
+    .process-box {
+      background-color: #d9d9d9;
+      height: 6px;
+      border-radius: 3px;
+      width: 90%;
+      overflow: hidden;
+      .process {
+        background-color: #4080ff;
+        height: 100%;
+      }
+    }
+  }
+}
+</style>

+ 24 - 0
src/components/common/table-loop/index.vue

@@ -62,6 +62,14 @@
       </swiper-slide>
     </swiper>
     <div v-else class="none-data">暂无数据</div>
+
+    <BigTableLoopDialog
+      v-if="visible"
+      :data="data"
+      :columns="columns"
+      @close="visible = false"
+      :width="bigTableWidth"
+    ></BigTableLoopDialog>
   </div>
 </template>
 
@@ -69,8 +77,10 @@
 import { ref, onMounted, computed, watch } from 'vue';
 import { Navigation, Mousewheel, Autoplay } from 'swiper';
 import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
+import BigTableLoopDialog from './big-table-loop-dialog.vue';
 import 'swiper/css';
 import 'swiper/css/autoplay';
+const visible = ref(false);
 const emits = defineEmits(['rowClick']);
 const props = defineProps({ data: Object, columns: Array });
 const modules = ref([Navigation, Mousewheel, Autoplay]);
@@ -82,6 +92,12 @@ const rowNum = computed(() => {
 });
 const swiperWidth = ref(0);
 const thead = ref();
+const bigTableWidth = computed(() => {
+  return (props.columns || []).reduce((total, col) => {
+    let tdWidth = parseFloat(col.style.width);
+    return total + tdWidth * 2;
+  }, 34);
+});
 onMounted(() => {
   let w = 0;
   for (let i = 0; i < thead.value.children.length; i++) {
@@ -107,6 +123,12 @@ const rowClick = (item) => {
   console.log('item:', item);
   emits('rowClick', item);
 };
+const maximize = () => {
+  visible.value = true;
+};
+defineExpose({
+  maximize,
+});
 </script>
 
 <style lang="less" scoped>
@@ -124,6 +146,8 @@ const rowClick = (item) => {
   .thead {
     height: 36px;
     font-size: 12px;
+    margin-left: auto;
+    margin-right: auto;
     .td {
       text-align: center;
       line-height: 36px;

+ 2 - 2
src/views/report/dispatch-analysis/index.vue

@@ -351,12 +351,12 @@ const tableColumns = [
   {
     prop: 'name',
     label: '城市',
-    style: { width: 'calc((100% - 90px) / 2)' },
+    style: { width: '80px' },
   },
   {
     prop: 'count',
     label: '总数',
-    style: { width: 'calc((100% - 90px) / 4)' },
+    style: { width: '37px' },
   },
   {
     prop: 'rate',

+ 45 - 2
src/views/report/sop-analysis/index.vue

@@ -36,9 +36,15 @@
                   label="项目预警处理最快TOP10"
                 ></t-option>
               </t-select>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart1?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
               <table-loop
+                ref="chart1"
                 :data="tableDataHandle(result1)"
                 :columns="tableColumns1"
               ></table-loop>
@@ -64,9 +70,15 @@
                   label="大区预警处理最快TOP10"
                 ></t-option>
               </t-select>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart2?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
               <table-loop
+                ref="chart2"
                 :data="tableDataHandle(result2)"
                 :columns="tableColumns2"
               ></table-loop>
@@ -92,9 +104,15 @@
                   label="供应商预警处理最快TOP10"
                 ></t-option>
               </t-select>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart3?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
               <table-loop
+                ref="chart3"
                 :data="tableDataHandle(result3)"
                 :columns="tableColumns3"
               ></table-loop>
@@ -214,9 +232,15 @@
           <div class="card">
             <div class="title">
               <span class="label">项目考勤异常TOP10</span>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart4?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
               <table-loop
+                ref="chart4"
                 :data="tableDataHandle(result4)"
                 :columns="tableColumns4"
               ></table-loop>
@@ -225,9 +249,15 @@
           <div class="card">
             <div class="title">
               <span class="label">项目考勤异常TOP10</span>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart5?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
               <table-loop
+                ref="chart5"
                 :data="tableDataHandle(result5)"
                 :columns="tableColumns5"
               ></table-loop>
@@ -236,9 +266,15 @@
           <div class="card">
             <div class="title">
               <span class="label">供应商考勤异常TOP5</span>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart6?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
               <table-loop
+                ref="chart6"
                 :data="tableDataHandle(result6)"
                 :columns="tableColumns6"
               ></table-loop>
@@ -263,6 +299,13 @@ import {
   sopWarningAnalysis,
 } from '@/api/report';
 import { createLineOption } from '@/utils/chart';
+import { FullscreenIcon } from 'tdesign-icons-vue-next';
+const chart1 = ref();
+const chart2 = ref();
+const chart3 = ref();
+const chart4 = ref();
+const chart5 = ref();
+const chart6 = ref();
 const curTimeRange = ref([]);
 const serviceOptions = ref([]);
 
@@ -425,7 +468,7 @@ const tableColumns5 = [
     label: '异常数',
     style: { width: '70px' },
   },
-  { prop: 'd', label: '均值', style: { width: '60px' } },
+  { prop: 'avg', label: '均值', style: { width: '60px' } },
 ];
 
 const tableColumns6 = [
@@ -435,7 +478,7 @@ const tableColumns6 = [
     style: { width: '80px' },
   },
   { prop: 'total', label: '异常数', style: { width: '70px' } },
-  { prop: 'e', label: '均值', style: { width: '60px' } },
+  { prop: 'avg', label: '均值', style: { width: '60px' } },
 ];
 watch(serviceId, (serviceId) => {
   sort1.value = sort2.value = sort3.value = 'PENDING';