From a187651231b81bf0f85b2b04fe528ad50a80119f Mon Sep 17 00:00:00 2001 From: shiyu Date: Sun, 25 May 2025 15:48:19 +0800 Subject: [PATCH] feat(ImageGrid): add edit functionality for images and update picture API --- Services/Media/PictureService.cs | 26 +++++++++++-- Web/src/api/index.ts | 3 +- Web/src/api/pictureApi.ts | 10 ++++- Web/src/api/types.ts | 7 ++++ Web/src/components/image/ImageGrid.tsx | 53 ++++++++++++++++++++++++-- 5 files changed, 91 insertions(+), 8 deletions(-) diff --git a/Services/Media/PictureService.cs b/Services/Media/PictureService.cs index 7119297..dbf541a 100644 --- a/Services/Media/PictureService.cs +++ b/Services/Media/PictureService.cs @@ -766,11 +766,31 @@ public class PictureService( picture.Description = description.Trim(); } + // 只有当名称或描述发生变化时才更新嵌入向量 if (!string.IsNullOrWhiteSpace(name) || !string.IsNullOrWhiteSpace(description)) { - var combinedText = $"{picture.Name}. {picture.Description}"; - var embedding = await embeddingService.GetEmbeddingAsync(combinedText); - picture.Embedding = new Vector(embedding); + try + { + var combinedText = $"{picture.Name}. {picture.Description}"; + var embedding = await embeddingService.GetEmbeddingAsync(combinedText); + + // 只有在成功获取到非空嵌入向量时才更新 + if (embedding != null && embedding.Length > 0) + { + picture.Embedding = new Vector(embedding); + } + else + { + // 记录获取到空向量的警告 + Console.WriteLine($"警告: 图片 {pictureId} 的嵌入向量为空,跳过向量更新"); + } + } + catch (Exception ex) + { + // 记录错误但不抛出异常,允许其他字段的更新继续进行 + Console.WriteLine($"更新图片 {pictureId} 的嵌入向量时出错: {ex.Message}"); + // 不设置 picture.Embedding,保持原值不变 + } } if (tags != null) diff --git a/Web/src/api/index.ts b/Web/src/api/index.ts index 3ce6a2c..ce67681 100644 --- a/Web/src/api/index.ts +++ b/Web/src/api/index.ts @@ -24,7 +24,8 @@ export { unfavoritePicture, getUserFavorites, uploadPicture, - deleteMultiplePictures, // 添加导出删除图片函数 + deleteMultiplePictures, + updatePicture, } from './pictureApi'; // 导出Album API diff --git a/Web/src/api/pictureApi.ts b/Web/src/api/pictureApi.ts index 8ae62ed..eb67d83 100644 --- a/Web/src/api/pictureApi.ts +++ b/Web/src/api/pictureApi.ts @@ -1,4 +1,4 @@ -import type { PaginatedResult, PictureResponse, FilteredPicturesRequest, BaseResult } from './types'; +import type { PaginatedResult, PictureResponse, FilteredPicturesRequest, BaseResult, UpdatePictureRequest } from './types'; import { fetchApi, BASE_URL } from './fetchClient'; // 获取图片列表 @@ -196,3 +196,11 @@ export async function deleteMultiplePictures(pictureIds: number[]): Promise> { + return fetchApi('/picture/update_picture', { + method: 'POST', + body: JSON.stringify(request), + }); +} + diff --git a/Web/src/api/types.ts b/Web/src/api/types.ts index c30a8c1..7d5374a 100644 --- a/Web/src/api/types.ts +++ b/Web/src/api/types.ts @@ -220,3 +220,10 @@ export interface UpdateUserRequest { currentPassword?: string; newPassword?: string; } + +export interface UpdatePictureRequest { + id: number; + name?: string; + description?: string; + tags?: string[]; +} diff --git a/Web/src/components/image/ImageGrid.tsx b/Web/src/components/image/ImageGrid.tsx index ba9a3a0..7ef8832 100644 --- a/Web/src/components/image/ImageGrid.tsx +++ b/Web/src/components/image/ImageGrid.tsx @@ -8,6 +8,7 @@ import type { PictureResponse } from '../../api'; import { favoritePicture, unfavoritePicture, getPictures, deleteMultiplePictures } from '../../api'; import ImageViewer from './ImageViewer'; import ShareImageDialog from './ShareImageDialog'; +import EditImageDialog from './EditImageDialog'; import './ImageGrid.css'; import { useAuth } from '../../api/AuthContext'; @@ -159,6 +160,15 @@ const ImageGrid: React.FC = ({ y: 0, }); + // 添加编辑对话框状态 + const [editDialogState, setEditDialogState] = useState<{ + visible: boolean; + image: PictureResponse | null; + }>({ + visible: false, + image: null + }); + // 简化标志变量 const isUsingExternalData = !!dataSource; @@ -354,7 +364,33 @@ const ImageGrid: React.FC = ({ }); }; - // 修改handleMenuAction中的分享处理 + // 处理编辑图片 + const handleEditImage = (image: PictureResponse) => { + setEditDialogState({ + visible: true, + image + }); + }; + + // 关闭编辑对话框 + const handleCloseEditDialog = () => { + setEditDialogState({ + ...editDialogState, + visible: false + }); + }; + + // 处理图片更新成功 + const handleImageUpdateSuccess = (updatedImage: PictureResponse) => { + // 更新本地图片列表中对应的图片 + setImages(prevImages => + prevImages.map(img => + img.id === updatedImage.id ? { ...img, ...updatedImage } : img + ) + ); + }; + + // 修改handleMenuAction中的编辑处理 const handleMenuAction = (action: string) => { if (!contextMenu.image) return; @@ -366,7 +402,7 @@ const ImageGrid: React.FC = ({ handleDeleteImage(contextMenu.image); break; case 'edit': - onEdit?.(contextMenu.image); + handleEditImage(contextMenu.image); break; case 'download': onDownload?.(contextMenu.image); @@ -497,7 +533,11 @@ const ImageGrid: React.FC = ({ className="custom-card-action-item" onClick={(e) => { e.stopPropagation(); - onEdit && onEdit(image); + if (onEdit) { + onEdit(image); + } else { + handleEditImage(image); + } }} > @@ -686,6 +726,13 @@ const ImageGrid: React.FC = ({ onClose={handleCloseShareDialog} image={shareDialogState.image} /> + + ); };