fix rest day style in chart

This commit is contained in:
Timi
2026-09-23 16:12:09 +08:00
parent 9f4a7d7b2d
commit f8574c387d
7 changed files with 80 additions and 20 deletions
+21 -2
View File
@@ -24,7 +24,7 @@ import type { EChartsOption } from "echarts";
import ChartRangeSlider from "@/components/ChartRangeSlider.vue";
import { useStoreChart, useStoreChartWindow } from "@/pages/store/component/useStoreChart";
type ChartOptionBuilder = (visibleDateTextList: string[]) => EChartsOption;
type ChartOptionBuilder = (visibleDateTextList: string[], chartWidth: number) => EChartsOption;
const props = withDefaults(defineProps<{
caption?: string;
@@ -42,6 +42,7 @@ const props = withDefaults(defineProps<{
});
const dateTextList = computed(() => props.dateTextList);
const chartWidth = ref(window.innerWidth);
const {
rangeText,
showSlider: chartShowSlider,
@@ -51,9 +52,27 @@ const {
handleSliderChange
} = useStoreChartWindow(dateTextList);
const option = computed<EChartsOption>(() => typeof props.option === "function"
? props.option(visibleDateTextList.value)
? props.option(visibleDateTextList.value, chartWidth.value)
: props.option);
const { chartElement } = useStoreChart(option);
let resizeObserver: ResizeObserver | undefined;
onMounted(() => {
resizeObserver = new window.ResizeObserver(updateChartWidth);
if (chartElement.value) {
resizeObserver.observe(chartElement.value);
updateChartWidth();
}
});
onBeforeUnmount(() => {
resizeObserver?.disconnect();
resizeObserver = undefined;
});
function updateChartWidth(): void {
chartWidth.value = chartElement.value?.clientWidth || window.innerWidth;
}
</script>
<style scoped lang="less">
@@ -29,14 +29,14 @@ const props = defineProps<{
const dateTextList = computed(() => props.dateTextList);
const { restDaySet } = useRestDayCalendar(dateTextList);
function buildOption(visibleDateTextList: string[]): EChartsOption {
function buildOption(visibleDateTextList: string[], chartWidth: number): EChartsOption {
const labelList = visibleDateTextList.map(item => item.slice(5));
return {
...buildAxisChartOption(labelList),
xAxis: {
type: "category",
data: labelList,
axisTick: { show: false },
axisTick: { show: true, length: 0, interval: 0 },
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
},
yAxis: [
@@ -62,7 +62,7 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
name: "订单数",
type: "bar",
yAxisIndex: 0,
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, window.innerWidth - 32),
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, chartWidth),
tooltip: { valueFormatter: value => formatQuantity(Number(value)) },
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.orderCount))
},
@@ -29,14 +29,14 @@ const props = defineProps<{
const dateTextList = computed(() => props.dateTextList);
const { restDaySet } = useRestDayCalendar(dateTextList);
function buildOption(visibleDateTextList: string[]): EChartsOption {
function buildOption(visibleDateTextList: string[], chartWidth: number): EChartsOption {
const labelList = visibleDateTextList.map(item => item.slice(5));
return {
...buildAxisChartOption(labelList),
xAxis: {
type: "category",
data: labelList,
axisTick: { show: false },
axisTick: { show: true, length: 0, interval: 0 },
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
},
series: [
@@ -44,7 +44,7 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
name: "直接履约",
type: "bar",
stack: "fulfillment",
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, window.innerWidth - 32),
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, chartWidth),
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.directBaseQuantity))
},
{
@@ -29,14 +29,14 @@ const props = defineProps<{
const dateTextList = computed(() => props.dateTextList);
const { restDaySet } = useRestDayCalendar(dateTextList);
function buildOption(visibleDateTextList: string[]): EChartsOption {
function buildOption(visibleDateTextList: string[], chartWidth: number): EChartsOption {
const labelList = visibleDateTextList.map(item => item.slice(5));
return {
...buildAxisChartOption(labelList),
xAxis: {
type: "category",
data: labelList,
axisTick: { show: false },
axisTick: { show: true, length: 0, interval: 0 },
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
},
yAxis: [
@@ -62,7 +62,7 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
type: "bar",
stack: "quantity",
yAxisIndex: 0,
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, window.innerWidth - 32),
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, chartWidth),
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.directBaseQuantity))
},
{
@@ -29,7 +29,7 @@ const props = defineProps<{
const dateTextList = computed(() => props.dateTextList);
const { restDaySet } = useRestDayCalendar(dateTextList);
function buildOption(visibleDateTextList: string[]): EChartsOption {
function buildOption(visibleDateTextList: string[], chartWidth: number): EChartsOption {
const labelList = visibleDateTextList.map(item => item.slice(5));
return {
...buildAxisChartOption(labelList),
@@ -37,7 +37,7 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
type: "category",
data: labelList,
axisLine: { onZero: true },
axisTick: { show: false },
axisTick: { show: true, length: 0, interval: 0 },
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
},
series: [
@@ -45,7 +45,7 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
name: "入库",
type: "bar",
stack: "stock-movement",
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, window.innerWidth - 32),
markArea: buildRestDayMarkArea(visibleDateTextList, restDaySet.value, chartWidth),
data: visibleDateTextList.map(dateText => Math.abs(getNumber(getDailyItem(props.list, dateText)?.inQuantity)))
},
{
@@ -32,6 +32,7 @@ const MAX_TOOLTIP_CUSTOMER_COUNT = 24;
const statList = ref<CustomerDailyStatView[]>([]);
let statRequestId = 0;
const chartWidth = ref(window.innerWidth);
// ---------- 图表窗口 ----------
@@ -47,6 +48,18 @@ const {
const { restDaySet } = useRestDayCalendar(dateTextList);
const chartOption = computed<EChartsOption>(() => ({
...buildStoreBaseChartOption(visibleDateTextList.value),
xAxis: {
type: "category",
data: visibleDateTextList.value.map(item => item.slice(5)),
axisTick: {
show: true,
length: 0,
interval: 0
},
axisLabel: {
color: "#52607a"
}
},
grid: {
top: 48,
left: 0,
@@ -84,7 +97,6 @@ const chartOption = computed<EChartsOption>(() => ({
name: "客户总量",
type: "line",
yAxisIndex: 0,
markArea: buildRestDayMarkArea(visibleDateTextList.value, restDaySet.value, window.innerWidth - 32),
smooth: true,
showSymbol: false,
data: visibleDateTextList.value.map(dateText => getDailyStat(dateText)?.totalCustomerCount || 0)
@@ -93,6 +105,7 @@ const chartOption = computed<EChartsOption>(() => ({
name: "新客户量",
type: "bar",
yAxisIndex: 1,
markArea: buildRestDayMarkArea(visibleDateTextList.value, restDaySet.value, chartWidth.value),
data: visibleDateTextList.value.map(dateText => getDailyStat(dateText)?.newCustomerCount || 0)
}
],
@@ -104,6 +117,20 @@ const chartOption = computed<EChartsOption>(() => ({
}));
const { chartElement } = useStoreChart(chartOption);
let resizeObserver: ResizeObserver | undefined;
onMounted(() => {
resizeObserver = new window.ResizeObserver(updateChartWidth);
if (chartElement.value) {
resizeObserver.observe(chartElement.value);
updateChartWidth();
}
});
onBeforeUnmount(() => {
resizeObserver?.disconnect();
resizeObserver = undefined;
});
watch(() => props.dateTextList, async () => {
await loadCustomerDailyStat();
@@ -128,6 +155,10 @@ async function loadCustomerDailyStat(): Promise<void> {
}
}
function updateChartWidth(): void {
chartWidth.value = chartElement.value?.clientWidth || window.innerWidth;
}
function getDailyStat(dateText: string): CustomerDailyStatView | undefined {
const dateValue = Number(dateText.replaceAll("-", ""));
return statList.value.find(item => item.dateValue === dateValue);
@@ -1,3 +1,4 @@
import { onMounted, watch } from "vue";
import type { ComputedRef } from "vue";
import type { MarkAreaComponentOption } from "echarts";
import StoreChartAPI from "@/api/StoreChartAPI";
@@ -10,9 +11,9 @@ export function useRestDayCalendar(dateTextList: ComputedRef<string[]>) {
watch(dateTextList, async () => {
await loadRestDays();
}, {
deep: true,
immediate: true
}, { deep: true });
onMounted(async () => {
await loadRestDays();
});
async function loadRestDays(): Promise<void> {
@@ -51,17 +52,26 @@ export function buildRestDayMarkArea(
chartWidth: number
): MarkAreaComponentOption | undefined {
const data: NonNullable<MarkAreaComponentOption["data"]> = [];
let restDayBeginIndex = -1;
for (let dateIndex = 0; dateIndex < dateTextList.length; dateIndex++) {
const dateText = dateTextList[dateIndex];
if (dateText && restDaySet.has(getDateValue(dateText))) {
data.push([{ name: "休", xAxis: dateIndex }, { xAxis: dateIndex }]);
const isRestDay = Boolean(dateText && restDaySet.has(getDateValue(dateText)));
if (isRestDay && restDayBeginIndex < 0) {
restDayBeginIndex = dateIndex;
} else if (!isRestDay && 0 <= restDayBeginIndex) {
data.push([{ name: "休", xAxis: restDayBeginIndex }, { xAxis: dateIndex - 1 }]);
restDayBeginIndex = -1;
}
}
if (0 <= restDayBeginIndex) {
data.push([{ name: "休", xAxis: restDayBeginIndex }, { xAxis: dateTextList.length - 1 }]);
}
if (!data.length) {
return undefined;
}
return {
silent: true,
animation: false,
itemStyle: {
color: "rgba(148, 163, 184, .12)"
},