feat(reports): implement report analysis

This commit is contained in:
yelan
2026-08-27 16:48:17 +08:00
parent 94a0d88f8b
commit 332fb53cfa
8 changed files with 1198 additions and 16 deletions
@@ -0,0 +1,114 @@
<script setup lang="ts">
import { computed } from 'vue'
import type { ReportTrendPoint } from '../types'
const props = defineProps<{
points: ReportTrendPoint[]
}>()
const chartBars = computed(() => {
const width = 640
const height = 200
const paddingX = 30
const paddingY = 30
const slotWidth = (width - paddingX * 2) / Math.max(props.points.length, 1)
const barWidth = slotWidth * 0.55
const maxValue = Math.max(...props.points.map((point) => point.value), 3) * 1.2
return props.points.map((point, index) => {
const barHeight = (point.value / maxValue) * (height - paddingY * 2)
const x = paddingX + slotWidth * index + (slotWidth - barWidth) / 2
const y = height - paddingY - barHeight
return {
...point,
x,
y,
width: barWidth,
height: Math.max(barHeight, 2),
}
})
})
const gridLines = [0, 1, 2, 3].map((index) => 30 + ((200 - 60) / 3) * index)
</script>
<template>
<div v-if="points.length" class="chart-wrap">
<svg viewBox="0 0 640 200" role="img" aria-label="每日签署量趋势柱状图">
<defs>
<linearGradient id="report-bar-gradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#18a0c0" />
<stop offset="1" stop-color="#0e6e8c" />
</linearGradient>
</defs>
<line
v-for="line in gridLines"
:key="line"
x1="30"
:y1="line"
x2="610"
:y2="line"
stroke="#e6eef2"
stroke-dasharray="3 4"
/>
<g v-for="bar in chartBars" :key="bar.date">
<rect
:x="bar.x"
:y="bar.y"
:width="bar.width"
:height="bar.height"
rx="4"
:fill="bar.value ? 'url(#report-bar-gradient)' : '#e2ebef'"
>
<title>{{ bar.label }}:{{ bar.value }} 单</title>
</rect>
<text
v-if="bar.value"
:x="bar.x + bar.width / 2"
:y="bar.y - 6"
text-anchor="middle"
font-size="10.5"
fill="#0a4f66"
font-weight="bold"
>
{{ bar.value }}
</text>
<text
:x="bar.x + bar.width / 2"
y="190"
text-anchor="middle"
font-size="9.5"
fill="#687f8b"
>
{{ bar.label }}
</text>
</g>
</svg>
</div>
<div v-else class="empty-chart">暂无趋势数据</div>
</template>
<style scoped>
.chart-wrap {
width: 100%;
min-height: 200px;
}
.chart-wrap svg {
display: block;
width: 100%;
height: auto;
}
.empty-chart {
display: grid;
min-height: 200px;
color: var(--mut);
font-size: 13px;
place-items: center;
}
</style>