Sfoglia il codice sorgente

refactor(searchTerm): 优化报表页面布局和高度适配

- 使用 useCustomHeight 钩子实现自定义表格高度计算
- 调整卡片和表格的样式布局
WanGxC 6 mesi fa
parent
commit
97210716a1

+ 38 - 0
src/utils/useCustomHeight.ts

@@ -0,0 +1,38 @@
+export function useCustomHeight(heightObj: Record<string, number | Ref<HTMLElement | null>>) {
+  const tableHeight = ref<number>(0);
+
+  const calculateHeight = () => {
+    let totalHeight = 0;
+    const entries = Object.entries(heightObj);
+
+    entries.forEach(([key, height], index) => {
+      // console.log(`Processing ${key} at index ${index}:`);
+
+      // 判断 height 是否为 ref,如果是则解引用,否则直接使用数值
+      const resolvedHeight = isRef(height) ? unref(height) : height;
+
+      let currentHeight = 0;
+      if (typeof resolvedHeight === 'number') {
+        currentHeight = resolvedHeight;
+      } else if (resolvedHeight instanceof HTMLElement) {
+        currentHeight = resolvedHeight.offsetHeight;
+      }
+
+      totalHeight += currentHeight;
+      // console.log(`Key: ${key}, Current height: ${currentHeight}, Total so far: ${totalHeight}`);
+    });
+
+    tableHeight.value = window.innerHeight - totalHeight;
+  };
+
+  onMounted(() => {
+    calculateHeight();
+    window.addEventListener('resize', calculateHeight);
+  });
+
+  onBeforeUnmount(() => {
+    window.removeEventListener('resize', calculateHeight);
+  });
+
+  return { tableHeight };
+}

+ 73 - 65
src/views/searchTerm/asinView/index.vue

@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" setup>
 /**
  * @Name: index.vue
  * @Description: asinView
@@ -13,48 +13,54 @@ import { ElMessage } from 'element-plus';
 import { asinColumns } from './useColumns';
 import WeekRangePicker from '/@/components/WeekRangePicker/index.vue';
 import MonthRangePicker from '/@/components/MonthRangePicker/index.vue';
+import { useCustomHeight } from '/@/utils/useCustomHeight';
+
+
+const topCard = ref();
+const heightObj = { topBar: 50, topCard: topCard, cardMargin: 32 };
+const { tableHeight } = useCustomHeight(heightObj);
 
 const weekDate = ref([
   dayjs().subtract(2, 'week').day(0).format('YYYY-MM-DD'),
-  dayjs().subtract(1, 'week').day(6).format('YYYY-MM-DD'),
+  dayjs().subtract(1, 'week').day(6).format('YYYY-MM-DD')
 ]);
 const monthDate = ref([
   dayjs().subtract(2, 'month').startOf('month').format('YYYY-MM-DD'),
-  dayjs().subtract(0, 'month').startOf('month').format('YYYY-MM-DD'),
+  dayjs().subtract(0, 'month').startOf('month').format('YYYY-MM-DD')
 ]);
 const reportTypeSelect = ref('weekly');
 const searchTermInp = ref('');
 const asinInp = ref('B0');
 const tableLoading = ref(false);
 
+const tablePage = reactive({
+  total: 0,
+  currentPage: 1,
+  pageSize: 20
+});
+
 const gridOptions: any = reactive({
-  height: '100%',
+  height: 'auto',
   border: false,
   round: true,
   columnConfig: {
-    resizable: true,
+    resizable: true
   },
   toolbarConfig: {
     custom: true,
     slots: {
-      buttons: 'toolbar_buttons',
-    },
+      buttons: 'toolbar_buttons'
+    }
   },
   columns: asinColumns,
-  data: [],
-});
-
-const tablePage = reactive({
-  total: 0,
-  currentPage: 1,
-  pageSize: 20,
+  data: []
 });
 
 onBeforeMount(() => {
   fetchTableData();
 });
 
-watch([weekDate, monthDate], () => {
+watch([ weekDate, monthDate ], () => {
   fetchTableData();
 });
 
@@ -92,7 +98,7 @@ async function fetchTableData() {
     search_term: searchTermInp.value,
     report_type: reportTypeSelect.value,
     date_start: reportTypeSelect.value == 'weekly' ? weekDate.value[0] : monthDate.value[0],
-    date_end: reportTypeSelect.value == 'weekly' ? weekDate.value[1] : monthDate.value[1],
+    date_end: reportTypeSelect.value == 'weekly' ? weekDate.value[1] : monthDate.value[1]
   };
   try {
     const response = await getTableData(query);
@@ -144,57 +150,59 @@ function validateAsinInput(input: string) {
 </script>
 
 <template>
-  <div class="py-2 px-2.5 flex" style="background-color: #f7f7f7">
-    <el-card shadow="hover" class="mb-2.5" style="border: none; margin-bottom: 10px">
-      <div ref="queryContainer" class="flex justify-between">
-        <div class="flex gap-5 flex-wrap">
-          <div>
-            <span class="font-medium mr-0.5">报告类型 </span>
-            <el-select v-model="reportTypeSelect" @change="handleSelectChange" style="width: 90px">
-              <el-option label="周度" value="weekly" />
-              <el-option label="月度" value="monthly" />
-            </el-select>
-          </div>
-          <div>
-            <span class="font-medium mr-0.5">搜索词 </span>
-            <el-input
-              v-model="searchTermInp"
-              @keyup.enter="handleQueryChange"
-              :prefix-icon="Search"
-              placeholder="输入后回车查询"
-              clearable
-              @clear="handleSelectChange"
-              style="width: 240px" />
-          </div>
-          <div>
-            <span class="font-medium mr-0.5">ASIN </span>
-            <el-input
-              v-model="asinInp"
-              @keyup.enter="handleQueryChange"
-              :prefix-icon="Search"
-              placeholder="输入后回车查询"
-              clearable
-              @clear="handleSelectChange"
-              style="width: 180px" />
+  <div class="py-2 px-2.5" style="background-color: #f7f7f7">
+    <div ref="topCard">
+      <el-card class="mb-2.5" shadow="hover" style="border: none; margin-bottom: 10px">
+        <div ref="queryContainer" class="flex justify-between">
+          <div class="flex gap-5 flex-wrap">
+            <div>
+              <span class="font-medium mr-0.5">报告类型 </span>
+              <el-select v-model="reportTypeSelect" style="width: 90px" @change="handleSelectChange">
+                <el-option label="周度" value="weekly"/>
+                <el-option label="月度" value="monthly"/>
+              </el-select>
+            </div>
+            <div>
+              <span class="font-medium mr-0.5">搜索词 </span>
+              <el-input
+                  v-model="searchTermInp"
+                  :prefix-icon="Search"
+                  clearable
+                  placeholder="输入后回车查询"
+                  style="width: 240px"
+                  @clear="handleSelectChange"
+                  @keyup.enter="handleQueryChange"/>
+            </div>
+            <div>
+              <span class="font-medium mr-0.5">ASIN </span>
+              <el-input
+                  v-model="asinInp"
+                  :prefix-icon="Search"
+                  clearable
+                  placeholder="输入后回车查询"
+                  style="width: 180px"
+                  @clear="handleSelectChange"
+                  @keyup.enter="handleQueryChange"/>
+            </div>
+            <div>
+              <span class="font-medium mr-0.5">报告日期 </span>
+              <MonthRangePicker v-if="reportTypeSelect === 'monthly'" v-model="monthDate"/>
+              <WeekRangePicker v-else v-model="weekDate"/>
+            </div>
           </div>
-          <div>
-            <span class="font-medium mr-0.5">报告日期 </span>
-            <MonthRangePicker v-model="monthDate" v-if="reportTypeSelect === 'monthly'" />
-            <WeekRangePicker v-model="weekDate" v-else />
+          <div class="flex">
+            <el-button :icon="Refresh" circle @click="refreshTable"></el-button>
           </div>
         </div>
-        <div class="flex">
-          <el-button @click="refreshTable" :icon="Refresh" circle></el-button>
-        </div>
-      </div>
-    </el-card>
-    <el-card shadow="hover" style="border: none; flex: 1 1 auto; height: calc(100vh - 154px)">
-      <div style="overflow: hidden; width: 100%; height: calc(100vh - 174px)" v-loading="tableLoading">
+      </el-card>
+    </div>
+    <el-card :body-style="{ height: tableHeight + 'px' }" shadow="hover" style="border: none;">
+      <div v-loading="tableLoading" class=" w-full h-full">
         <vxe-grid v-bind="gridOptions">
           <template #toolbar_buttons></template>
           <template v-for="col in asinColumns" #[`${col.field}_default`]="{ row }">
             <div v-if="col.field === 'clickedItemName'">
-              <el-tooltip effect="dark" :content="row.clickedItemName" placement="top" :show-after="300">
+              <el-tooltip :content="row.clickedItemName" :show-after="300" effect="dark" placement="top">
                 <div class="line-text font-medium">
                   {{ row.clickedItemName }}
                 </div>
@@ -206,11 +214,11 @@ function validateAsinInput(input: string) {
           </template>
           <template #pager>
             <vxe-pager
-              :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
-              v-model:current-page="tablePage.currentPage"
-              v-model:page-size="tablePage.pageSize"
-              :total="tablePage.total"
-              @page-change="handlePageChange">
+                v-model:current-page="tablePage.currentPage"
+                v-model:page-size="tablePage.pageSize"
+                :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
+                :total="tablePage.total"
+                @page-change="handlePageChange">
             </vxe-pager>
           </template>
         </vxe-grid>

+ 56 - 48
src/views/searchTerm/brandView/index.vue

@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" setup>
 /**
  * @Name: index.vue
  * @Description: brandView
@@ -13,14 +13,20 @@ import { ElMessage } from 'element-plus';
 import { brandColumns } from './useColumns';
 import WeekRangePicker from '/@/components/WeekRangePicker/index.vue';
 import MonthRangePicker from '/@/components/MonthRangePicker/index.vue';
+import { useCustomHeight } from '/@/utils/useCustomHeight';
+
+
+const topCard = ref();
+const heightObj = { topBar: 50, topCard: topCard, cardMargin: 32 };
+const { tableHeight } = useCustomHeight(heightObj);
 
 const weekDate = ref([
   dayjs().subtract(2, 'week').day(0).format('YYYY-MM-DD'),
-  dayjs().subtract(1, 'week').day(6).format('YYYY-MM-DD'),
+  dayjs().subtract(1, 'week').day(6).format('YYYY-MM-DD')
 ]);
 const monthDate = ref([
   dayjs().subtract(2, 'month').startOf('month').format('YYYY-MM-DD'),
-  dayjs().subtract(0, 'month').startOf('month').format('YYYY-MM-DD'),
+  dayjs().subtract(0, 'month').startOf('month').format('YYYY-MM-DD')
 ]);
 const reportTypeSelect = ref('weekly');
 const searchTermInp = ref('zosi');
@@ -31,29 +37,29 @@ const gridOptions: any = reactive({
   border: false,
   round: true,
   columnConfig: {
-    resizable: true,
+    resizable: true
   },
   toolbarConfig: {
     custom: true,
     slots: {
-      buttons: 'toolbar_buttons',
-    },
+      buttons: 'toolbar_buttons'
+    }
   },
   columns: brandColumns,
-  data: [],
+  data: []
 });
 
 const tablePage = reactive({
   total: 0,
   currentPage: 1,
-  pageSize: 20,
+  pageSize: 20
 });
 
 onBeforeMount(() => {
   fetchTableData();
 });
 
-watch([weekDate, monthDate], () => {
+watch([ weekDate, monthDate ], () => {
   fetchTableData();
 });
 
@@ -83,7 +89,7 @@ async function fetchTableData() {
     search_term: searchTermInp.value,
     report_type: reportTypeSelect.value,
     date_start: reportTypeSelect.value == 'weekly' ? weekDate.value[0] : monthDate.value[0],
-    date_end: reportTypeSelect.value == 'weekly' ? weekDate.value[1] : monthDate.value[1],
+    date_end: reportTypeSelect.value == 'weekly' ? weekDate.value[1] : monthDate.value[1]
   };
   try {
     const response = await getTableData(query);
@@ -140,51 +146,53 @@ function calculateLastWeek() {
   const today = dayjs();
   const lastDay = today.subtract(1, 'day'); // 昨天
   const firstDay = lastDay.subtract(6, 'day'); // 一周前
-  return [firstDay.format('YYYY-MM-DD'), lastDay.format('YYYY-MM-DD')];
+  return [ firstDay.format('YYYY-MM-DD'), lastDay.format('YYYY-MM-DD') ];
 }
 </script>
 
 <template>
   <div class="py-2 px-2.5" style="background-color: #f7f7f7">
-    <el-card shadow="hover" class="mb-2.5" style="border: none; margin-bottom: 10px">
-      <div class="flex justify-between">
-        <div class="flex gap-5 flex-wrap">
-          <div>
-            <span class="font-medium mr-0.5">报告类型 </span>
-            <el-select v-model="reportTypeSelect" @change="handleSelectChange" style="width: 90px">
-              <el-option label="周度" value="weekly" />
-              <el-option label="月度" value="monthly" />
-            </el-select>
-          </div>
-          <div>
-            <span class="font-medium mr-0.5">搜索词 </span>
-            <el-input
-              v-model="searchTermInp"
-              @keyup.enter="handleQueryChange"
-              :prefix-icon="Search"
-              placeholder="输入后回车查询"
-              clearable
-              @clear="handleSelectChange"
-              style="width: 240px" />
+    <div ref="topCard">
+      <el-card class="mb-2.5" shadow="hover" style="border: none; margin-bottom: 10px">
+        <div class="flex justify-between">
+          <div class="flex gap-5 flex-wrap">
+            <div>
+              <span class="font-medium mr-0.5">报告类型 </span>
+              <el-select v-model="reportTypeSelect" style="width: 90px" @change="handleSelectChange">
+                <el-option label="周度" value="weekly"/>
+                <el-option label="月度" value="monthly"/>
+              </el-select>
+            </div>
+            <div>
+              <span class="font-medium mr-0.5">搜索词 </span>
+              <el-input
+                  v-model="searchTermInp"
+                  :prefix-icon="Search"
+                  clearable
+                  placeholder="输入后回车查询"
+                  style="width: 240px"
+                  @clear="handleSelectChange"
+                  @keyup.enter="handleQueryChange"/>
+            </div>
+            <div>
+              <span class="font-medium mr-0.5">报告日期 </span>
+              <MonthRangePicker v-if="reportTypeSelect === 'monthly'" v-model="monthDate"/>
+              <WeekRangePicker v-else v-model="weekDate"/>
+            </div>
           </div>
-          <div>
-            <span class="font-medium mr-0.5">报告日期 </span>
-            <MonthRangePicker v-model="monthDate" v-if="reportTypeSelect === 'monthly'" />
-            <WeekRangePicker v-model="weekDate" v-else />
+          <div class="flex">
+            <el-button :icon="Refresh" circle @click="refreshTable"></el-button>
           </div>
         </div>
-        <div class="flex">
-          <el-button @click="refreshTable" :icon="Refresh" circle></el-button>
-        </div>
-      </div>
-    </el-card>
-    <el-card shadow="hover" style="border: none; flex: 1 1 auto; height: calc(100vh - 154px)">
-      <div style="overflow: hidden; width: 100%; height: calc(100vh - 174px)" v-loading="tableLoading">
+      </el-card>
+    </div>
+    <el-card :body-style="{ height: tableHeight + 'px' }" shadow="hover" style="border: none;">
+      <div v-loading="tableLoading" class="w-full h-full">
         <vxe-grid v-bind="gridOptions">
           <template #toolbar_buttons></template>
           <template v-for="col in brandColumns" #[`${col.field}_default`]="{ row }">
             <div v-if="col.field === 'clickedItemName'">
-              <el-tooltip effect="dark" :content="row.clickedItemName" placement="top" :show-after="300">
+              <el-tooltip :content="row.clickedItemName" :show-after="300" effect="dark" placement="top">
                 <div class="line-text">
                   {{ row.clickedItemName }}
                 </div>
@@ -196,11 +204,11 @@ function calculateLastWeek() {
           </template>
           <template #pager>
             <vxe-pager
-              :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
-              v-model:current-page="tablePage.currentPage"
-              v-model:page-size="tablePage.pageSize"
-              :total="tablePage.total"
-              @page-change="handlePageChange">
+                v-model:current-page="tablePage.currentPage"
+                v-model:page-size="tablePage.pageSize"
+                :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
+                :total="tablePage.total"
+                @page-change="handlePageChange">
             </vxe-pager>
           </template>
         </vxe-grid>