Răsfoiți Sursa

修改专题页资产列表布局

gongtianxiao 1 lună în urmă
părinte
comite
7d2056f8fa

+ 98 - 32
src/components/stats/ComplianceAssetTable.vue

@@ -1,42 +1,55 @@
 <template>
 <template>
   <div class="compliance-table" :class="{ 'compliance-table--fluid': fluid }">
   <div class="compliance-table" :class="{ 'compliance-table--fluid': fluid }">
-    <div class="compliance-table__header">
-      <div
-        v-for="column in columns"
-        :key="column.key"
-        class="compliance-table__cell compliance-table__cell--header"
-        :style="cellStyle(column)"
-      >
-        {{ column.label }}
+    <div :class="{ 'compliance-table__sticky-chrome': stickyChrome }">
+      <div v-if="stickyChrome" class="compliance-table__chrome-content">
+        <slot name="chrome" />
       </div>
       </div>
-    </div>
-    <div class="compliance-table__body">
-      <template v-if="paginatedRows.length">
-        <div
-          v-for="(row, rowIndex) in paginatedRows"
-          :key="row.id ?? rowIndex"
-          class="compliance-table__row"
-        >
+      <div ref="headScrollRef" class="compliance-table-head-scroll">
+        <div class="compliance-table__header">
           <div
           <div
             v-for="column in columns"
             v-for="column in columns"
             :key="column.key"
             :key="column.key"
-            class="compliance-table__cell"
-            :class="{ 'compliance-table__cell--action': column.type === 'action' }"
+            class="compliance-table__cell compliance-table__cell--header"
             :style="cellStyle(column)"
             :style="cellStyle(column)"
           >
           >
-            <button
-              v-if="column.type === 'action'"
-              type="button"
-              class="compliance-table__link"
-              @click="$emit('row-action', row)"
-            >
-              {{ column.actionLabel || '查看' }}
-            </button>
-            <template v-else>{{ row[column.key] ?? '暂无' }}</template>
+            {{ column.label }}
           </div>
           </div>
         </div>
         </div>
-      </template>
-      <div v-else class="compliance-table__empty">暂无符合条件的数据</div>
+      </div>
+    </div>
+    <div
+      class="compliance-table-body-scroll"
+      :class="{ 'compliance-table-body-scroll--sticky-chrome': stickyChrome }"
+      @scroll="syncTableScroll"
+    >
+      <div class="compliance-table__body">
+        <template v-if="paginatedRows.length">
+          <div
+            v-for="(row, rowIndex) in paginatedRows"
+            :key="row.id ?? rowIndex"
+            class="compliance-table__row"
+          >
+            <div
+              v-for="column in columns"
+              :key="column.key"
+              class="compliance-table__cell"
+              :class="{ 'compliance-table__cell--action': column.type === 'action' }"
+              :style="cellStyle(column)"
+            >
+              <button
+                v-if="column.type === 'action'"
+                type="button"
+                class="compliance-table__link"
+                @click="$emit('row-action', row)"
+              >
+                {{ column.actionLabel || '查看' }}
+              </button>
+              <template v-else>{{ row[column.key] ?? '暂无' }}</template>
+            </div>
+          </div>
+        </template>
+        <div v-else class="compliance-table__empty">暂无符合条件的数据</div>
+      </div>
     </div>
     </div>
     <div class="compliance-table__pagination">
     <div class="compliance-table__pagination">
       <button type="button" :disabled="currentPage === 1" @click="prevPage">
       <button type="button" :disabled="currentPage === 1" @click="prevPage">
@@ -51,7 +64,7 @@
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-import { ref, computed, watch, defineProps, defineEmits} from 'vue';
+import { ref, computed, watch, defineProps, defineEmits } from 'vue';
 
 
 const props = defineProps({
 const props = defineProps({
   columns: {
   columns: {
@@ -70,10 +83,24 @@ const props = defineProps({
     type: Boolean,
     type: Boolean,
     default: false,
     default: false,
   },
   },
+  stickyChrome: {
+    type: Boolean,
+    default: false,
+  },
 });
 });
 
 
 defineEmits(['row-action']);
 defineEmits(['row-action']);
 
 
+const headScrollRef = ref(null);
+
+const syncTableScroll = (event) => {
+  const head = headScrollRef.value;
+  const scrollLeft = event.target.scrollLeft;
+  if (head && head.scrollLeft !== scrollLeft) {
+    head.scrollLeft = scrollLeft;
+  }
+};
+
 const cellStyle = (column) => {
 const cellStyle = (column) => {
   if (props.fluid) {
   if (props.fluid) {
     if (column.type === 'action') {
     if (column.type === 'action') {
@@ -137,6 +164,46 @@ watch(totalPages, (pages) => {
   gap: 4px;
   gap: 4px;
 }
 }
 
 
+/* 与 PageHeader 高度一致(layout/PageHeader.vue) */
+.compliance-table__sticky-chrome {
+  position: sticky;
+  top: 64px;
+  z-index: 50;
+  background: var(--color-surface);
+  display: flex;
+  flex-direction: column;
+  gap: var(--section-gap);
+  margin: 0 calc(-1 * var(--card-padding));
+  padding: 0 var(--card-padding);
+  box-shadow: 0 4px 12px rgba(17, 17, 17, 0.06);
+}
+
+.compliance-table__chrome-content {
+  display: flex;
+  flex-direction: column;
+  gap: var(--section-gap);
+}
+
+.compliance-table-head-scroll {
+  width: 100%;
+  overflow: hidden;
+  flex-shrink: 0;
+  border-bottom: 1px solid var(--color-divider);
+  padding-right: 8px;
+  box-sizing: border-box;
+}
+
+.compliance-table-body-scroll {
+  width: 100%;
+  max-height: min(720px, calc(100vh - 280px));
+  overflow: auto;
+  scrollbar-gutter: stable;
+}
+
+.compliance-table-body-scroll--sticky-chrome {
+  max-height: min(640px, calc(100vh - 380px));
+}
+
 .compliance-table__header,
 .compliance-table__header,
 .compliance-table__row {
 .compliance-table__row {
   display: flex;
   display: flex;
@@ -168,7 +235,7 @@ watch(totalPages, (pages) => {
 
 
 .compliance-table--fluid .compliance-table__cell--header {
 .compliance-table--fluid .compliance-table__cell--header {
   white-space: nowrap;
   white-space: nowrap;
-  overflow: hidden;
+  overflow: visible;
   text-overflow: ellipsis;
   text-overflow: ellipsis;
   height: 42px;
   height: 42px;
   line-height: 42px;
   line-height: 42px;
@@ -286,5 +353,4 @@ watch(totalPages, (pages) => {
   font-size: 14px;
   font-size: 14px;
   padding: 0;
   padding: 0;
 }
 }
-
 </style>
 </style>

+ 31 - 36
src/components/stats/TopicFullDataListSection.vue

@@ -1,35 +1,36 @@
 <template>
 <template>
   <div ref="rootRef" class="topic-full-list">
   <div ref="rootRef" class="topic-full-list">
-    <div class="topic-full-list__head">
-      <SectionHeader :title="title" />
-      <button
-        v-if="showExport"
-        type="button"
-        class="export-btn"
-        @click="$emit('export')"
-      >
-        {{ exportLabel }}
-      </button>
-    </div>
-
-    <slot name="filters" />
-
-    <slot name="hint">
-      <p v-if="filterHint" class="filter-hint">
-        当前筛选:<strong>{{ filterHint }}</strong>
-        <template v-if="total != null"> · 共 {{ total }} 条</template>
-      </p>
-    </slot>
-
-    <div class="table-scroll">
-      <ComplianceAssetTable
-        fluid
-        :columns="columns"
-        :rows="rows"
-        :page-size="pageSize"
-        @row-action="$emit('row-action', $event)"
-      />
-    </div>
+    <ComplianceAssetTable
+      fluid
+      sticky-chrome
+      :columns="columns"
+      :rows="rows"
+      :page-size="pageSize"
+      @row-action="$emit('row-action', $event)"
+    >
+      <template #chrome>
+        <div class="topic-full-list__head">
+          <SectionHeader :title="title" />
+          <button
+            v-if="showExport"
+            type="button"
+            class="export-btn"
+            @click="$emit('export')"
+          >
+            {{ exportLabel }}
+          </button>
+        </div>
+
+        <slot name="filters" />
+
+        <slot name="hint">
+          <p v-if="filterHint" class="filter-hint">
+            当前筛选:<strong>{{ filterHint }}</strong>
+            <template v-if="total != null"> · 共 {{ total }} 条</template>
+          </p>
+        </slot>
+      </template>
+    </ComplianceAssetTable>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -91,7 +92,6 @@ defineExpose({
   padding: var(--card-padding);
   padding: var(--card-padding);
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
-  gap: var(--section-gap);
   background: var(--color-surface);
   background: var(--color-surface);
   border: 1px solid var(--color-accent-border);
   border: 1px solid var(--color-accent-border);
 }
 }
@@ -104,11 +104,6 @@ defineExpose({
   flex-wrap: wrap;
   flex-wrap: wrap;
 }
 }
 
 
-.table-scroll {
-  width: 100%;
-  overflow-x: auto;
-}
-
 .export-btn {
 .export-btn {
   height: 38px;
   height: 38px;
   padding: 0 20px;
   padding: 0 20px;

+ 1 - 1
src/pages/HomePage.vue

@@ -120,7 +120,7 @@ const metricCardList = computed(() => [
   },
   },
   {
   {
     id: 2,
     id: 2,
-    title: '已出租/在用建筑面积',
+    title: '已使用建筑面积',
     text: '占总建筑面积',
     text: '占总建筑面积',
     showTrendIcon: false,
     showTrendIcon: false,
     percent: rentPercent.value,
     percent: rentPercent.value,

+ 1 - 1
src/pages/Topic2Page.vue

@@ -56,7 +56,7 @@
         title="权属穿透全量数据列表"
         title="权属穿透全量数据列表"
         :columns="TOPIC2_FULL_COLUMNS"
         :columns="TOPIC2_FULL_COLUMNS"
         :rows="fullRows"
         :rows="fullRows"
-        :page-size="7"
+        :page-size="10"
         :filter-hint="filterHint"
         :filter-hint="filterHint"
         @export="handleExport"
         @export="handleExport"
         @row-action="openAssetDetail"
         @row-action="openAssetDetail"

+ 1 - 1
src/pages/Topic3Page.vue

@@ -120,7 +120,7 @@
         title="闲置资产全量数据列表"
         title="闲置资产全量数据列表"
         :columns="TOPIC3_FULL_COLUMNS"
         :columns="TOPIC3_FULL_COLUMNS"
         :rows="fullRows"
         :rows="fullRows"
-        :page-size="7"
+        :page-size="10"
         :filter-hint="filterHint"
         :filter-hint="filterHint"
         :total="fullRows.length"
         :total="fullRows.length"
         @export="handleExport"
         @export="handleExport"