Wygeneruj dane do wykresu słupkowego ładowania, za pomocą listy DTO

0

Pytanie

Mam ten obiekt DTO, stworzony z Rest API za pomocą Typescript:

export interface BillingSummaryDTO {
    paid?: number,
    outstanding?: number,
    pastDue?: number,
    cancelled?: number,
    createdAt?: Moment | null,
}

export async function getBillingSummary(): Promise<AxiosResponse<BillingSummaryDTO[]>> {
  return await axios.get<BillingSummaryDTO[]>(
      `${baseUrl}/management/billing/summary`
  );
}

Przykład wykresu:

import {
  BarChart,
  Bar,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  Legend,
} from "recharts";
import {Box} from "@material-ui/core";

const data = [
  {
    name: "Jan",
    Chargebacks: 4000,
    Transactions: 2400,
    USD: 2400,
  },
  {
    name: "Feb",
    Chargebacks: 3000,
    Transactions: 1398,
    USD: 2210,
  },
  {
    name: "Mar",
    Chargebacks: 2000,
    Transactions: 9800,
    USD: 2290,
  },
  {
    name: "Apr",
    Chargebacks: 2780,
    Transactions: 3908,
    USD: 2000,
  },
  {
    name: "May",
    Chargebacks: 1890,
    Transactions: 4800,
    USD: 2181,
  },
  {
    name: "Jun",
    Chargebacks: 2390,
    Transactions: 3800,
    USD: 2500,
  },
  {
    name: "Jul",
    Chargebacks: 3490,
    Transactions: 4300,
    USD: 2100,
  },
  {
    name: "Aug",
    Chargebacks: 3490,
    Transactions: 4300,
    USD: 2100,
  },
  {
    name: "Sep",
    Chargebacks: 3490,
    Transactions: 4300,
    USD: 2100,
  },
];

const useStyles = makeStyles((theme) =>
  createStyles({
    root: {
      flexGrow: 1,
    },
    paper: {
      padding: theme.spacing(2),
      textAlign: "center",
      color: theme.palette.text.secondary,
    },
  })
);

const usePaperStyles = makeStyles((theme) =>
  createStyles({
    root: {
      display: "flex",
      flexWrap: "wrap",
      "& > *": {
        margin: theme.spacing(1),
        width: theme.spacing(16),
        height: theme.spacing(16),
      },
    },
  })
);

const useTimelineStyles = makeStyles((theme) => ({
  paper: {
    padding: "6px 16px",
  },
  secondaryTail: {
    backgroundColor: theme.palette.secondary.main,
  },
}));

export default function Billing() {
  const [click, setClick] = useState(false);
  const closeMobileMenu = () => setClick(false);
  const classes = useStyles();
  const classesPaper = usePaperStyles();
  const classesTimeline = useTimelineStyles();

  return (
    <>
      <Grid container justifyContent="center" alignItems="center">
        <Grid item xs={11}>
          {/*Padding on the top*/}
          <Box m="5rem" />
        </Grid>

        <Grid item xs={12} >
          <h4 className="chart-label">Invoices Summary</h4>
          <BarChart
            width={1000}
            height={300}
            data={data}
            margin={{
              top: 5,
              right: 30,
              left: 20,
              bottom: 5,
            }}
            barSize={30}
          >
            <XAxis
              dataKey="name"
              scale="point"
              padding={{ left: 10, right: 10 }}
            />
            <YAxis />
            <Tooltip />
            <Legend />
            <CartesianGrid strokeDasharray="3 3" />
            <Bar
              dataKey="Transactions"
              fill="#8884d8"
              background={{ fill: "#eee" }}
            />
          </BarChart>
        </Grid>
      </Grid>
    </>
  );
}

Jak mogę wykorzystać dane z BillingSummaryDTO[] aby wygenerować wykres?

1

Najlepsza odpowiedź

2

Tworzenie funkcji, która koreluje BillingSummaryDTO[] i przekształca ją w modelu danych (jak widać w zmiennej data) , które podałeś do spożycia <BarChart/> jest to właściwe podejście.

export interface BarChartDataModel {
  name: string,
  Chargebacks: number,
  Transactions: number,
  USD: number,
}

const data : BarChartDataModel []

Dane te będą wykorzystywane w <BarChart/> jak


<BarChart
            data={data}
            // ....
          >
         // ...
 </BarChart>

Taka funkcja będzie map reduce podchodźcie z niewielką pomocą z biblioteki zarządzania datami JS, takie jak momentjs

4-шаговое rozwiązanie

  1. Umieść wszystkie rachunki w kolejności (najpierw najstarsze konto) w celu ułatwienia wyświetlania-zmniejsz później
  2. Rachunki za wiadra na lata w wiadra, zwane "wiadrami na lata"
  3. Rachunki za wiadro w każdym rocznym wiadra do wiadra, zwane "miesięcznym wiadrem".
  4. Zmniejsz wszystkie rachunki w każdym comiesięcznym wiadrze do obiektu, następującego po BarChartDataModel interfejs. Kolekcja obiektów, takich za BarChartDataModel interfejs to data przechodzimy do naszego <BarChart/> składnik
  5. Użyj tej kolekcji obiektów w naszym <BarChart/> składnik

Twój kod będzie :

export interface BillingSummaryDTO {
    paid?: number,
    outstanding?: number,
    pastDue?: number,
    cancelled?: number,
    createdAt?: Moment | null,
}

export interface BarChartDataModel {
  name: string,
  Chargebacks: number,
  Transactions: number,
  USD: number,
}

export async function getBillingSummary(): Promise<AxiosResponse<BillingSummaryDTO[]>> {
  const response = await axios.get<BillingSummaryDTO[]>(
      `${baseUrl}/management/billing/summary`
  );
  // STEP 1 : Chronological ordering. Oldest bills will show first
  const chronologicallyOrdered = response.sort((a:BillingSummaryDTO,b:BillingSummaryDTO)=> a.createdAt - b.createdAt )

  // STEP 2 : Bucket by year
  const groupByYear = chronologicallyOrdered.reduce((yearwiseBills : any, bill:BillingSummaryDTO, currIdx:number)) => 
     {
        const year = moment(bill.createdAt).year().toString()
        if(!yearwiseBills[year]){ 
          yearwiseBills[year] = []
        } 
        yearwiseBills[year].push(bill)
        return yearwiseBills
     }
  ,{})

  // STEP 3 : In each yearwise bucket -> bucket by month
  const groupByMonth = Object.keys(groupByYear).map((year, yearwiseBills) => yearwiseBills.reduce((monthwiseBills: any, bill:BillingSummaryDTO, currIdx:number)) => 
     {
        const moment = moment(bill.createdAt).month().toString()
        if(!yearAcc[month]){ 
          monthwiseBills[month] = []
        } 
        monthwiseBills[month].push(bill)
        return monthwiseBills
     }
  ,{}) );

 // STEP 4 : Reduce all bills in a monthwise bucket into a monthlyReport object and store all monthlyReport objects in an monthlyReportArray
 const monthlyReportArray:BarChartDataModel[] = Object.keys(groupByMonth).map((year, yearwiseBills) => 
   Object.keys(bills).map((month, monthwiseBills) => monthwiseBills.reduce((monthlyReport:BarChartDataModel,bill:BillingSummaryDTO) => {
    if(bill.cancelled){
      monthlyReport.Chargebacks++
    }else{
      monthlyReport.Transactions++,
      monthlyReport.USD += bill.paid
    }
    return monthlyReport
  },{
    name : moment(month, 'M').format('MMM')
    Transactions : 0,
    USD : 0,
    Chargebacks:0
   } )
 )


 // STEP 5 : Consume this as the "data" for the "<BarChart/>" component
 return monthlyReportArray
}
 

Najpierw nagrałem na lata, a następnie przez miesiąc, zamiast bezpośrednio nagrywać przez miesiąc, bo nie chcemy połączyć raporty miesięczne, powiedzmy, "maj 1997 roku" i "Maja 1998 roku", tylko w "Maj" dla naszego grafika. Chcielibyśmy, aby były one odrębnymi

2021-11-24 05:49:15

Dostaję wiele błędów. Jesteś pewien, że to powinno być prawidłowe rozwiązanie?
Peter Penzov

Czy mógłby pan podzielić się swoimi błędami. Metoda redukcji mapy idealny, więc logika pozostaje taka sama. Mogą wystąpić problemy ze składnią (w zasadzie błąd sprawdzania typu).
Ankit Sanghvi

W innych językach

Ta strona jest w innych językach

Русский
..................................................................................................................
Italiano
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................