chore: initial commit

This commit is contained in:
hailin
2026-05-18 13:52:47 +08:00
commit 0753129afe
148 changed files with 14202 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
import { useRef, useEffect } from 'react';
import * as echarts from 'echarts';
import { ContentPage } from './ContentPage';
import type { BarChartCompareItem } from '../types/data';
interface ExportTaxBarProps {
title: string;
data: BarChartCompareItem[];
description?: string;
}
export const ExportTaxBar = ({ title, data = [], description }: ExportTaxBarProps) => {
const chartRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!chartRef.current) return;
const myChart = echarts.init(chartRef.current);
const option: echarts.EChartsOption = {
animation: false,
silent: true,
tooltip: {
show: false
},
legend: {
data: ['本机构', '全量客户'],
right: 10,
top: 0,
textStyle: { fontSize: 9, color: '#666' },
itemWidth: 10,
itemHeight: 10,
itemGap: 12
},
grid: {
top: 30,
bottom: 75,
left: 35,
right: 15,
containLabel: true
},
xAxis: {
type: 'category',
data: data.map(d => d.label),
axisLabel: {
fontSize: 8,
color: '#666',
interval: 0,
rotate: 0,
margin: 8,
formatter: (value: string) => {
if (value.includes('出口免抵退税额')) {
return value.replace('额', '额\n');
}
if (value.includes('出口退税额')) {
return value.replace('额', '额\n');
}
if (value.includes('关联企业数量')) {
return value.replace('数量', '数量\n');
}
return value;
}
},
axisLine: { lineStyle: { color: '#F0F0F0' } },
axisTick: { show: false }
},
yAxis: {
type: 'value',
min: 0,
max: 100,
interval: 20,
axisLabel: { fontSize: 9, color: '#666', formatter: '{value}%' },
axisLine: { show: false },
axisTick: { show: false },
splitLine: { show: true, lineStyle: { type: 'dashed', color: '#F0F0F0' } }
},
series: [
{
name: '本机构',
type: 'bar',
data: data.map(d => d.customerValue),
barGap: '10%',
barWidth: 22,
itemStyle: { color: '#45dad1', borderRadius: [2, 2, 0, 0] },
label: {
show: true,
position: 'top',
fontSize: 8,
color: '#666',
formatter: '{c}%'
}
},
{
name: '全量客户',
type: 'bar',
data: data.map(d => d.marketValue),
barGap: '10%',
barWidth: 22,
itemStyle: { color: '#40a9ff', borderRadius: [2, 2, 0, 0] },
label: {
show: true,
position: 'top',
fontSize: 8,
color: '#666',
formatter: '{c}%'
}
}
]
};
myChart.setOption(option);
const handleResize = () => myChart.resize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
myChart.dispose();
};
}, [data]);
return (
<div className="flex flex-col w-full break-inside-avoid">
<div className="subtitle-container mb-1">
<span className="blue-bar-subtitle h-[12px]"></span>
<h4 className="text-[16px] font-semibold text-[#333]">{title}</h4>
</div>
{description && (
<div className="bg-gray-50 border border-gray-200 rounded-md px-3 py-2 mb-2">
<p className="text-[10px] text-gray-600 leading-relaxed">{description}</p>
</div>
)}
<div className="relative w-full bg-white border-[0.5px] border-gray-100 rounded-lg p-2">
<div className="echarts-canvas-container relative w-full" style={{ height: '320px' }}>
<div ref={chartRef} className="echarts-inner w-full h-full" />
<img className="echarts-export-image absolute inset-0 w-full h-full object-contain hidden" />
</div>
</div>
</div>
);
};
interface Page06ExportTaxProps {
exportFreeTaxRebate: BarChartCompareItem[];
exportTaxRebate: BarChartCompareItem[];
chartDescriptions?: { exportFreeTaxRebate?: string; exportTaxRebate?: string };
}
export const Page06ExportTax = ({ exportFreeTaxRebate = [], exportTaxRebate = [], chartDescriptions }: Page06ExportTaxProps) => {
return (
<ContentPage pageNumber={6} hidePageNumber={true}>
<div className="flex flex-col space-y-8 -mx-[20px] px-[20px]">
<ExportTaxBar title="不同出口免抵退税金额企业分布" data={exportFreeTaxRebate} description={chartDescriptions?.exportFreeTaxRebate} />
<ExportTaxBar title="不同出口退税金额企业分布" data={exportTaxRebate} description={chartDescriptions?.exportTaxRebate} />
</div>
</ContentPage>
);
};