| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- <template>
- <PageHeader />
- <div class="main">
- <QueryFilter />
- <div class="top-wrapper">
- <MetricCard
- v-for="item in metricCardList"
- :key="item.id"
- :title="item.title"
- :text="item.text"
- :showTrendIcon="item.showTrendIcon"
- :trend="item.trend"
- :percent="item.percent"
- :value="item.value"
- :showUnit="item.showUnit"
- />
- </div>
- <ChartSpecial />
- <MonthlyReport />
- </div>
- </template>
- <script setup>
- import PageHeader from '@/components/layout/PageHeader.vue';
- import QueryFilter from '@/components/stats/QueryFilter.vue';
- import ChartSpecial from '@/components/stats/ChartSpecial.vue';
- import MonthlyReport from '@/components/stats/MonthlyReport.vue';
- import MetricCard from '@/components/stats/MetricCard.vue';
- import { computed, onMounted } from 'vue';
- import { useEnterpriseStore } from '@/store/enterprise';
- import { useFilterStore } from '@/store/filter';
- import { sumFieldToWan, sumFieldsToWan } from '@/utils/areaMath';
- import { formatPercent2 } from '@/utils/calculatePercentage';
- import {
- buildHistoricalSnapshots,
- computeCertifiedRateFromSnapshots,
- computeIdleRateFromSnapshots,
- emptyComparison,
- formatRatePointChange,
- formatRelativeChange,
- getPreviousMonthPeriod,
- getYearAgoPeriod,
- sumSnapshotsToWan,
- } from '@/utils/statsComparison';
- const filterStore = useFilterStore();
- const enterpriseStore = useEnterpriseStore();
- const filteredList = computed(() =>
- enterpriseStore.filteredByGroup(filterStore.selectGroup, filterStore.selectDate)
- );
- const previousMonth = computed(() => getPreviousMonthPeriod(filterStore.selectDate));
- const previousYear = computed(() => getYearAgoPeriod(filterStore.selectDate));
- const momSnapshots = computed(() =>
- buildHistoricalSnapshots(filteredList.value, previousMonth.value)
- );
- const yoySnapshots = computed(() =>
- buildHistoricalSnapshots(filteredList.value, previousYear.value)
- );
- const totalBuildingArea = computed(() => sumFieldToWan(filteredList.value, 'c_sjjzmj'));
- const totalRentedArea = computed(() =>
- sumFieldsToWan(filteredList.value, ['c_zymj', 'c_cjmj', 'c_czmj'])
- );
- const rentPercent = computed(() =>
- formatPercent2(totalRentedArea.value, totalBuildingArea.value)
- );
- const idleArea = computed(() => sumFieldToWan(filteredList.value, 'c_xzmj'));
- const idleRate = computed(() => formatPercent2(idleArea.value, totalBuildingArea.value));
- const idleRateNum = computed(() => {
- const { rateNum } = computeIdleRateFromSnapshots(filteredList.value);
- return rateNum;
- });
- const certifiedAssetPercent = computed(() => {
- const sum = filteredList.value.filter((item) => item.c_sfblcz === '是').length;
- return formatPercent2(sum, filteredList.value.length);
- });
- const certifiedRateNum = computed(() => {
- const { rateNum } = computeCertifiedRateFromSnapshots(filteredList.value);
- return rateNum;
- });
- const buildingAreaYoY = computed(() => {
- if (!filterStore.selectDate) return emptyComparison();
- const previous = sumSnapshotsToWan(yoySnapshots.value, 'c_sjjzmj');
- return formatRelativeChange(totalBuildingArea.value, previous);
- });
- const idleRateMoM = computed(() => {
- if (!filterStore.selectDate) return emptyComparison();
- const { rateNum: previous } = computeIdleRateFromSnapshots(momSnapshots.value);
- return formatRatePointChange(idleRateNum.value, previous);
- });
- const certifiedRateMoM = computed(() => {
- if (!filterStore.selectDate) return emptyComparison();
- const { rateNum: previous } = computeCertifiedRateFromSnapshots(momSnapshots.value);
- return formatRatePointChange(certifiedRateNum.value, previous);
- });
- const metricCardList = computed(() => [
- {
- id: 1,
- title: '建筑总面积',
- text: '同比去年',
- percent: buildingAreaYoY.value.text,
- trend: buildingAreaYoY.value.trend,
- value: totalBuildingArea.value,
- showTrendIcon: true,
- showUnit: true,
- },
- {
- id: 2,
- title: '已出租/在用建筑面积',
- text: '占总建筑面积',
- showTrendIcon: false,
- percent: rentPercent.value,
- value: totalRentedArea.value,
- showUnit: true,
- },
- {
- id: 3,
- title: '闲置率',
- text: '环比上月',
- trend: idleRateMoM.value.trend,
- percent: idleRateMoM.value.text,
- value: idleRate.value,
- showTrendIcon: true,
- showUnit: false,
- },
- {
- id: 4,
- title: '已办证资产占比',
- text: '环比上月',
- trend: certifiedRateMoM.value.trend,
- percent: certifiedRateMoM.value.text,
- value: certifiedAssetPercent.value,
- showTrendIcon: true,
- showUnit: false,
- },
- ]);
- onMounted(async () => {
- await enterpriseStore.fetchStatisticsList();
- });
- </script>
- <style scoped>
- .main {
- width: 100%;
- max-width: var(--page-max-width);
- min-height: 1080px;
- height: auto;
- padding: 24px;
- display: flex;
- flex-direction: column;
- gap: 12px;
- position: relative;
- }
- .top-wrapper {
- width: 100%;
- max-width: var(--content-max-width);
- min-height: 146px;
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 16px;
- }
- .top-wrapper :deep(.stat-card) {
- width: 100%;
- max-width: none;
- height: 100%;
- min-height: 146px;
- }
- .top-wrapper :deep(.stat-card-header),
- .top-wrapper :deep(.stat-card-main) {
- width: 100%;
- max-width: none;
- }
- .top-wrapper :deep(.stat-card-trend) {
- width: auto;
- max-width: 100%;
- flex-shrink: 1;
- }
- </style>
|