feat(customer): implement customer analysis page and drawer flow
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import type {
|
||||
CustomerAnalysisCompositionItemDto,
|
||||
CustomerAnalysisSegmentCode,
|
||||
} from '#/api/customer';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import {
|
||||
formatInteger,
|
||||
formatPercent,
|
||||
resolveCompositionToneColor,
|
||||
} from '../composables/customer-analysis-page/helpers';
|
||||
|
||||
interface Props {
|
||||
items: CustomerAnalysisCompositionItemDto[];
|
||||
totalCustomers: number;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'segment', segmentCode: CustomerAnalysisSegmentCode): void;
|
||||
}>();
|
||||
|
||||
const donutStyle = computed(() => {
|
||||
if (props.items.length === 0) {
|
||||
return {
|
||||
background: 'conic-gradient(#e5e7eb 0deg 360deg)',
|
||||
};
|
||||
}
|
||||
|
||||
let angle = 0;
|
||||
const parts: string[] = [];
|
||||
for (const item of props.items) {
|
||||
const start = angle;
|
||||
const delta = Math.max(0, Math.min(360, (item.percent / 100) * 360));
|
||||
angle += delta;
|
||||
const end = Math.min(360, angle);
|
||||
parts.push(
|
||||
`${resolveCompositionToneColor(item.tone)} ${start}deg ${end}deg`,
|
||||
);
|
||||
}
|
||||
|
||||
if (angle < 360) {
|
||||
parts.push(`#e5e7eb ${angle}deg 360deg`);
|
||||
}
|
||||
|
||||
return {
|
||||
background: `conic-gradient(${parts.join(',')})`,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="ca-card">
|
||||
<div class="ca-card-title">新老客占比</div>
|
||||
<div class="ca-donut-wrap">
|
||||
<div class="ca-donut" :style="donutStyle">
|
||||
<div class="ca-donut-hole">
|
||||
<div class="num">{{ formatInteger(props.totalCustomers) }}</div>
|
||||
<div class="lbl">总客户</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ca-legend">
|
||||
<button
|
||||
v-for="item in props.items"
|
||||
:key="item.segmentCode"
|
||||
class="ca-legend-item"
|
||||
type="button"
|
||||
@click="emit('segment', item.segmentCode)"
|
||||
>
|
||||
<span
|
||||
class="ca-legend-dot"
|
||||
:style="{ backgroundColor: resolveCompositionToneColor(item.tone) }"
|
||||
></span>
|
||||
<span class="ca-legend-label">{{ item.label }}</span>
|
||||
<span class="ca-legend-value">{{ formatPercent(item.percent) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user