feat(customer): implement customer analysis page and drawer flow

This commit is contained in:
2026-03-03 16:45:22 +08:00
parent ccf7d403de
commit d450526204
28 changed files with 2880 additions and 3 deletions

View File

@@ -0,0 +1,158 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import { Empty, Spin } from 'ant-design-vue';
import CustomerDetailDrawer from '#/views/customer/list/components/CustomerDetailDrawer.vue';
import CustomerProfileDrawer from '#/views/customer/list/components/CustomerProfileDrawer.vue';
import AmountDistributionCard from './components/AmountDistributionCard.vue';
import AnalysisStatsGrid from './components/AnalysisStatsGrid.vue';
import AnalysisToolbar from './components/AnalysisToolbar.vue';
import CompositionCard from './components/CompositionCard.vue';
import GrowthTrendCard from './components/GrowthTrendCard.vue';
import MemberDetailDrawer from './components/MemberDetailDrawer.vue';
import RfmMatrixCard from './components/RfmMatrixCard.vue';
import SegmentDrawer from './components/SegmentDrawer.vue';
import TopCustomerTableCard from './components/TopCustomerTableCard.vue';
import { useCustomerAnalysisPage } from './composables/useCustomerAnalysisPage';
const {
detail,
handleExport,
handleSegmentPageChange,
handleSegmentSearch,
isDetailDrawerOpen,
isDetailLoading,
isExporting,
isMemberDrawerOpen,
isMemberLoading,
isOverviewLoading,
isProfileDrawerOpen,
isProfileLoading,
isSegmentDrawerOpen,
isSegmentLoading,
isStoreLoading,
memberDetail,
openDetail,
openMember,
openMemberFromDetail,
openProfile,
openProfilePage,
openSegmentByCode,
openTopCustomerDetail,
overview,
period,
profile,
segmentKeyword,
segmentPagination,
segmentResult,
selectedStoreId,
setDetailDrawerOpen,
setMemberDrawerOpen,
setPeriod,
setProfileDrawerOpen,
setSegmentDrawerOpen,
setSegmentKeyword,
setSelectedStoreId,
storeOptions,
} = useCustomerAnalysisPage();
</script>
<template>
<Page title="客户分析" content-class="page-customer-analysis">
<div class="ca-page">
<AnalysisToolbar
:selected-store-id="selectedStoreId"
:store-options="storeOptions"
:is-store-loading="isStoreLoading"
:period="period"
:is-exporting="isExporting"
@update:selected-store-id="setSelectedStoreId"
@update:period="setPeriod"
@export="handleExport"
/>
<div v-if="!selectedStoreId" class="ca-empty">
<Empty description="暂无门店,请先创建门店" />
</div>
<Spin v-else :spinning="isOverviewLoading">
<AnalysisStatsGrid :overview="overview" @segment="openSegmentByCode" />
<div class="ca-grid">
<GrowthTrendCard
:points="overview.growthTrend"
@segment="openSegmentByCode"
/>
<CompositionCard
:items="overview.composition"
:total-customers="overview.totalCustomers"
@segment="openSegmentByCode"
/>
<AmountDistributionCard
:items="overview.amountDistribution"
@segment="openSegmentByCode"
/>
<RfmMatrixCard
:rows="overview.rfmRows"
@segment="openSegmentByCode"
/>
<TopCustomerTableCard
:rows="overview.topCustomers"
@detail="openTopCustomerDetail"
@segment="openSegmentByCode"
/>
</div>
</Spin>
</div>
<SegmentDrawer
:open="isSegmentDrawerOpen"
:loading="isSegmentLoading"
:result="segmentResult"
:pagination="segmentPagination"
:keyword="segmentKeyword"
@close="setSegmentDrawerOpen(false)"
@update:keyword="setSegmentKeyword"
@search="handleSegmentSearch"
@page-change="handleSegmentPageChange"
@detail="openDetail"
@profile="openProfile"
@member="openMember"
/>
<CustomerDetailDrawer
:open="isDetailDrawerOpen"
:loading="isDetailLoading"
:detail="detail"
:show-member-action="true"
@close="setDetailDrawerOpen(false)"
@profile="openProfile"
@profile-page="openProfilePage"
@member="openMemberFromDetail"
/>
<CustomerProfileDrawer
:open="isProfileDrawerOpen"
:loading="isProfileLoading"
:profile="profile"
@close="setProfileDrawerOpen(false)"
/>
<MemberDetailDrawer
:open="isMemberDrawerOpen"
:loading="isMemberLoading"
:detail="memberDetail"
@close="setMemberDrawerOpen(false)"
/>
</Page>
</template>
<style lang="less">
@import './styles/index.less';
</style>