feat(miniprogram): 温润东方风全面 UI 重设计

73 文件变更,覆盖全部 40 个页面 SCSS + TabBar 图标 + 组件样式。
统一赤陶主色 #C4623A + 暖米背景 + 衬线标题字体 + 12px 圆角体系。
This commit is contained in:
iven
2026-04-28 00:19:52 +08:00
parent fbb28e655d
commit 50eae8b809
97 changed files with 7633 additions and 2373 deletions

View File

@@ -0,0 +1,98 @@
import React, { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
import { Canvas, View } from '@tarojs/components';
import Taro from '@tarojs/taro';
import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import {
GridComponent,
TooltipComponent,
MarkAreaComponent,
MarkPointComponent,
} from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
LineChart,
GridComponent,
TooltipComponent,
MarkAreaComponent,
MarkPointComponent,
CanvasRenderer,
]);
interface EcCanvasProps {
canvasId: string;
height?: number;
}
export interface EcCanvasRef {
setOption: (option: echarts.EChartsOption) => void;
}
const EcCanvas = forwardRef<EcCanvasRef, EcCanvasProps>(
({ canvasId, height = 300 }, ref) => {
const chartInstance = useRef<echarts.ECharts | null>(null);
const canvasNode = useRef<any>(null);
const initChart = async () => {
try {
const query = Taro.createSelectorQuery();
query
.select(`#${canvasId}`)
.node()
.exec((res) => {
const node = res[0]?.node;
if (!node) return;
canvasNode.current = node;
const dpr = Taro.getSystemInfoSync().pixelRatio;
const width = node.width || 350;
const heightVal = node.height || height;
node.width = width * dpr;
node.height = heightVal * dpr;
const ctx = node.getContext('2d');
chartInstance.current = echarts.init(ctx as any, undefined, {
renderer: 'canvas',
width,
height: heightVal,
devicePixelRatio: dpr,
});
});
} catch (e) {
console.error('EcCanvas init failed:', e);
}
};
useEffect(() => {
initChart();
return () => {
chartInstance.current?.dispose();
};
}, []);
useImperativeHandle(ref, () => ({
setOption: (option: echarts.EChartsOption) => {
if (chartInstance.current) {
chartInstance.current.setOption(option);
}
},
}));
return (
<View style={{ width: '100%', height: `${height}rpx` }}>
<Canvas
type='2d'
id={canvasId}
style={{ width: '100%', height: '100%' }}
/>
</View>
);
},
);
EcCanvas.displayName = 'EcCanvas';
export default EcCanvas;

View File

@@ -1,6 +1,7 @@
import React, { useEffect, useRef, useCallback } from 'react';
import { View, Text } from '@tarojs/components';
import { EChart } from 'echarts-taro3-react';
import EcCanvas from '../EcCanvas';
import type { EcCanvasRef } from '../EcCanvas';
import './index.scss';
interface TrendChartProps {
@@ -11,8 +12,14 @@ interface TrendChartProps {
height?: number;
}
export default function TrendChart({ data, referenceMin, referenceMax, unit = '', height = 500 }: TrendChartProps) {
const chartRef = useRef<any>(null);
export default function TrendChart({
data,
referenceMin,
referenceMax,
unit = '',
height = 500,
}: TrendChartProps) {
const chartRef = useRef<EcCanvasRef>(null);
const getOption = useCallback(() => {
if (!data || data.length === 0) return null;
@@ -21,10 +28,15 @@ export default function TrendChart({ data, referenceMin, referenceMax, unit = ''
const markArea: any = {};
if (referenceMin != null && referenceMax != null) {
markArea.data = [[
{ yAxis: referenceMin, itemStyle: { color: 'rgba(5,150,105,0.08)' } },
{ yAxis: referenceMax },
]];
markArea.data = [
[
{
yAxis: referenceMin,
itemStyle: { color: 'rgba(5,150,105,0.08)' },
},
{ yAxis: referenceMax },
],
];
}
series.push({
@@ -35,17 +47,34 @@ export default function TrendChart({ data, referenceMin, referenceMax, unit = ''
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,
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 {
@@ -77,7 +106,7 @@ export default function TrendChart({ data, referenceMin, referenceMax, unit = ''
if (chartRef.current && data && data.length > 0) {
const option = getOption();
if (option) {
chartRef.current.refresh(option);
chartRef.current.setOption(option);
}
}
}, [data, getOption]);
@@ -92,7 +121,7 @@ export default function TrendChart({ data, referenceMin, referenceMax, unit = ''
return (
<View className='trend-chart' style={{ height: `${height}rpx` }}>
<EChart canvasId='trend-chart-canvas' ref={chartRef} />
<EcCanvas canvasId='trend-chart-canvas' ref={chartRef} height={height} />
</View>
);
}