feat: 联调点赞功能

This commit is contained in:
liuyonghe0111 2025-12-24 11:43:34 +08:00
parent 3ed5f603c4
commit e6b28751bd
5 changed files with 32 additions and 30 deletions

View File

@ -5,7 +5,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { IconButton } from '@/components/ui/button';
import Link from 'next/link';
import { getTranslations } from 'next-intl/server';
import LikedIcon from '@/components/features/LikedIcon';
import LikedButton from '@/components/features/LikeButton';
import { LikeTargetType } from '@/services/editor/type';
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
@ -20,11 +20,7 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
<Link href="/home">
<IconButton variant="ghost" size="large" iconfont="icon-arrow-left" />
</Link>
<LikedIcon
iconProps={{ size: 'large' }}
objectId={id}
objectType={LikeTargetType.Character}
/>
<LikedButton size="large" objectId={id} objectType={LikeTargetType.Character} />
</div>
{/* 内容区 */}
<div className="mx-auto flex-1 overflow-auto pb-4 w-full">

View File

@ -23,7 +23,7 @@ import IconFont from '@/components/ui/iconFont';
import MaskCreate from './MaskCreate';
import { useTranslations } from 'next-intl';
import { useParams } from 'next/navigation';
import LikedIcon from '@/components/features/LikedIcon';
import LikedButton from '@/components/features/LikeButton';
import { LikeTargetType } from '@/services/editor/type';
type SettingProps = {
@ -71,7 +71,7 @@ export default function SettingDialog({ open, onOpenChange }: SettingProps) {
<AlertDialogContent className="max-w-[500px]" showCloseButton={activeTab === 'profile'}>
<AlertDialogTitle className="flex justify-between">
{activeTab === 'profile' ? (
<LikedIcon objectId={characterId} objectType={LikeTargetType.Character} />
<LikedButton objectId={characterId} objectType={LikeTargetType.Character} />
) : (
titleMap[activeTab]
)}

View File

@ -4,29 +4,31 @@ import { LikeTargetType, LikeType } from '@/services/editor/type';
import { IconButton } from '../ui/button';
import { useThmubObject } from '@/hooks/services/common';
import React from 'react';
import { cn } from '@/lib/utils';
type LikedIconProps = {
objectId: string;
objectType: LikeTargetType;
iconProps?: React.ComponentProps<typeof IconButton>;
};
} & React.ComponentProps<typeof IconButton>;
const LikedIcon = React.memo((props: LikedIconProps) => {
const { objectId, objectType, iconProps } = props;
const LikedButton = React.memo((props: LikedIconProps) => {
const { objectId, objectType, ...iconProps } = props;
const { thumb, handleThumb, loading } = useThmubObject({ objectId, objectType });
const isLiked = thumb === LikeType.Liked;
return (
<IconButton
variant="tertiary"
size="small"
{...iconProps}
iconfont={thumb === LikeType.Liked ? 'icon-Like-fill' : 'icon-Like'}
iconfont={isLiked ? 'icon-Like-fill' : 'icon-Like'}
className={cn(iconProps?.className, isLiked && 'text-red-500')}
onClick={() => {
if (loading) return;
handleThumb(thumb === LikeType.Liked ? LikeType.Canceled : LikeType.Liked);
handleThumb(isLiked ? LikeType.Canceled : LikeType.Liked);
}}
/>
);
});
export default LikedIcon;
export default LikedButton;

View File

@ -1,30 +1,35 @@
import { getLikeStatus, thmubObject } from '@/services/editor';
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { authKeys } from '@/lib/query-keys';
import { LikeObjectParamsType, LikeType } from '@/services/editor/type';
import { useAsyncFn } from '../tools';
import { useCurrentUser } from '../auth';
export function useThmubObject(props: Pick<LikeObjectParamsType, 'objectId' | 'objectType'>) {
const queryClient = useQueryClient();
const [thumb, setThumb] = useState<LikeType>();
const user = queryClient.getQueryData(authKeys.currentUser()) as any;
const { data: user } = useCurrentUser();
useQuery({
queryKey: ['likeStatus', props.objectId, user.userId],
enabled: !!props.objectId && !!user.userId,
queryFn: () => {
return getLikeStatus({ objectId: props.objectId, userId: user.userId });
const { data: likeStatus, refetch: refetchLikeStatus } = useQuery({
queryKey: ['likeStatus', props.objectId, user?.userId],
enabled: !!props.objectId && !!user?.userId,
queryFn: async () => {
const { data } = await getLikeStatus({ objectId: props.objectId, userId: user?.userId });
return data.likeStatus;
},
});
useEffect(() => {
if (typeof likeStatus === 'number') {
setThumb(likeStatus);
}
}, [likeStatus]);
const { run: handleThumb, loading } = useAsyncFn(async (likeType: LikeType) => {
setThumb(likeType);
const user = queryClient.getQueryData(authKeys.currentUser()) as any;
const { data } = await thmubObject({ ...props, likeType, userId: user?.userId });
if (data.code === 200) {
} else {
setThumb(undefined);
const { code } = await thmubObject({ ...props, likeType, userId: user?.userId });
if (code === 200) {
refetchLikeStatus();
}
});

View File

@ -23,6 +23,5 @@ export async function thmubObject(params: LikeObjectParamsType) {
}
export async function getLikeStatus(params: Pick<LikeObjectParamsType, 'objectId' | 'userId'>) {
const { data } = await editorRequest('/api/like/getLikeStatus', { method: 'POST', data: params });
return data;
return editorRequest('/api/like/getLikeStatus', { method: 'POST', data: params });
}