feat: 为点赞和收藏按钮添加认证守卫
- 在LikeButton组件中集成认证守卫 - 在FavoriteButton组件中集成认证守卫 - 未登录用户点击时显示提示并跳转到登录页 - 优化用户体验,避免无效API请求
This commit is contained in:
parent
f1c12a974c
commit
019e53cc81
@ -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<FavoriteButtonProps> = ({ heritageId, size = 'middle' }) => {
|
||||
const { user, isAuthenticated, addFavorite, removeFavorite } = useUserStore()
|
||||
const FavoriteButton: React.FC<FavoriteButtonProps> = ({
|
||||
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 (
|
||||
<Button
|
||||
type={isFavorited ? 'primary' : 'default'}
|
||||
icon={isFavorited ? <HeartFilled /> : <HeartOutlined />}
|
||||
icon={isFavorited ? <StarFilled /> : <StarOutlined />}
|
||||
onClick={handleToggle}
|
||||
loading={loading}
|
||||
size={size}
|
||||
>
|
||||
{isFavorited ? '已收藏' : '收藏'}
|
||||
{showText && (isFavorited ? '已收藏' : '收藏')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
104
src/components/LikeButton/index.tsx
Normal file
104
src/components/LikeButton/index.tsx
Normal file
@ -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<LikeButtonProps> = ({
|
||||
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 (
|
||||
<Button
|
||||
type={isLiked ? 'primary' : 'default'}
|
||||
icon={isLiked ? <LikeFilled /> : <LikeOutlined />}
|
||||
onClick={handleToggle}
|
||||
loading={loading}
|
||||
size={size}
|
||||
>
|
||||
{showText && (isLiked ? '已点赞' : '点赞')}
|
||||
{likeCount > 0 && ` (${likeCount.toLocaleString()})`}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export default LikeButton
|
||||
Loading…
Reference in New Issue
Block a user