You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Chart.js实现多产品每日价格折线图的展示调整需求

React + Chart.js 产品每日价格折线图调整方案

1. 数据预处理(核心修正步骤)

原始数据集是按单条记录存储的产品日期价格数据,需先按产品名称分组,同时提取并排序所有日期(确保从旧到新):

// 假设传入组件的原始数据集为props.data
const groupedData = data.reduce((acc, item) => {
  if (!acc[item.product_name]) {
    acc[item.product_name] = [];
  }
  acc[item.product_name].push({
    date: item.date,
    whole_price: item.whole_price,
    retail_price: item.retail_price
  });
  return acc;
}, {});

// 提取唯一日期并按时间排序(旧→新)
const sortedDates = [...new Set(data.map(item => item.date))].sort((a, b) => new Date(a) - new Date(b));

2. 图表配置修正

X轴日期顺序控制

使用Chart.js的TimeScale轴保证日期按时间顺序展示,需引入适配库:

options: {
  scales: {
    x: {
      type: 'time',
      time: {
        unit: 'day',
        displayFormats: { day: 'yyyy-MM-dd' }
      },
      title: { display: true, text: '日期' }
    },
    y: {
      title: { display: true, text: '价格' },
      beginAtZero: false
    }
  },
  legend: {
    position: 'top',
    // 图例直接显示产品名称(对应数据集的label)
    labels: { usePointStyle: true }
  }
}

产品数据集生成

根据选中的价格类型,为每个产品生成对应的折线数据,缺失日期用null填充保证折线连续:

const generateDatasets = (priceType) => {
  return Object.entries(groupedData).map(([productName, prices], index) => {
    const dataPoints = sortedDates.map(date => {
      const match = prices.find(p => p.date === date);
      return match ? match[priceType] : null;
    });

    // 自定义产品配色(可按需扩展)
    const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF'];
    return {
      label: productName,
      data: dataPoints,
      borderColor: colors[index % colors.length],
      backgroundColor: `${colors[index % colors.length]}20`,
      fill: false,
      tension: 0.1
    };
  });
};

3. 批发/零售价切换功能

用React状态管理选中的价格类型,切换时自动更新图表数据:

const [selectedPriceType, setSelectedPriceType] = useState('whole_price');

// 切换按钮UI
<div style={{ marginBottom: '1rem' }}>
  <button 
    onClick={() => setSelectedPriceType('whole_price')}
    style={{ 
      padding: '0.5rem 1rem', marginRight: '0.5rem', border: 'none', borderRadius: '4px', cursor: 'pointer',
      backgroundColor: selectedPriceType === 'whole_price' ? '#36A2EB' : '#e0e0e0',
      color: selectedPriceType === 'whole_price' ? '#fff' : '#000'
    }}
  >
    批发价
  </button>
  <button 
    onClick={() => setSelectedPriceType('retail_price')}
    style={{ 
      padding: '0.5rem 1rem', border: 'none', borderRadius: '4px', cursor: 'pointer',
      backgroundColor: selectedPriceType === 'retail_price' ? '#FF6384' : '#e0e0e0',
      color: selectedPriceType === 'retail_price' ? '#fff' : '#000'
    }}
  >
    零售价
  </button>
</div>

4. 完整可运行组件代码

import React, { useState, useEffect } from 'react';
import { Line } from 'react-chartjs-2';
import { Chart as ChartJS, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, TimeScale } from 'chart.js';
import 'chartjs-adapter-date-fns'; // 时间轴适配依赖

// 注册Chart.js所需组件
ChartJS.register(LinearScale, PointElement, LineElement, Title, Tooltip, Legend, TimeScale);

const PriceChart = ({ data }) => {
  const [selectedPriceType, setSelectedPriceType] = useState('whole_price');
  const [chartData, setChartData] = useState({ datasets: [] });

  useEffect(() => {
    if (!data?.length) return;

    // 按产品分组数据
    const groupedData = data.reduce((acc, item) => {
      acc[item.product_name] ??= [];
      acc[item.product_name].push(item);
      return acc;
    }, {});

    // 排序日期
    const sortedDates = [...new Set(data.map(i => i.date))].sort((a, b) => new Date(a) - new Date(b));

    // 生成对应价格类型的数据集
    const datasets = Object.entries(groupedData).map(([name, prices], idx) => {
      const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF'];
      return {
        label: name,
        data: sortedDates.map(date => prices.find(p => p.date === date)?.[selectedPriceType] || null),
        borderColor: colors[idx % colors.length],
        backgroundColor: `${colors[idx % colors.length]}20`,
        fill: false,
        tension: 0.1
      };
    });

    setChartData({ labels: sortedDates, datasets });
  }, [data, selectedPriceType]);

  const chartOptions = {
    responsive: true,
    scales: {
      x: {
        type: 'time',
        time: { unit: 'day', displayFormats: { day: 'yyyy-MM-dd' } },
        title: { display: true, text: '日期' }
      },
      y: { title: { display: true, text: '价格' }, beginAtZero: false }
    },
    tooltip: { mode: 'index', intersect: false }
  };

  return (
    <div>
      <div style={{ marginBottom: '1rem' }}>
        <button 
          onClick={() => setSelectedPriceType('whole_price')}
          style={{ 
            padding: '0.5rem 1rem', marginRight: '0.5rem', border: 'none', borderRadius: '4px', cursor: 'pointer',
            backgroundColor: selectedPriceType === 'whole_price' ? '#36A2EB' : '#e0e0e0',
            color: selectedPriceType === 'whole_price' ? '#fff' : '#000'
          }}
        >
          批发价
        </button>
        <button 
          onClick={() => setSelectedPriceType('retail_price')}
          style={{ 
            padding: '0.5rem 1rem', border: 'none', borderRadius: '4px', cursor: 'pointer',
            backgroundColor: selectedPriceType === 'retail_price' ? '#FF6384' : '#e0e0e0',
            color: selectedPriceType === 'retail_price' ? '#fff' : '#000'
          }}
        >
          零售价
        </button>
      </div>
      <Line data={chartData} options={chartOptions} />
    </div>
  );
};

export default PriceChart;

依赖安装提示

确保安装必要依赖包:

npm install chart.js react-chartjs-2 chartjs-adapter-date-fns

内容的提问来源于stack exchange,提问作者bedrani sidali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:25:25