fix store chart style

This commit is contained in:
Timi
2026-08-12 17:06:02 +08:00
parent f14e36c730
commit a02fa239c2
6 changed files with 128 additions and 3 deletions
+23
View File
@@ -63,6 +63,9 @@
:title="getRecordEventName(item)"
:description="getRecordCustomerName(item)"
:note="`${formatRecordTime(item.registeredAt)}`"
arrow
hover
@click="toRecordDetail(item)"
/>
</t-cell-group>
<div v-else class="empty-block">该日暂无登记事件记录</div>
@@ -130,6 +133,8 @@ const emit = defineEmits<{
"update:selectedEventIdList": [value: string[]];
}>();
const route = useRoute();
const router = useRouter();
const weekNameList = ["日", "一", "二", "三", "四", "五", "六"];
const dayRecordVisible = ref(false);
const eventFilterVisible = ref(false);
@@ -192,6 +197,20 @@ function openDayRecords(day: CalendarDay): void {
dayRecordVisible.value = true;
}
async function toRecordDetail(record: EventRecord): Promise<void> {
if (!record.id) {
return;
}
dayRecordVisible.value = false;
await router.push({
path: `/management/registration-event-records/${record.id}`,
query: {
transitionDepth: String(getCurrentRouteDepth() + 1)
}
});
}
function getRecordEventName(record?: EventRecord): string {
if (!record) {
return "";
@@ -226,6 +245,10 @@ function isInCurrentMonth(value?: number): boolean {
return !!date && date.getFullYear() === props.modelValue.getFullYear() && date.getMonth() === props.modelValue.getMonth();
}
function getCurrentRouteDepth(): number {
return Number(route.meta.depth ?? 0);
}
function getMonthStart(date: Date): Date {
return new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0);
}
+21
View File
@@ -30,6 +30,11 @@ const pageBackground = computed(() => globalUIStore.bodyBackground);
const pathCache = new Map<string, number>();
function calcDepth(sourceRoute: RouteLocationNormalized): number {
const queryDepth = parseTransitionDepth(sourceRoute.query.transitionDepth);
if (queryDepth !== undefined) {
return queryDepth;
}
if (!sourceRoute.meta.dynamicDepth) {
return Number(sourceRoute.meta.depth ?? 0);
}
@@ -47,6 +52,22 @@ function calcDepth(sourceRoute: RouteLocationNormalized): number {
return depth;
}
function parseTransitionDepth(value: unknown): number | undefined {
if (Array.isArray(value)) {
return parseTransitionDepth(value[0]);
}
if (typeof value !== "string") {
return undefined;
}
const depth = Number(value);
if (!Number.isInteger(depth) || depth < 0 || 20 < depth) {
return undefined;
}
return depth;
}
const unregisterGuard = router.beforeEach((to, from) => {
const toDepth = calcDepth(to);
const fromDepth = calcDepth(from);
@@ -27,6 +27,16 @@ const statList = ref<CustomerGenderStatView[]>([]);
const chartOption = computed<EChartsOption>(() => ({
...buildStoreBaseChartOption(props.dateTextList),
grid: {
top: 24,
left: 12,
right: 12,
bottom: 12,
containLabel: true
},
legend: {
show: false
},
tooltip: {
trigger: "item"
},
@@ -1,7 +1,11 @@
<template>
<section class="chart-section">
<h2>登记量趋势</h2>
<div ref="chartElement" class="chart" />
<div
ref="chartElement"
class="chart"
:style="chartStyle"
/>
<chart-range-slider
v-if="showSlider"
:model-value="sliderValue"
@@ -35,6 +39,7 @@ let statRequestId = 0;
// ---------- 图表窗口 ----------
const chartWidth = ref(window.innerWidth);
const dateTextList = computed(() => props.dateTextList);
const {
rangeText,
@@ -44,8 +49,21 @@ const {
visibleDateTextList,
handleSliderChange
} = useStoreChartWindow(dateTextList);
const legendRowCount = computed(() => countLegendRows(eventList.value.map(event => event.name || "未命名事件")));
const chartHeight = computed(() => `${16 + Math.max(0, legendRowCount.value - 1) * 1.5}rem`);
const legendBottom = computed(() => 20 + legendRowCount.value * 24);
const chartStyle = computed(() => ({
height: chartHeight.value
}));
const chartOption = computed<EChartsOption>(() => ({
...buildStoreBaseChartOption(visibleDateTextList.value),
grid: {
top: Math.max(48, legendBottom.value),
left: 12,
right: 12,
bottom: 12,
containLabel: true
},
series: eventList.value.map(event => ({
name: event.name || "未命名事件",
type: "bar",
@@ -58,6 +76,7 @@ const chartOption = computed<EChartsOption>(() => ({
}));
const { chartElement } = useStoreChart(chartOption);
let resizeObserver: ResizeObserver | undefined;
watch(() => props.dateTextList, async () => {
await loadDailyStat();
@@ -66,10 +85,20 @@ watch(() => props.dateTextList, async () => {
});
onMounted(async () => {
resizeObserver = new window.ResizeObserver(updateChartWidth);
if (chartElement.value) {
resizeObserver.observe(chartElement.value);
updateChartWidth();
}
await loadEvents();
await loadDailyStat();
});
onBeforeUnmount(() => {
resizeObserver?.disconnect();
resizeObserver = undefined;
});
async function loadEvents(): Promise<void> {
eventList.value = await EventAPI.listValid();
}
@@ -110,6 +139,30 @@ function getEventIdList(): string[] {
return eventList.value.map(item => item.id).filter((id): id is string => Boolean(id));
}
function updateChartWidth(): void {
const width = chartElement.value?.clientWidth || window.innerWidth;
chartWidth.value = Math.max(1, width);
}
function countLegendRows(nameList: string[]): number {
let rowCount = 1;
let rowWidth = 0;
const maxWidth = Math.max(160, chartWidth.value - 24);
for (const name of nameList) {
const itemWidth = estimateLegendItemWidth(name);
if (0 < rowWidth && maxWidth < rowWidth + itemWidth) {
rowCount++;
rowWidth = 0;
}
rowWidth += itemWidth;
}
return rowCount;
}
function estimateLegendItemWidth(name: string): number {
return Math.min(chartWidth.value, 38 + Array.from(name).length * 14);
}
function groupRecordDailyStatByEventId(list: StoreEventRecordDailyStatView[]): Record<string, StoreEventRecordDailyStatView[]> {
const map: Record<string, StoreEventRecordDailyStatView[]> = {};
for (const item of list) {
@@ -24,19 +24,32 @@ const eventList = ref<EventItem[]>([]);
const statMap = ref<Record<string, StoreEventRecordDailyStatView[]>>({});
let statRequestId = 0;
const shouldRotateAxisLabel = computed(() => eventList.value.length > 4 || eventList.value.some(item => 6 < getEventName(item).length));
const chartOption = computed<EChartsOption>(() => ({
...buildStoreBaseChartOption(props.dateTextList),
grid: {
top: 24,
left: 12,
right: 12,
bottom: shouldRotateAxisLabel.value ? 68 : 36,
containLabel: true
},
legend: {
show: false
},
xAxis: {
type: "category",
data: eventList.value.map(item => item.name || "未命名事件"),
data: eventList.value.map(getEventName),
axisTick: {
show: false
},
axisLabel: {
color: "#52607a"
color: "#52607a",
hideOverlap: true,
interval: 0,
overflow: "truncate",
rotate: shouldRotateAxisLabel.value ? 45 : 0,
width: shouldRotateAxisLabel.value ? 72 : 56
}
},
series: [{
@@ -99,6 +112,10 @@ function getEventColor(event: EventItem): string | undefined {
return event.color || undefined;
}
function getEventName(event: EventItem): string {
return event.name || "未命名事件";
}
function getEventIdList(): string[] {
return eventList.value.map(item => item.id).filter((id): id is string => Boolean(id));
}
@@ -87,6 +87,7 @@ export function useStoreChart(option: ComputedRef<EChartsOption> | Ref<EChartsOp
}
chart = chart || init(chartElement.value);
chart.setOption(option.value, true);
chart.resize();
}
function resizeChart(): void {