feat(health): 新增 TrendChart ECharts 折线图组件
This commit is contained in:
17
apps/miniprogram/src/components/TrendChart/index.scss
Normal file
17
apps/miniprogram/src/components/TrendChart/index.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
@import '../../styles/variables.scss';
|
||||
|
||||
.trend-chart {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.trend-chart-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 500rpx;
|
||||
}
|
||||
|
||||
.trend-chart-empty-text {
|
||||
font-size: 28px;
|
||||
color: $tx3;
|
||||
}
|
||||
98
apps/miniprogram/src/components/TrendChart/index.tsx
Normal file
98
apps/miniprogram/src/components/TrendChart/index.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import React, { useEffect, useRef, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import { EChart } from 'echarts-taro3-react';
|
||||
import './index.scss';
|
||||
|
||||
interface TrendChartProps {
|
||||
data: { date: string; value: number }[];
|
||||
referenceMin?: number;
|
||||
referenceMax?: number;
|
||||
unit?: string;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
export default function TrendChart({ data, referenceMin, referenceMax, unit = '', height = 500 }: TrendChartProps) {
|
||||
const chartRef = useRef<any>(null);
|
||||
|
||||
const getOption = useCallback(() => {
|
||||
if (!data || data.length === 0) return null;
|
||||
|
||||
const series: any[] = [];
|
||||
const markArea: any = {};
|
||||
|
||||
if (referenceMin != null && referenceMax != null) {
|
||||
markArea.data = [[
|
||||
{ yAxis: referenceMin, itemStyle: { color: 'rgba(5,150,105,0.08)' } },
|
||||
{ yAxis: referenceMax },
|
||||
]];
|
||||
}
|
||||
|
||||
series.push({
|
||||
type: 'line',
|
||||
data: data.map((d) => d.value),
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: '#0891B2', width: 2 },
|
||||
itemStyle: { color: '#0891B2' },
|
||||
areaStyle: { color: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: 'rgba(8,145,178,0.15)' }, { offset: 1, color: 'rgba(8,145,178,0.01)' }] } },
|
||||
markArea: markArea.data ? { silent: true, data: markArea.data } : undefined,
|
||||
markPoint: (referenceMin != null && referenceMax != null) ? {
|
||||
data: data
|
||||
.filter((d) => d.value < referenceMin || d.value > referenceMax)
|
||||
.map((d) => ({
|
||||
coord: [data.indexOf(d), d.value],
|
||||
itemStyle: { color: '#DC2626' },
|
||||
symbolSize: 12,
|
||||
})),
|
||||
} : undefined,
|
||||
});
|
||||
|
||||
return {
|
||||
grid: { left: 45, right: 15, top: 20, bottom: 30 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: data.map((d) => d.date.slice(5)),
|
||||
axisLabel: { fontSize: 10, color: '#94A3B8' },
|
||||
axisLine: { lineStyle: { color: '#E5E7EB' } },
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { fontSize: 10, color: '#94A3B8' },
|
||||
splitLine: { lineStyle: { color: '#F3F4F6' } },
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (params: any) => {
|
||||
const p = params[0];
|
||||
const idx = p.dataIndex;
|
||||
return `${data[idx]?.date || ''}\n${p.value}${unit ? ' ' + unit : ''}`;
|
||||
},
|
||||
},
|
||||
series,
|
||||
};
|
||||
}, [data, referenceMin, referenceMax, unit]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chartRef.current && data && data.length > 0) {
|
||||
const option = getOption();
|
||||
if (option) {
|
||||
chartRef.current.refresh(option);
|
||||
}
|
||||
}
|
||||
}, [data, getOption]);
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
return (
|
||||
<View className='trend-chart-empty'>
|
||||
<Text className='trend-chart-empty-text'>暂无数据</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View className='trend-chart' style={{ height: `${height}rpx` }}>
|
||||
<EChart canvasId='trend-chart-canvas' ref={chartRef} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user