Browse Source

新增首页饼图点击跳转

gongtianxiao 1 tháng trước cách đây
mục cha
commit
8b1c42569f

+ 16 - 0
src/components/stats/ChartSpecial.vue

@@ -21,16 +21,20 @@
           <SectionHeader :title="item.text" />
           <BarChart
             v-if="isSmallScreen"
+            clickable
             :xAxisData="pieToBar(item.data).xAxisData"
             :seriesData="pieToBar(item.data).seriesData"
             :style="smallBarStyle"
+            @bar-click="item.onSliceClick"
           />
           <PieChart
             v-else
+            clickable
             :data="item.data"
             :legend-head-count="item.legendHeadCount"
             :legend-grid-no-padding-right="item.legendGridNoPaddingRight"
             value-unit="万m²"
+            @slice-click="item.onSliceClick"
           />
         </div>
       </div>
@@ -57,6 +61,7 @@ import { useRouter } from 'vue-router';
 import { useEnterpriseStore } from '@/store/enterprise';
 import { useFilterStore } from '@/store/filter';
 import { sumFieldToWan,toWanSquareMeters } from '@/utils/areaMath';
+import { buildTopic1ChartQuery } from '@/utils/topic1ChartNavigation';
 
 const router = useRouter();
 const filterStore = useFilterStore();
@@ -86,6 +91,11 @@ const onMainBarClick = (groupName) => {
   router.push('/topic1');
 };
 
+const navigateToTopic1FromPie = (chartKey, sliceName) => {
+  const query = buildTopic1ChartQuery(chartKey, sliceName);
+  router.push(Object.keys(query).length ? { path: '/topic1', query } : '/topic1');
+};
+
 const filteredList = computed(() =>
   enterpriseStore.filteredByGroup(filterStore.selectGroup, filterStore.selectDate)
 );
@@ -241,19 +251,25 @@ const pieChartList = computed(() => [
   {
     name: '图表1',
     text: '土地类型面积',
+    chartKey: 'landUsage',
     data: isSmallScreen.value ? purposeListCompact.value : purposeListFull.value,
     legendHeadCount: isSmallScreen.value ? 0 : PURPOSE_TOP_N,
+    onSliceClick: (name) => navigateToTopic1FromPie('landUsage', name),
   },
   {
     name: '图表2',
     text: '房屋使用状态',
+    chartKey: 'util',
     data: usageStatusList.value,
+    onSliceClick: (name) => navigateToTopic1FromPie('util', name),
   },
   {
     name: '图表3',
     text: '房龄分布',
+    chartKey: 'age',
     data: ageDistributionList.value,
     legendGridNoPaddingRight: true,
+    onSliceClick: (name) => navigateToTopic1FromPie('age', name),
   },
 ]);
 

+ 26 - 19
src/pages/Topic1Page.vue

@@ -74,8 +74,8 @@
 
 <script setup>
 import { showWarning } from '@/utils/message';
-import { ref, computed, watch } from 'vue';
-import { useRouter } from 'vue-router';
+import { ref, computed, watch, nextTick } from 'vue';
+import { useRouter, useRoute } from 'vue-router';
 import PageHeader from '@/components/layout/PageHeader.vue';
 import TopicPageHeader from '@/components/stats/TopicPageHeader.vue';
 import QueryFilter from '@/components/stats/QueryFilter.vue';
@@ -93,21 +93,25 @@ import {
   mapTopic1Row,
 } from '@/utils/topic1AssetList';
 import { GROUP_DISPLAY_NAMES } from '@/utils/aggregateReportRecords';
+import {
+  AGE_SLICE_TO_KEY,
+  createDefaultTopic1ListFilters,
+  hasTopic1ChartQuery,
+  parseTopic1ListFiltersFromQuery,
+} from '@/utils/topic1ChartNavigation';
 
 const enterpriseStore = useEnterpriseStore();
 const filterStore = useFilterStore();
 const router = useRouter();
+const route = useRoute();
 const fullListRef = ref(null);
 
 const DISPLAY_TO_GROUP = Object.fromEntries(
   Object.entries(GROUP_DISPLAY_NAMES).map(([group, short]) => [short, group])
 );
 
-const AGE_SLICE_TO_KEY = {
-  '0-10年': '0-10',
-  '10-20年': '10-20',
-  '20年以上': '20+',
-};
+const createDefaultFilters = (group = filterStore.selectGroup) =>
+  createDefaultTopic1ListFilters(group);
 
 const USAGE_PIE_CONFIG = [
   { name: '出租', field: 'c_czmj', color: 'rgba(1, 118, 255, 1)' },
@@ -116,17 +120,6 @@ const USAGE_PIE_CONFIG = [
   { name: '闲置', field: 'c_xzmj', color: 'rgba(255, 232, 119, 1)' },
 ];
 
-const createDefaultFilters = (group = filterStore.selectGroup) => ({
-  keyword: '',
-  purpose: '全部',
-  group,
-  age: '全部',
-  util: '全部',
-  fwUsage: '',
-  landType: '',
-  landUsage: '',
-});
-
 const listFilters = ref(createDefaultFilters());
 
 const filteredList = computed(() =>
@@ -272,9 +265,23 @@ const resetListFilters = () => {
 };
 
 watch(() => filterStore.selectGroup, (group) => {
+  if (hasTopic1ChartQuery(route.query)) {
+    listFilters.value = parseTopic1ListFiltersFromQuery(route.query, group);
+    return;
+  }
   listFilters.value = createDefaultFilters(group);
 });
 
+watch(
+  () => route.fullPath,
+  () => {
+    if (!hasTopic1ChartQuery(route.query)) return;
+    listFilters.value = parseTopic1ListFiltersFromQuery(route.query, filterStore.selectGroup);
+    nextTick(() => scrollToFullList());
+  },
+  { immediate: true },
+);
+
 watch(
   () => listFilters.value.group,
   (group) => {
@@ -389,7 +396,7 @@ const topPieChartsList = computed(() => [
   width: 100%;
   max-width: var(--page-max-width);
   padding: 24px;
-  padding-bottom: 32px;
+  padding-bottom: 0;
   display: flex;
   flex-direction: column;
   gap: 12px;

+ 54 - 0
src/utils/topic1ChartNavigation.js

@@ -0,0 +1,54 @@
+/** 房龄环形图扇区名称 → 列表筛选项 key */
+export const AGE_SLICE_TO_KEY = {
+  '0-10年': '0-10',
+  '10-20年': '10-20',
+  '20年以上': '20+',
+};
+
+export const TOPIC1_HOME_LAND_OTHER = '其他';
+
+export const createDefaultTopic1ListFilters = (group = '全部') => ({
+  keyword: '',
+  purpose: '全部',
+  group,
+  age: '全部',
+  util: '全部',
+  fwUsage: '',
+  landType: '',
+  landUsage: '',
+});
+
+export const hasTopic1ChartQuery = (query = {}) =>
+  Boolean(query.util || query.landUsage || query.age || query.fwUsage);
+
+/** 首页 / 外链跳转:环形图扇区 → 专题1路由 query */
+export const buildTopic1ChartQuery = (chartKey, sliceName) => {
+  const query = {};
+  if (chartKey === 'util' && sliceName) {
+    query.util = sliceName;
+    return query;
+  }
+  if (chartKey === 'landUsage' && sliceName && sliceName !== TOPIC1_HOME_LAND_OTHER) {
+    query.landUsage = sliceName;
+    return query;
+  }
+  if (chartKey === 'age') {
+    const ageKey = AGE_SLICE_TO_KEY[sliceName];
+    if (ageKey) query.age = ageKey;
+    return query;
+  }
+  if (chartKey === 'fwUsage' && sliceName) {
+    query.fwUsage = sliceName;
+    return query;
+  }
+  return query;
+};
+
+export const parseTopic1ListFiltersFromQuery = (query = {}, group = '全部') => {
+  const filters = createDefaultTopic1ListFilters(group);
+  if (typeof query.util === 'string' && query.util) filters.util = query.util;
+  if (typeof query.landUsage === 'string' && query.landUsage) filters.landUsage = query.landUsage;
+  if (typeof query.age === 'string' && query.age) filters.age = query.age;
+  if (typeof query.fwUsage === 'string' && query.fwUsage) filters.fwUsage = query.fwUsage;
+  return filters;
+};