修复了豆瓣读书

This commit is contained in:
lsy 2025-03-27 21:40:41 +08:00
parent 1700c1bc44
commit 1cff530f8a
2 changed files with 214 additions and 33 deletions

View File

@ -9,11 +9,22 @@ interface WorldHeatmapProps {
const WorldHeatmap: React.FC<WorldHeatmapProps> = ({ visitedPlaces }) => {
const chartRef = useRef<HTMLDivElement>(null);
const chartInstanceRef = useRef<echarts.ECharts | null>(null);
useEffect(() => {
if (!chartRef.current) return;
const chart = echarts.init(chartRef.current);
// 确保之前的实例被正确销毁
if (chartInstanceRef.current) {
chartInstanceRef.current.dispose();
}
// 初始化图表并保存实例引用
const chart = echarts.init(chartRef.current, null, {
renderer: 'canvas',
useDirtyRect: false
});
chartInstanceRef.current = chart;
const mergedWorldData = {
...worldData,
@ -41,17 +52,44 @@ const WorldHeatmap: React.FC<WorldHeatmapProps> = ({ visitedPlaces }) => {
echarts.registerMap('merged-world', mergedWorldData as any);
// 检查当前是否为暗色模式
const isDarkMode = document.documentElement.classList.contains('dark');
// 根据当前模式设置颜色
const getChartColors = () => {
return {
textColor: isDarkMode ? '#ffffff' : '#374151',
borderColor: isDarkMode ? '#374151' : '#e5e7eb',
unvisitedColor: isDarkMode ? '#1f2937' : '#e5e7eb',
visitedColor: isDarkMode ? '#059669' : '#10b981',
emphasisColor: isDarkMode ? '#059669' : '#10b981',
tooltipBgColor: isDarkMode ? '#111827' : '#ffffff',
};
};
const colors = getChartColors();
// 使用动态颜色方案
const option = {
title: {
text: '我的旅行足迹',
left: 'center',
top: 20
top: 20,
textStyle: {
color: colors.textColor,
fontWeight: 'bold'
}
},
tooltip: {
trigger: 'item',
formatter: ({name}: {name: string}) => {
const visited = visitedPlaces.includes(name);
return `${name}<br/>${visited ? '✓ 已去过' : '尚未去过'}`;
},
backgroundColor: colors.tooltipBgColor,
borderColor: colors.borderColor,
textStyle: {
color: colors.textColor
}
},
visualMap: {
@ -62,13 +100,14 @@ const WorldHeatmap: React.FC<WorldHeatmapProps> = ({ visitedPlaces }) => {
{ value: 0, label: '未去过' }
],
inRange: {
color: ['#e0e0e0', '#91cc75']
color: [colors.unvisitedColor, colors.visitedColor]
},
outOfRange: {
color: ['#e0e0e0']
color: [colors.unvisitedColor]
},
textStyle: {
color: '#333'
color: colors.textColor,
fontWeight: 500
}
},
series: [{
@ -78,12 +117,18 @@ const WorldHeatmap: React.FC<WorldHeatmapProps> = ({ visitedPlaces }) => {
roam: true,
emphasis: {
label: {
show: true
show: true,
color: colors.textColor
},
itemStyle: {
areaColor: '#91cc75'
areaColor: colors.emphasisColor
}
},
itemStyle: {
borderColor: colors.borderColor,
borderWidth: 1,
borderType: 'solid'
},
data: mergedWorldData.features.map((feature: any) => ({
name: feature.properties.name,
value: visitedPlaces.includes(feature.properties.name) ? 1 : 0
@ -94,19 +139,101 @@ const WorldHeatmap: React.FC<WorldHeatmapProps> = ({ visitedPlaces }) => {
chart.setOption(option);
window.addEventListener('resize', () => {
// 确保图表初始化后立即调整大小以适应容器
chart.resize();
const handleResize = () => {
if (chartInstanceRef.current) {
chartInstanceRef.current.resize();
}
};
window.addEventListener('resize', handleResize);
// 监听暗色模式变化并更新图表
const darkModeObserver = new MutationObserver(() => {
if (!chartRef.current) return;
// 检查当前是否为暗色模式
const newIsDarkMode = document.documentElement.classList.contains('dark');
if (chartInstanceRef.current) {
// 更新颜色设置
const newColors = {
textColor: newIsDarkMode ? '#ffffff' : '#374151',
borderColor: newIsDarkMode ? '#4b5563' : '#d1d5db',
unvisitedColor: newIsDarkMode ? '#1f2937' : '#e5e7eb',
visitedColor: newIsDarkMode ? '#059669' : '#10b981',
emphasisColor: newIsDarkMode ? '#059669' : '#10b981',
tooltipBgColor: newIsDarkMode ? '#111827' : '#ffffff',
};
// 更新图表选项
const newOption = {
title: {
textStyle: {
color: newColors.textColor
}
},
tooltip: {
backgroundColor: newColors.tooltipBgColor,
borderColor: newColors.borderColor,
textStyle: {
color: newColors.textColor
}
},
visualMap: {
inRange: {
color: [newColors.unvisitedColor, newColors.visitedColor]
},
outOfRange: {
color: [newColors.unvisitedColor]
},
textStyle: {
color: newColors.textColor
}
},
series: [{
emphasis: {
label: {
show: true,
color: newColors.textColor
},
itemStyle: {
areaColor: newColors.emphasisColor
}
},
itemStyle: {
borderColor: newColors.borderColor,
borderWidth: 1,
borderType: 'solid'
}
}]
};
// 应用新选项
chartInstanceRef.current.setOption(newOption);
}
});
darkModeObserver.observe(document.documentElement, { attributes: true });
return () => {
chart.dispose();
window.removeEventListener('resize', () => {
chart.resize();
});
if (chartInstanceRef.current) {
chartInstanceRef.current.dispose();
chartInstanceRef.current = null;
}
window.removeEventListener('resize', handleResize);
darkModeObserver.disconnect();
};
}, [visitedPlaces]);
return <div ref={chartRef} style={{ width: '100%', height: '600px' }} />;
return (
<div
ref={chartRef}
className="w-full h-[600px] md:h-[500px] lg:h-[600px] xl:h-[700px] dark:[&_.echarts-tooltip]:bg-[#111827] dark:[&_.echarts-tooltip]:border-[#374151] dark:[&_.echarts-tooltip]:text-white dark:[&_.echarts-title]:text-white dark:[&_.echarts-visual-map]:text-white dark:[&_.echarts-map]:border-[#4b5563] dark:[&_.echarts-map-emphasis]:text-white dark:[&_.echarts-map-emphasis]:bg-[#059669] dark:[&_.echarts-map-unvisited]:bg-[#1f2937] dark:[&_.echarts-map-visited]:bg-[#059669]"
/>
);
};
export default WorldHeatmap;

View File

@ -4,6 +4,16 @@ import { load } from 'cheerio';
// 添加服务器渲染标记
export const prerender = false;
// 生成随机的bid Cookie值
function generateBid() {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let result = '';
for (let i = 0; i < 11; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
export const GET: APIRoute = async ({ request }) => {
const url = new URL(request.url);
const type = url.searchParams.get('type') || 'movie';
@ -25,12 +35,19 @@ export const GET: APIRoute = async ({ request }) => {
doubanUrl = `https://movie.douban.com/people/${doubanId}/collect?start=${start}&sort=time&rating=all&filter=all&mode=grid`;
}
// 生成随机bid
const bid = generateBid();
const response = await fetch(doubanUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Referer': 'https://movie.douban.com/'
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-User': '?1',
'Sec-Fetch-Dest': 'document',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cookie': `bid=${bid}`
}
});
@ -58,17 +75,38 @@ export const GET: APIRoute = async ({ request }) => {
}
const items: DoubanItem[] = [];
$('.item.comment-item').each((_, element) => {
// 尝试不同的选择器
let itemSelector = '.item.comment-item';
let itemCount = $(itemSelector).length;
if (itemCount === 0) {
// 尝试其他可能的选择器
itemSelector = '.subject-item';
itemCount = $(itemSelector).length;
}
$(itemSelector).each((_, element) => {
const $element = $(element);
const imageUrl = $element.find('.pic img').attr('src') || '';
const title = $element.find('.title a em').text().trim();
const subtitle = $element.find('.title a').text().replace(title, '').trim();
const link = $element.find('.title a').attr('href') || '';
const intro = $element.find('.intro').text().trim();
// 根据选择器调整查找逻辑
let imageUrl = '';
let title = '';
let subtitle = '';
let link = '';
let intro = '';
let rating = 0;
let date = '';
if (itemSelector === '.item.comment-item') {
// 原始逻辑
imageUrl = $element.find('.pic img').attr('src') || '';
title = $element.find('.title a em').text().trim();
subtitle = $element.find('.title a').text().replace(title, '').trim();
link = $element.find('.title a').attr('href') || '';
intro = $element.find('.intro').text().trim();
// 获取评分从rating1-t到rating5-t
let rating = 0;
for (let i = 1; i <= 5; i++) {
if ($element.find(`.rating${i}-t`).length > 0) {
rating = i;
@ -76,7 +114,23 @@ export const GET: APIRoute = async ({ request }) => {
}
}
const date = $element.find('.date').text().trim();
date = $element.find('.date').text().trim();
} else if (itemSelector === '.subject-item') {
// 新的图书页面结构
imageUrl = $element.find('.pic img').attr('src') || '';
title = $element.find('.info h2 a').text().trim();
link = $element.find('.info h2 a').attr('href') || '';
intro = $element.find('.info .pub').text().trim();
// 获取评分
const ratingClass = $element.find('.rating-star').attr('class') || '';
const ratingMatch = ratingClass.match(/rating(\d)-t/);
if (ratingMatch) {
rating = parseInt(ratingMatch[1]);
}
date = $element.find('.info .date').text().trim();
}
items.push({
imageUrl,