add asset trends in statistics & analysis (#314)
This commit is contained in:
@@ -263,7 +263,7 @@ function onLegendSelectChanged(e: { selected: Record<string, boolean> }): void {
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.pie-chart-container {
|
||||
height: 610px;
|
||||
height: 650px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ const chartOptions = computed<object>(() => {
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.radar-chart-container {
|
||||
height: 610px;
|
||||
height: 650px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+100
-44
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-chart autoresize class="monthly-trends-chart-container" :class="{ 'transition-in': skeleton }" :option="chartOptions"
|
||||
<v-chart autoresize class="trends-chart-container" :class="{ 'transition-in': skeleton }" :option="chartOptions"
|
||||
@click="clickItem" @legendselectchanged="onLegendSelectChanged" />
|
||||
</template>
|
||||
|
||||
@@ -10,20 +10,33 @@ import type { ECElementEvent } from 'echarts/core';
|
||||
import type { CallbackDataParams } from 'echarts/types/dist/shared';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
import { type CommonMonthlyTrendsChartProps, type MonthlyTrendsBarChartClickEvent, useMonthlyTrendsChartBase } from '@/components/base/MonthlyTrendsChartBase.ts'
|
||||
import {
|
||||
type TrendsChartDateType,
|
||||
type CommonTrendsChartProps,
|
||||
type TrendsBarChartClickEvent,
|
||||
useTrendsChartBase
|
||||
} from '@/components/base/TrendsChartBase.ts'
|
||||
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import { itemAndIndex } from '@/core/base.ts';
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
import { type Year1BasedMonth, DateRangeScene } from '@/core/datetime.ts';
|
||||
import {
|
||||
type Year1BasedMonth,
|
||||
type YearMonthDay,
|
||||
DateRangeScene
|
||||
} from '@/core/datetime.ts';
|
||||
import type { ColorStyleValue } from '@/core/color.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { TrendChartType, ChartDateAggregationType } from '@/core/statistics.ts';
|
||||
import {
|
||||
ChartDataAggregationType,
|
||||
TrendChartType,
|
||||
ChartDateAggregationType
|
||||
} from '@/core/statistics.ts';
|
||||
|
||||
import { DEFAULT_CHART_COLORS } from '@/consts/color.ts';
|
||||
|
||||
import type { YearMonthDataItem, SortableTransactionStatisticDataItem } from '@/models/transaction.ts';
|
||||
import type { SortableTransactionStatisticDataItem } from '@/models/transaction.ts';
|
||||
|
||||
import {
|
||||
isArray,
|
||||
@@ -42,14 +55,14 @@ import {
|
||||
sortStatisticsItems
|
||||
} from '@/lib/statistics.ts';
|
||||
|
||||
interface DesktopMonthlyTrendsChartProps<T extends Year1BasedMonth> extends CommonMonthlyTrendsChartProps<T> {
|
||||
interface DesktopTrendsChartProps<T extends TrendsChartDateType> extends CommonTrendsChartProps<T> {
|
||||
skeleton?: boolean;
|
||||
type?: number;
|
||||
showValue?: boolean;
|
||||
showTotalAmountInTooltip?: boolean;
|
||||
}
|
||||
|
||||
interface MonthlyTrendsChartDataItem {
|
||||
interface TrendsChartDataItem {
|
||||
id: string;
|
||||
name: string;
|
||||
itemStyle: {
|
||||
@@ -64,17 +77,17 @@ interface MonthlyTrendsChartDataItem {
|
||||
data: number[];
|
||||
}
|
||||
|
||||
interface MonthlyTrendsChartTooltipItem extends SortableTransactionStatisticDataItem {
|
||||
interface TrendsChartTooltipItem extends SortableTransactionStatisticDataItem {
|
||||
readonly name: string;
|
||||
readonly color: unknown;
|
||||
readonly displayOrders: number[];
|
||||
readonly totalAmount: number;
|
||||
}
|
||||
|
||||
const props = defineProps<DesktopMonthlyTrendsChartProps<YearMonthDataItem>>();
|
||||
const props = defineProps<DesktopTrendsChartProps<TrendsChartDateType>>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'click', value: MonthlyTrendsBarChartClickEvent): void;
|
||||
(e: 'click', value: TrendsBarChartClickEvent): void;
|
||||
}>();
|
||||
|
||||
const theme = useTheme();
|
||||
@@ -82,6 +95,7 @@ const theme = useTheme();
|
||||
const {
|
||||
tt,
|
||||
getCurrentLanguageTextDirection,
|
||||
formatUnixTimeToShortDate,
|
||||
formatUnixTimeToGregorianLikeShortYear,
|
||||
formatUnixTimeToGregorianLikeShortYearMonth,
|
||||
formatYearQuarterToGregorianLikeYearQuarter,
|
||||
@@ -90,7 +104,7 @@ const {
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const { allDateRanges, getItemName } = useMonthlyTrendsChartBase(props);
|
||||
const { allDateRanges, getItemName } = useTrendsChartBase(props);
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -143,16 +157,18 @@ const allDisplayDateRanges = computed<string[]>(() => {
|
||||
allDisplayDateRanges.push(formatUnixTimeToGregorianLikeFiscalYear(dateRange.minUnixTime));
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type && 'quarter' in dateRange) {
|
||||
allDisplayDateRanges.push(formatYearQuarterToGregorianLikeYearQuarter(dateRange.year, dateRange.quarter));
|
||||
} else { // if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||
allDisplayDateRanges.push(formatUnixTimeToGregorianLikeShortYearMonth(dateRange.minUnixTime));
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type && props.chartMode === 'daily') {
|
||||
allDisplayDateRanges.push(formatUnixTimeToShortDate(dateRange.minUnixTime));
|
||||
}
|
||||
}
|
||||
|
||||
return allDisplayDateRanges;
|
||||
});
|
||||
|
||||
const allSeries = computed<MonthlyTrendsChartDataItem[]>(() => {
|
||||
const allSeries: MonthlyTrendsChartDataItem[] = [];
|
||||
const allSeries = computed<TrendsChartDataItem[]>(() => {
|
||||
const allSeries: TrendsChartDataItem[] = [];
|
||||
let maxAmount: number = 0;
|
||||
|
||||
for (const [item, index] of itemAndIndex(props.items)) {
|
||||
@@ -161,23 +177,41 @@ const allSeries = computed<MonthlyTrendsChartDataItem[]>(() => {
|
||||
}
|
||||
|
||||
const allAmounts: number[] = [];
|
||||
const dateRangeAmountMap: Record<string, YearMonthDataItem[]> = {};
|
||||
const dateRangeAmountMap: Record<string, (Year1BasedMonth | YearMonthDay)[]> = {};
|
||||
|
||||
for (const dataItem of item.items) {
|
||||
let dateRangeKey = '';
|
||||
|
||||
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
||||
dateRangeKey = dataItem.year.toString();
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type) {
|
||||
const fiscalYear = getFiscalYearFromUnixTime(
|
||||
getYearMonthFirstUnixTime({ year: dataItem.year, month1base: dataItem.month1base }),
|
||||
props.fiscalYearStart
|
||||
);
|
||||
dateRangeKey = fiscalYear.toString();
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type) {
|
||||
dateRangeKey = `${dataItem.year}-${Math.floor((dataItem.month1base - 1) / 3) + 1}`;
|
||||
} else { // if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||
dateRangeKey = `${dataItem.year}-${dataItem.month1base}`;
|
||||
if (props.chartMode === 'daily' && 'month' in dataItem) {
|
||||
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
||||
dateRangeKey = dataItem.year.toString();
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type) {
|
||||
const fiscalYear = getFiscalYearFromUnixTime(
|
||||
getYearMonthFirstUnixTime({ year: dataItem.year, month1base: dataItem.month }),
|
||||
props.fiscalYearStart
|
||||
);
|
||||
dateRangeKey = fiscalYear.toString();
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type) {
|
||||
dateRangeKey = `${dataItem.year}-${Math.floor((dataItem.month - 1) / 3) + 1}`;
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||
dateRangeKey = `${dataItem.year}-${dataItem.month}`;
|
||||
} else { // if (props.dateAggregationType === ChartDateAggregationType.Day.type) {
|
||||
dateRangeKey = `${dataItem.year}-${dataItem.month}-${dataItem.day}`;
|
||||
}
|
||||
} else if (props.chartMode === 'monthly' && 'month1base' in dataItem) {
|
||||
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
||||
dateRangeKey = dataItem.year.toString();
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type) {
|
||||
const fiscalYear = getFiscalYearFromUnixTime(
|
||||
getYearMonthFirstUnixTime({ year: dataItem.year, month1base: dataItem.month1base }),
|
||||
props.fiscalYearStart
|
||||
);
|
||||
dateRangeKey = fiscalYear.toString();
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type) {
|
||||
dateRangeKey = `${dataItem.year}-${Math.floor((dataItem.month1base - 1) / 3) + 1}`;
|
||||
} else { // if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||
dateRangeKey = `${dataItem.year}-${dataItem.month1base}`;
|
||||
}
|
||||
}
|
||||
|
||||
const dataItems = dateRangeAmountMap[dateRangeKey] || [];
|
||||
@@ -197,6 +231,8 @@ const allSeries = computed<MonthlyTrendsChartDataItem[]>(() => {
|
||||
dateRangeKey = `${dateRange.year}-${dateRange.quarter}`;
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type && 'month0base' in dateRange) {
|
||||
dateRangeKey = `${dateRange.year}-${dateRange.month0base + 1}`;
|
||||
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type && 'day' in dateRange && props.chartMode === 'daily') {
|
||||
dateRangeKey = `${dateRange.year}-${dateRange.month}-${dateRange.day}`;
|
||||
}
|
||||
|
||||
let amount = 0;
|
||||
@@ -204,8 +240,14 @@ const allSeries = computed<MonthlyTrendsChartDataItem[]>(() => {
|
||||
|
||||
if (isArray(dataItems)) {
|
||||
for (const dataItem of dataItems) {
|
||||
if (isNumber(dataItem[props.valueField])) {
|
||||
amount += dataItem[props.valueField] as number;
|
||||
const value = (dataItem as unknown as Record<string, unknown>)[props.valueField];
|
||||
|
||||
if (isNumber(value)) {
|
||||
if (props.dataAggregationType === ChartDataAggregationType.Sum) {
|
||||
amount += value;
|
||||
} else if (props.dataAggregationType === ChartDataAggregationType.Last) {
|
||||
amount = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,7 +259,7 @@ const allSeries = computed<MonthlyTrendsChartDataItem[]>(() => {
|
||||
allAmounts.push(amount);
|
||||
}
|
||||
|
||||
const finalItem: MonthlyTrendsChartDataItem = {
|
||||
const finalItem: TrendsChartDataItem = {
|
||||
id: (props.idField && item[props.idField]) ? item[props.idField] as string : getItemName(item[props.nameField] as string),
|
||||
name: (props.idField && item[props.idField]) ? item[props.idField] as string : getItemName(item[props.nameField] as string),
|
||||
itemStyle: {
|
||||
@@ -317,7 +359,7 @@ const chartOptions = computed<object>(() => {
|
||||
let tooltip = '';
|
||||
let totalAmount = 0;
|
||||
let actualDisplayItemCount = 0;
|
||||
const displayItems: MonthlyTrendsChartTooltipItem[] = [];
|
||||
const displayItems: TrendsChartTooltipItem[] = [];
|
||||
|
||||
for (const param of params) {
|
||||
const id = param.seriesId as string;
|
||||
@@ -435,19 +477,33 @@ function clickItem(e: ECElementEvent): void {
|
||||
let minUnixTime = dateRange.minUnixTime;
|
||||
let maxUnixTime = dateRange.maxUnixTime;
|
||||
|
||||
if (props.startYearMonth) {
|
||||
const startMinUnixTime = getYearMonthFirstUnixTime(props.startYearMonth);
|
||||
|
||||
if (startMinUnixTime > minUnixTime) {
|
||||
minUnixTime = startMinUnixTime;
|
||||
if (props.chartMode === 'daily') {
|
||||
if (props.startTime) {
|
||||
if (props.startTime > minUnixTime) {
|
||||
minUnixTime = props.startTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (props.endYearMonth) {
|
||||
const endMaxUnixTime = getYearMonthLastUnixTime(props.endYearMonth);
|
||||
if (props.endTime) {
|
||||
if (props.endTime < maxUnixTime) {
|
||||
maxUnixTime = props.endTime;
|
||||
}
|
||||
}
|
||||
} else if (props.chartMode === 'monthly') {
|
||||
if (props.startYearMonth) {
|
||||
const startMinUnixTime = getYearMonthFirstUnixTime(props.startYearMonth);
|
||||
|
||||
if (endMaxUnixTime < maxUnixTime) {
|
||||
maxUnixTime = endMaxUnixTime;
|
||||
if (startMinUnixTime > minUnixTime) {
|
||||
minUnixTime = startMinUnixTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (props.endYearMonth) {
|
||||
const endMaxUnixTime = getYearMonthLastUnixTime(props.endYearMonth);
|
||||
|
||||
if (endMaxUnixTime < maxUnixTime) {
|
||||
maxUnixTime = endMaxUnixTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,15 +554,15 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.monthly-trends-chart-container {
|
||||
.trends-chart-container {
|
||||
width: 100%;
|
||||
height: 720px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.monthly-trends-chart-container {
|
||||
height: 760px;
|
||||
.trends-chart-container {
|
||||
height: 790px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user