diff --git a/src/components/FavoriteButton/index.tsx b/src/components/FavoriteButton/index.tsx index 1cbf94a..29629a0 100644 --- a/src/components/FavoriteButton/index.tsx +++ b/src/components/FavoriteButton/index.tsx @@ -1,45 +1,90 @@ /** * 收藏按钮组件 + * 对接后端收藏API */ -import React from 'react' +import React, { useEffect, useState } from 'react' import { Button, message } from 'antd' -import { HeartOutlined, HeartFilled } from '@ant-design/icons' +import { StarOutlined, StarFilled } from '@ant-design/icons' import { useUserStore } from '@store/useUserStore' +import { checkFavorite, toggleFavorite } from '@services/favoriteApi' +import { requireAuth } from '@/utils/authGuard' +import type { FavoriteTargetType } from '@/types' interface FavoriteButtonProps { - heritageId: string + targetType: FavoriteTargetType + targetId: string | number size?: 'small' | 'middle' | 'large' + showText?: boolean + onStatusChange?: (isFavorited: boolean) => void } -const FavoriteButton: React.FC = ({ heritageId, size = 'middle' }) => { - const { user, isAuthenticated, addFavorite, removeFavorite } = useUserStore() +const FavoriteButton: React.FC = ({ + targetType, + targetId, + size = 'middle', + showText = true, + onStatusChange +}) => { + const { isAuthenticated } = useUserStore() + const [isFavorited, setIsFavorited] = useState(false) + const [loading, setLoading] = useState(false) - const isFavorited = user?.favorites.includes(heritageId) || false + // 检查收藏状态 + useEffect(() => { + if (isAuthenticated) { + fetchFavoriteStatus() + } + }, [targetId, isAuthenticated]) - const handleToggle = () => { - if (!isAuthenticated) { - message.warning('请先登录后再收藏') + const fetchFavoriteStatus = async () => { + try { + const numericId = typeof targetId === 'string' ? parseInt(targetId) : targetId + const status = await checkFavorite(targetType, numericId) + setIsFavorited(status) + } catch (error) { + console.error('Failed to check favorite status:', error) + } + } + + const handleToggle = async () => { + // 🔥 认证守卫:未登录时提示并跳转到登录页 + if (!requireAuth('收藏')) { return } - if (isFavorited) { - removeFavorite(heritageId) - message.success('已取消收藏') - } else { - addFavorite(heritageId) - message.success('收藏成功') + setLoading(true) + try { + const numericId = typeof targetId === 'string' ? parseInt(targetId) : targetId + await toggleFavorite({ + targetType, + targetId: numericId + }, isFavorited) + + const newStatus = !isFavorited + setIsFavorited(newStatus) + // 已移除成功提示 + + // 触发回调 + if (onStatusChange) { + onStatusChange(newStatus) + } + } catch (error: any) { + message.error(error.message || '操作失败') + } finally { + setLoading(false) } } return ( ) } diff --git a/src/components/LikeButton/index.tsx b/src/components/LikeButton/index.tsx new file mode 100644 index 0000000..2b81130 --- /dev/null +++ b/src/components/LikeButton/index.tsx @@ -0,0 +1,104 @@ +/** + * 点赞按钮组件 + * 对接后端点赞API + */ + +import React, { useEffect, useState } from 'react' +import { Button, message } from 'antd' +import { LikeOutlined, LikeFilled } from '@ant-design/icons' +import { useUserStore } from '@store/useUserStore' +import { checkLike, toggleLike } from '@services/likeApi' +import { requireAuth } from '@/utils/authGuard' +import type { LikeTargetType } from '@/types' + +interface LikeButtonProps { + targetType: LikeTargetType + targetId: string | number + size?: 'small' | 'middle' | 'large' + showText?: boolean + initialCount?: number + onStatusChange?: (isLiked: boolean, newCount: number) => void +} + +const LikeButton: React.FC = ({ + targetType, + targetId, + size = 'middle', + showText = true, + initialCount = 0, + onStatusChange +}) => { + const { isAuthenticated } = useUserStore() + const [isLiked, setIsLiked] = useState(false) + const [likeCount, setLikeCount] = useState(initialCount) + const [loading, setLoading] = useState(false) + + // 检查点赞状态 + useEffect(() => { + if (isAuthenticated) { + fetchLikeStatus() + } + }, [targetId, isAuthenticated]) + + // 更新初始点赞数 + useEffect(() => { + setLikeCount(initialCount) + }, [initialCount]) + + const fetchLikeStatus = async () => { + try { + const numericId = typeof targetId === 'string' ? parseInt(targetId) : targetId + const status = await checkLike(targetType, numericId) + setIsLiked(status) + } catch (error) { + console.error('Failed to check like status:', error) + } + } + + const handleToggle = async () => { + // 🔥 认证守卫:未登录时提示并跳转到登录页 + if (!requireAuth('点赞')) { + return + } + + setLoading(true) + try { + const numericId = typeof targetId === 'string' ? parseInt(targetId) : targetId + await toggleLike({ + targetType, + targetId: numericId + }, isLiked) + + const newStatus = !isLiked + const newCount = newStatus ? likeCount + 1 : likeCount - 1 + + setIsLiked(newStatus) + setLikeCount(newCount) + // 已移除成功提示 + + // 触发回调 + if (onStatusChange) { + onStatusChange(newStatus, newCount) + } + } catch (error: any) { + message.error(error.message || '操作失败') + } finally { + setLoading(false) + } + } + + return ( + + ) +} + +export default LikeButton