mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-05 23:57:19 +08:00
feat(AlbumService, ImageGrid, ImageViewer): enhance album deletion, optimize image loading, and improve favorite handling
This commit is contained in:
@@ -194,9 +194,22 @@ public class AlbumService(
|
|||||||
if (album == null)
|
if (album == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 注意:相册删除前,需要确保关联的图片被正确处理
|
// 先找出所有属于这个相册的图片
|
||||||
// 这里只移除相册,而不删除图片
|
var pictures = await dbContext.Pictures
|
||||||
|
.Where(p => p.AlbumId == id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 将这些图片的AlbumId设置为null
|
||||||
|
foreach (var picture in pictures)
|
||||||
|
{
|
||||||
|
picture.AlbumId = null;
|
||||||
|
picture.Album = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存图片更改
|
||||||
|
await dbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
// 然后删除相册
|
||||||
dbContext.Albums.Remove(album);
|
dbContext.Albums.Remove(album);
|
||||||
await dbContext.SaveChangesAsync();
|
await dbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
|||||||
@@ -178,42 +178,36 @@ const ImageGrid: React.FC<ImageGridProps> = ({
|
|||||||
const requestState = useRef({
|
const requestState = useRef({
|
||||||
inProgress: false,
|
inProgress: false,
|
||||||
lastParams: '',
|
lastParams: '',
|
||||||
noResultsFor: '' // 新增:记录哪些查询参数没有返回结果
|
noResultsFor: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
// 优化构建查询参数函数
|
const favoriteOperationsInProgress = useRef<Map<number, boolean>>(new Map());
|
||||||
const buildQueryParams = useCallback((): PaginationParams => {
|
|
||||||
const params: PaginationParams = {
|
const buildQueryParams = useCallback((): PaginationParams => ({
|
||||||
page: currentPage,
|
page: currentPage,
|
||||||
pageSize,
|
pageSize,
|
||||||
...queryParams,
|
...queryParams,
|
||||||
searchQuery: queryParams.searchQuery,
|
searchQuery: queryParams.searchQuery,
|
||||||
tags: Array.isArray(queryParams.tags) ? queryParams.tags.join(',') : undefined,
|
tags: Array.isArray(queryParams.tags) ? queryParams.tags.join(',') : undefined,
|
||||||
useVectorSearch: queryParams.useVectorSearch,
|
useVectorSearch: queryParams.useVectorSearch,
|
||||||
similarityThreshold: queryParams.similarityThreshold
|
similarityThreshold: queryParams.similarityThreshold
|
||||||
};
|
}), [currentPage, pageSize, queryParams]);
|
||||||
return params;
|
|
||||||
}, [currentPage, pageSize, queryParams]);
|
|
||||||
|
|
||||||
// 优化加载数据函数,减少依赖项
|
|
||||||
const loadImages = useCallback(async () => {
|
const loadImages = useCallback(async () => {
|
||||||
if (isUsingExternalData || requestState.current.inProgress) return;
|
if (isUsingExternalData || requestState.current.inProgress) return;
|
||||||
|
|
||||||
const params = buildQueryParams();
|
const params = buildQueryParams();
|
||||||
const paramsString = JSON.stringify(params);
|
const paramsString = JSON.stringify(params);
|
||||||
|
|
||||||
// 检查是否是已知没有结果的查询
|
if (requestState.current.noResultsFor === paramsString && images.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (requestState.current.noResultsFor === paramsString) {
|
if (requestState.current.noResultsFor === paramsString) {
|
||||||
// 如果这个查询之前没有结果,且当前还是空结果状态,不再重复请求
|
|
||||||
if (images.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 如果之前没结果但现在有图片显示,重置noResultsFor让新查询可以执行
|
|
||||||
requestState.current.noResultsFor = '';
|
requestState.current.noResultsFor = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestState.current.lastParams === paramsString) {
|
if (requestState.current.lastParams === paramsString) {
|
||||||
// 如果参数没变且已有数据或无数据状态已确认,跳过请求
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,16 +222,13 @@ const ImageGrid: React.FC<ImageGridProps> = ({
|
|||||||
try {
|
try {
|
||||||
const result = await getPictures(params);
|
const result = await getPictures(params);
|
||||||
|
|
||||||
// 无论成功与否,都更新lastParams以避免相同参数的重复请求
|
|
||||||
requestState.current.lastParams = paramsString;
|
requestState.current.lastParams = paramsString;
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// 更新图片数据
|
|
||||||
setImages(result.data || []);
|
setImages(result.data || []);
|
||||||
setTotalImages(result.totalCount || 0);
|
setTotalImages(result.totalCount || 0);
|
||||||
onImagesLoaded?.(result.data || [], result.totalCount || 0);
|
onImagesLoaded?.(result.data || [], result.totalCount || 0);
|
||||||
|
|
||||||
// 如果结果为空,记录到noResultsFor
|
|
||||||
if (!result.data || result.data.length === 0) {
|
if (!result.data || result.data.length === 0) {
|
||||||
requestState.current.noResultsFor = paramsString;
|
requestState.current.noResultsFor = paramsString;
|
||||||
}
|
}
|
||||||
@@ -264,10 +255,20 @@ const ImageGrid: React.FC<ImageGridProps> = ({
|
|||||||
if (isUsingExternalData && dataSource) setImages(dataSource);
|
if (isUsingExternalData && dataSource) setImages(dataSource);
|
||||||
}, [dataSource, isUsingExternalData]);
|
}, [dataSource, isUsingExternalData]);
|
||||||
|
|
||||||
// 优化收藏/取消收藏逻辑
|
// 优化收藏/取消收藏逻辑,添加防抖功能
|
||||||
const handleToggleFavorite = async (image: PictureResponse) => {
|
const handleToggleFavorite = async (image: PictureResponse) => {
|
||||||
|
const { id, isFavorited } = image;
|
||||||
|
|
||||||
|
// 检查此图片是否有收藏操作正在进行中
|
||||||
|
if (favoriteOperationsInProgress.current.get(id)) {
|
||||||
|
// 如果有操作正在进行中,直接返回,不执行新的操作
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { id, isFavorited } = image;
|
// 设置操作锁定状态
|
||||||
|
favoriteOperationsInProgress.current.set(id, true);
|
||||||
|
|
||||||
const api = isFavorited ? unfavoritePicture : favoritePicture;
|
const api = isFavorited ? unfavoritePicture : favoritePicture;
|
||||||
const result = await api(id);
|
const result = await api(id);
|
||||||
|
|
||||||
@@ -293,6 +294,11 @@ const ImageGrid: React.FC<ImageGridProps> = ({
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('操作失败,请重试');
|
message.error('操作失败,请重试');
|
||||||
|
} finally {
|
||||||
|
// 操作完成后,延迟300ms释放锁定状态,进一步防止快速重复点击
|
||||||
|
setTimeout(() => {
|
||||||
|
favoriteOperationsInProgress.current.delete(id);
|
||||||
|
}, 300);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -382,12 +388,20 @@ const ImageGrid: React.FC<ImageGridProps> = ({
|
|||||||
|
|
||||||
// 处理图片更新成功
|
// 处理图片更新成功
|
||||||
const handleImageUpdateSuccess = (updatedImage: PictureResponse) => {
|
const handleImageUpdateSuccess = (updatedImage: PictureResponse) => {
|
||||||
// 更新本地图片列表中对应的图片
|
|
||||||
setImages(prevImages =>
|
setImages(prevImages =>
|
||||||
prevImages.map(img =>
|
prevImages.map(img => {
|
||||||
img.id === updatedImage.id ? { ...img, ...updatedImage } : img
|
if (img.id === updatedImage.id) {
|
||||||
)
|
return {
|
||||||
|
...img,
|
||||||
|
...updatedImage,
|
||||||
|
userId: img.userId,
|
||||||
|
permission: updatedImage.permission ?? img.permission
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return img;
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
closeContextMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改handleMenuAction中的编辑处理
|
// 修改handleMenuAction中的编辑处理
|
||||||
@@ -716,7 +730,7 @@ const ImageGrid: React.FC<ImageGridProps> = ({
|
|||||||
onClose={() => setViewerState({ ...viewerState, visible: false })}
|
onClose={() => setViewerState({ ...viewerState, visible: false })}
|
||||||
images={images}
|
images={images}
|
||||||
initialIndex={viewerState.index}
|
initialIndex={viewerState.index}
|
||||||
onFavorite={onToggleFavorite || handleToggleFavorite}
|
onFavorite={handleToggleFavorite} // 总是传递本地的handleToggleFavorite而不是条件判断
|
||||||
showFavoriteCount={showFavoriteCount}
|
showFavoriteCount={showFavoriteCount}
|
||||||
onShare={handleShareImage}
|
onShare={handleShareImage}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -200,12 +200,15 @@
|
|||||||
border: none;
|
border: none;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
border-radius: 50%;
|
border-radius: 8px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
width: 40px;
|
min-width: 40px;
|
||||||
|
padding: 0 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-btn:hover {
|
.footer-btn:hover {
|
||||||
@@ -213,8 +216,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer-btn span {
|
.footer-btn span {
|
||||||
margin-left: 4px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-btn .anticon + span {
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 16px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-info-drawer {
|
.image-info-drawer {
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
const [shareDialogVisible, setShareDialogVisible] = useState(false);
|
const [shareDialogVisible, setShareDialogVisible] = useState(false);
|
||||||
const [imageLoaded, setImageLoaded] = useState(false);
|
const [imageLoaded, setImageLoaded] = useState(false);
|
||||||
const [currentLoading, setCurrentLoading] = useState(false);
|
const [currentLoading, setCurrentLoading] = useState(false);
|
||||||
|
const [fadeTransition, setFadeTransition] = useState(false);
|
||||||
|
const [, setActiveImage] = useState<string | null>(null);
|
||||||
|
|
||||||
const [zoomPanState, setZoomPanState] = useState<ZoomPanState>({
|
const [zoomPanState, setZoomPanState] = useState<ZoomPanState>({
|
||||||
scale: 1,
|
scale: 1,
|
||||||
@@ -79,6 +81,9 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
const imageRef = useRef<HTMLImageElement>(null);
|
const imageRef = useRef<HTMLImageElement>(null);
|
||||||
const imageCache = useRef<ImageCache>({});
|
const imageCache = useRef<ImageCache>({});
|
||||||
const sessionKey = useRef<string>(Date.now().toString());
|
const sessionKey = useRef<string>(Date.now().toString());
|
||||||
|
const currentLoadingUrl = useRef<string | null>(null);
|
||||||
|
const preloadedImagesRef = useRef<{[key: string]: HTMLImageElement}>({});
|
||||||
|
const favoriteOperationsInProgress = useRef<Map<number, boolean>>(new Map());
|
||||||
|
|
||||||
const currentImage = localImages[currentIndex];
|
const currentImage = localImages[currentIndex];
|
||||||
const preloadRange = 2;
|
const preloadRange = 2;
|
||||||
@@ -103,19 +108,8 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 当前加载中的图片URL追踪
|
|
||||||
const currentLoadingUrl = useRef<string | null>(null);
|
|
||||||
|
|
||||||
// 预渲染图片容器
|
|
||||||
const preloadedImagesRef = useRef<{[key: string]: HTMLImageElement}>({});
|
|
||||||
|
|
||||||
// 图片过渡状态
|
|
||||||
const [fadeTransition, setFadeTransition] = useState(false);
|
|
||||||
const [, setActiveImage] = useState<string | null>(null);
|
|
||||||
|
|
||||||
const loadImage = useCallback((imageUrl: string): Promise<HTMLImageElement> => {
|
const loadImage = useCallback((imageUrl: string): Promise<HTMLImageElement> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 检查缓存
|
|
||||||
if (imageCache.current[imageUrl]?.loaded) {
|
if (imageCache.current[imageUrl]?.loaded) {
|
||||||
if (currentImage && imageUrl === currentImage.path) {
|
if (currentImage && imageUrl === currentImage.path) {
|
||||||
setImageLoaded(true);
|
setImageLoaded(true);
|
||||||
@@ -152,13 +146,11 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
});
|
});
|
||||||
}, [currentImage]);
|
}, [currentImage]);
|
||||||
|
|
||||||
// 图片切换逻辑优化
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setImageLoaded(false);
|
setImageLoaded(false);
|
||||||
setCurrentLoading(true);
|
setCurrentLoading(true);
|
||||||
setFadeTransition(true);
|
setFadeTransition(true);
|
||||||
|
|
||||||
// 利用缓存快速显示
|
|
||||||
if (currentImage && imageCache.current[currentImage.path]?.loaded) {
|
if (currentImage && imageCache.current[currentImage.path]?.loaded) {
|
||||||
setActiveImage(currentImage.path);
|
setActiveImage(currentImage.path);
|
||||||
setImageLoaded(true);
|
setImageLoaded(true);
|
||||||
@@ -167,7 +159,6 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
setTimeout(() => setFadeTransition(false), 100);
|
setTimeout(() => setFadeTransition(false), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置缩放状态
|
|
||||||
setZoomPanState(prev => ({
|
setZoomPanState(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
@@ -177,7 +168,6 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
}));
|
}));
|
||||||
}, [currentIndex]);
|
}, [currentIndex]);
|
||||||
|
|
||||||
// 可见性变化处理
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible && !wasVisible.current) {
|
if (visible && !wasVisible.current) {
|
||||||
resetViewerState();
|
resetViewerState();
|
||||||
@@ -188,14 +178,12 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
wasVisible.current = visible;
|
wasVisible.current = visible;
|
||||||
}, [visible, resetViewerState]);
|
}, [visible, resetViewerState]);
|
||||||
|
|
||||||
// 初始索引处理
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible && initialIndex >= 0 && initialIndex < images.length) {
|
if (visible && initialIndex >= 0 && initialIndex < images.length) {
|
||||||
setCurrentIndex(initialIndex);
|
setCurrentIndex(initialIndex);
|
||||||
}
|
}
|
||||||
}, [visible, initialIndex, images.length]);
|
}, [visible, initialIndex, images.length]);
|
||||||
|
|
||||||
// 图片加载逻辑
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!currentImage || !visible) return;
|
if (!currentImage || !visible) return;
|
||||||
|
|
||||||
@@ -218,7 +206,6 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
setCurrentLoading(false);
|
setCurrentLoading(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 预加载相邻图片
|
|
||||||
if (localImages.length > 1) {
|
if (localImages.length > 1) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
for (let i = 1; i <= preloadRange; i++) {
|
for (let i = 1; i <= preloadRange; i++) {
|
||||||
@@ -272,29 +259,39 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
|
|
||||||
const handleFavoriteClick = useCallback(async () => {
|
const handleFavoriteClick = useCallback(async () => {
|
||||||
if (!currentImage) return;
|
if (!currentImage) return;
|
||||||
|
|
||||||
|
if (favoriteOperationsInProgress.current.get(currentImage.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
favoriteOperationsInProgress.current.set(currentImage.id, true);
|
||||||
|
|
||||||
if (onFavorite) {
|
if (onFavorite) {
|
||||||
onFavorite(currentImage);
|
onFavorite(currentImage);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFavorited = currentImage.isFavorited;
|
const isFavorited = currentImage.isFavorited;
|
||||||
|
|
||||||
const result = isFavorited
|
const result = isFavorited
|
||||||
? await unfavoritePicture(currentImage.id)
|
? await unfavoritePicture(currentImage.id)
|
||||||
: await favoritePicture(currentImage.id);
|
: await favoritePicture(currentImage.id);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
message.success(isFavorited ? '已取消收藏' : '已添加到收藏');
|
message.success(isFavorited ? '已取消收藏' : '已添加到收藏');
|
||||||
|
|
||||||
|
const updatedImage = {
|
||||||
|
...currentImage,
|
||||||
|
isFavorited: !isFavorited,
|
||||||
|
favoriteCount: isFavorited
|
||||||
|
? Math.max(0, (currentImage.favoriteCount || 0) - 1)
|
||||||
|
: (currentImage.favoriteCount || 0) + 1
|
||||||
|
};
|
||||||
|
|
||||||
setLocalImages(prevImages =>
|
setLocalImages(prevImages =>
|
||||||
prevImages.map(img =>
|
prevImages.map(img =>
|
||||||
img.id === currentImage.id ? {
|
img.id === currentImage.id ? updatedImage : img
|
||||||
...img,
|
|
||||||
isFavorited: !isFavorited,
|
|
||||||
favoriteCount: isFavorited
|
|
||||||
? Math.max(0, (img.favoriteCount || 0) - 1)
|
|
||||||
: (img.favoriteCount || 0) + 1
|
|
||||||
} : img
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -303,6 +300,10 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('收藏操作失败:', error);
|
console.error('收藏操作失败:', error);
|
||||||
message.error('操作失败,请重试');
|
message.error('操作失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => {
|
||||||
|
favoriteOperationsInProgress.current.delete(currentImage.id);
|
||||||
|
}, 300);
|
||||||
}
|
}
|
||||||
}, [currentImage, onFavorite]);
|
}, [currentImage, onFavorite]);
|
||||||
|
|
||||||
@@ -484,7 +485,6 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
}
|
}
|
||||||
}, [visible, handleMouseUp, handleTouchEnd]);
|
}, [visible, handleMouseUp, handleTouchEnd]);
|
||||||
|
|
||||||
// 渲染优化:减少重绘和提高性能
|
|
||||||
if (images.length === 0 || !currentImage) {
|
if (images.length === 0 || !currentImage) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -595,21 +595,20 @@ const ImageViewer: React.FC<ImageViewerProps> = ({
|
|||||||
<div className="image-name">{currentImage.name}</div>
|
<div className="image-name">{currentImage.name}</div>
|
||||||
|
|
||||||
<div className="footer-actions">
|
<div className="footer-actions">
|
||||||
{onFavorite && (
|
<Button
|
||||||
<Button
|
type="text"
|
||||||
type="text"
|
icon={currentImage.isFavorited ?
|
||||||
icon={currentImage.isFavorited ?
|
<HeartFilled style={{ color: '#ff4d4f' }} /> :
|
||||||
<HeartFilled style={{ color: '#ff4d4f' }} /> :
|
<HeartOutlined style={{ color: '#fff' }} />
|
||||||
<HeartOutlined style={{ color: '#fff' }} />
|
}
|
||||||
}
|
onClick={handleFavoriteClick}
|
||||||
onClick={handleFavoriteClick}
|
className="footer-btn"
|
||||||
className="footer-btn"
|
>
|
||||||
>
|
{showFavoriteCount && typeof currentImage.favoriteCount === 'number' && (
|
||||||
{showFavoriteCount && typeof currentImage.favoriteCount === 'number' && (
|
<span>{currentImage.favoriteCount}</span>
|
||||||
<span>{currentImage.favoriteCount}</span>
|
)}
|
||||||
)}
|
</Button>
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<Dropdown menu={{ items: albumItems }} disabled={loadingAlbums || albums.length === 0}>
|
<Dropdown menu={{ items: albumItems }} disabled={loadingAlbums || albums.length === 0}>
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type OutletContextType = {
|
|||||||
function AlbumDetail() {
|
function AlbumDetail() {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { updateBreadcrumbTitle } = useOutletContext<OutletContextType>();
|
const { updateBreadcrumbTitle = () => {} } = useOutletContext<OutletContextType>();
|
||||||
|
|
||||||
const [album, setAlbum] = useState<AlbumResponse | null>(null);
|
const [album, setAlbum] = useState<AlbumResponse | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@@ -28,6 +28,7 @@ function AlbumDetail() {
|
|||||||
const [selectedPictures, setSelectedPictures] = useState<number[]>([]);
|
const [selectedPictures, setSelectedPictures] = useState<number[]>([]);
|
||||||
const [editForm] = Form.useForm();
|
const [editForm] = Form.useForm();
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
const [refreshTrigger, setRefreshTrigger] = useState(0); // 添加刷新触发器
|
||||||
|
|
||||||
const loadAlbum = async () => {
|
const loadAlbum = async () => {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
@@ -36,8 +37,10 @@ function AlbumDetail() {
|
|||||||
const result = await getAlbumById(parseInt(id));
|
const result = await getAlbumById(parseInt(id));
|
||||||
if (result.success && result.data) {
|
if (result.success && result.data) {
|
||||||
setAlbum(result.data);
|
setAlbum(result.data);
|
||||||
// 更新面包屑标题
|
// 添加检查确保 updateBreadcrumbTitle 是一个函数
|
||||||
updateBreadcrumbTitle(result.data.name);
|
if (typeof updateBreadcrumbTitle === 'function') {
|
||||||
|
updateBreadcrumbTitle(result.data.name);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
message.error(result.message || '获取相册失败');
|
message.error(result.message || '获取相册失败');
|
||||||
}
|
}
|
||||||
@@ -114,6 +117,7 @@ function AlbumDetail() {
|
|||||||
message.success(`已添加 ${selectedPictures.length} 张图片到相册`);
|
message.success(`已添加 ${selectedPictures.length} 张图片到相册`);
|
||||||
setSelectedPictures([]);
|
setSelectedPictures([]);
|
||||||
loadAlbum();
|
loadAlbum();
|
||||||
|
setRefreshTrigger(prev => prev + 1); // 更新刷新触发器
|
||||||
} else {
|
} else {
|
||||||
message.error(result.message || '添加图片到相册失败');
|
message.error(result.message || '添加图片到相册失败');
|
||||||
}
|
}
|
||||||
@@ -289,7 +293,8 @@ function AlbumDetail() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ImageGrid
|
<ImageGrid
|
||||||
queryParams={{ albumId: parseInt(id || '0') }} // 直接传入albumId参数获取相册图片
|
key={refreshTrigger}
|
||||||
|
queryParams={{ albumId: parseInt(id || '0') }}
|
||||||
onToggleFavorite={handleToggleFavorite}
|
onToggleFavorite={handleToggleFavorite}
|
||||||
showFavoriteCount={true}
|
showFavoriteCount={true}
|
||||||
showPagination={true}
|
showPagination={true}
|
||||||
|
|||||||
Reference in New Issue
Block a user