From a20859f6220ad1e29f71e7101cbe81ca00f85601 Mon Sep 17 00:00:00 2001 From: Shiina Kin Date: Sat, 7 Dec 2024 00:43:22 +0800 Subject: [PATCH] refactor: refactor user image view with custom component --- .../form/userField/image/ImageEditForm.vue | 74 ++ ui/src/locales/zh_cn.yaml | 156 +++- ui/src/views/userField/image/MyImageView.vue | 804 +++++++++--------- 3 files changed, 584 insertions(+), 450 deletions(-) create mode 100644 ui/src/components/form/userField/image/ImageEditForm.vue diff --git a/ui/src/components/form/userField/image/ImageEditForm.vue b/ui/src/components/form/userField/image/ImageEditForm.vue new file mode 100644 index 00000000..7ea6602b --- /dev/null +++ b/ui/src/components/form/userField/image/ImageEditForm.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/ui/src/locales/zh_cn.yaml b/ui/src/locales/zh_cn.yaml index f711d357..be781ce0 100644 --- a/ui/src/locales/zh_cn.yaml +++ b/ui/src/locales/zh_cn.yaml @@ -76,53 +76,115 @@ imageUploadView: title: "上传列表" uploadAllButton: "上传全部" myImageView: - myImageFilterUploadTimeASC: "上传时间升序" - myImageFilterUploadTimeDESC: "上传时间降序" - myImageFilterFileSizeASC: "文件大小升序" - myImageFilterFileSizeDESC: "文件大小降序" - myImageFilterPublicVisible: "公开" - myImageFilterPrivateVisible: "私密" - myImageFilterAllVisible: "全部" - myImageFilterAlbumButton: "相册" - myImageFilterAlbumTitle: "相册列表" - myImageDialogImageCopySuccessMessage: "复制成功" - myImageDialogImageCopyPrivateWarningMessage: "复制失败,图片为私密图片" - myImageDialogImageDetailTitle: "图片详情" - myImageDialogImageDetailImageName: "图片名称" - myImageDialogImageDetailImageRawName: "图片原始名称" - myImageDialogImageDetailImageType: "图片类型" - myImageDialogImageDetailImageAlbumName: "所属相册" - myImageDialogImageDetailImageOwnerName: "所属用户" - myImageDialogImageDetailImageSize: "图片尺寸" - myImageDialogImageDetailImageFileSize: "图片大小" - myImageDialogImageDetailImageUploadTime: "上传时间" - myImageDialogImageDetailImageIsPublic: "是否公开" - myImageDialogImageDetailImageDesc: "图片描述" - myImageDialogImageRenameCancelButton: "取消" - myImageDialogImageRenameSubmitButton: "保存" - myImageDialogImageRenameTitle: "修改图片名称" - myImageDialogImageRenameOldImageName: "旧图片名" - myImageDialogImageRenameNewImageName: "新图片名" - myImageDialogImageRenameSuccessMessage: "重命名成功" - myImageDialogImageRenameFailedTitle: "重命名失败" - myImageDialogImageDeleteConfirmTitle: "确认删除" - myImageDialogImageDeleteConfirmWarningMainContent: "你确定要删除图片吗?" - myImageDialogImageDeleteConfirmWarningSubContent: "真的会删除,而且无法找回" - myImageDialogImageDeleteConfirmCancelButton: "取消" - myImageDialogImageDeleteConfirmSubmitButton: "确认删除" - myImageDialogImageDeleteConfirmSuccessTitle: "删除成功" - myImageDialogImageDeleteConfirmFailedTitle: "删除失败" - myImageDialogImageChangeVisibleSuccessMessage: "修改访问权限成功" - myImageDialogImageChangeVisibleFailedTitle: "修改访问权限失败" - myImageDialogImageChangeAlbumTableAlbumId: "相册ID" - myImageDialogImageChangeAlbumTableAlbumName: "相册名" - myImageDialogImageChangeAlbumTableImageCount: "图片数量" - myImageDialogImageChangeAlbumTableIsUncategorized: "是否为未分类相册" - myImageDialogImageChangeAlbumCancelButton: "取消" - myImageDialogImageChangeAlbumSubmitButton: "移动" - myImageDialogImageChangeAlbumWarningMessage: "请选择相册" - myImageDialogImageChangeAlbumSuccessMessage: "修改相册成功" - myImageDialogImageChangeAlbumFailedTitle: "修改相册失败" + filter: + image: + uploadTimeASC: "上传时间升序" + uploadTimeDESC: "上传时间降序" + fileSizeASC: "文件大小升序" + fileSizeDESC: "文件大小降序" + visible: + public: "公开" + private: "私密" + all: "全部" + album: + button: "相册" + drawer: + title: "相册列表" + contextMenu: + single: + copyImage: "复制图片" + copyLink: "复制链接" + moveToAlbum: "移动到相册" + settingAsPrivate: "设为私密" + settingAsPublic: "设为公开" + detail: "详情信息" + edit: "修改" + delete: "删除" + multi: + moveToAlbum: "移动到相册" + settingAsPrivate: "设为私密" + settingAsPublic: "设为公开" + delete: "删除" + detail: + dialog: + title: "图片详情" + name: "图片名称" + rawName: "图片原始名称" + type: "图片类型" + albumName: "所属相册" + ownerName: "所属用户" + strategyName: "所属存储策略" + strategyType: "存储策略类型" + size: "图片尺寸" + fileSize: "图片大小" + fileSizeUnit: "MB" + uploadTime: "上传时间" + isPrivate: + title: "是否公开" + true: "私密" + false: "公开" + description: "图片描述" + toast: + failedTitle: "获取图片信息失败" + edit: + dialog: + title: "修改图片" + form: + displayName: "图片名" + description: "图片描述" + cancelButton: "取消" + submitButton: "保存" + verify: + atLeastOneField: "请至少修改一个字段" + toast: + successTitle: "重命名成功" + failedTitle: "重命名失败" + copyImage: + toast: + successTitle: "复制成功" + failedTitle: "复制失败" + copyLink: + toast: + successTitle: "复制成功" + failedTitle: "复制失败, 私密图片无法复制外链" + changeVisible: + toast: + successTitle: "修改访问权限成功" + failedTitle: "修改访问权限失败" + changeAlbum: + dialog: + title: "移动到相册" + form: + table: + albumId: "相册ID" + albumName: "相册名" + imageCount: "图片数量" + isUncategorized: + title: "是否为未分类" + true: "是" + false: "否" + isDefault: + title: "是否默认" + true: "是" + false: "否" + cancelButton: "取消" + submitButton: "移动" + verify: + album: + required: "请选择相册" + toast: + successTitle: "修改相册成功" + failedTitle: "修改相册失败" + delete: + dialog: + title: "确认删除" + mainContent: "你确定要删除图片吗?" + subContent: "真的会删除,而且无法找回" + cancelButton: "取消" + submitButton: "确认删除" + toast: + successTitle: "删除成功" + failedTitle: "删除失败" myAlbumView: toolbar: createButton: "创建相册" diff --git a/ui/src/views/userField/image/MyImageView.vue b/ui/src/views/userField/image/MyImageView.vue index 832e2684..8de00414 100644 --- a/ui/src/views/userField/image/MyImageView.vue +++ b/ui/src/views/userField/image/MyImageView.vue @@ -2,23 +2,27 @@ import { computed, ref, watchEffect } from "vue"; import { useI18n } from "vue-i18n"; import { + Configuration, + ImageApi, AlbumApi, type AlbumApiApiAlbumPageGetRequest, type AlbumPageVO, - Configuration, - ImageApi, type ImageApiApiImagePageGetRequest, + type ImageApiApiImageImageIdPatchRequest, type ImagePageVO, type ImageVO } from "api-client"; import { useUserFieldStore } from "@/stores/counter"; +import { useToast } from "primevue/usetoast"; import { Icon } from "@iconify/vue"; +import { api as viewerApi } from "v-viewer"; import ImageCard from "@/components/ImageCard.vue"; import ContextMenu from "@/components/ContextMenu.vue"; import BottomPaginator from "@/components/BottomPaginator.vue"; -import { api as viewerApi } from "v-viewer"; +import LoadingDialog from "@/components/LoadingDialog.vue"; +import ConfirmDialog from "@/components/ConfirmDialog.vue"; +import ImageEditForm from "@/components/form/userField/image/ImageEditForm.vue"; import Button from "primevue/button"; -import FloatLabel from "primevue/floatlabel"; import InputText from "primevue/inputtext"; import InputGroup from "primevue/inputgroup"; import InputGroupAddon from "primevue/inputgroupaddon"; @@ -29,7 +33,6 @@ import DataTable from "primevue/datatable"; import Column from "primevue/column"; import Paginator from "primevue/paginator"; import Dialog from "primevue/dialog"; -import { useToast } from "primevue/usetoast"; import type { MenuItem } from "primevue/menuitem"; import md5 from "crypto-js/md5"; import { debounce } from "lodash-es"; @@ -42,8 +45,6 @@ import { } from "@/utils/URLFormatUtils"; import type { ImageDisplay, ImageView } from "@/types/ImageType"; import { convertImageToBlob } from "@/utils/ImageUtils"; -import LoadingDialog from "@/components/LoadingDialog.vue"; -import ConfirmDialog from "@/components/ConfirmDialog.vue"; import { formatUTCStringToLocale } from "@/utils/DateTimeUtils"; const userFieldStore = useUserFieldStore(); @@ -84,13 +85,13 @@ const pageRequest = computed(() => { }; }); -const debouncePageUserImage = debounce((request: ImageApiApiImagePageGetRequest) => { +const debouncePageUserAlbum = debounce((request: ImageApiApiImagePageGetRequest) => { pageUserImage(request); -}, 200); +}, 300); watchEffect(() => { const pageReq = pageRequest.value; - debouncePageUserImage(pageReq); + debouncePageUserAlbum(pageReq); }); const curPage = ref(1); @@ -147,7 +148,7 @@ const multiImageContextMenuRef = ref(); const singleImageContextMenuItems = ref([ { - label: "复制图片", + label: t("myImageView.contextMenu.single.copyImage"), icon: "mdi:content-copy", command: () => { fetchImageBlob(curRightClickImageId.value) @@ -163,19 +164,23 @@ const singleImageContextMenuItems = ref([ .then(() => { toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageCopySuccessMessage"), + summary: t("myImageView.copyImage.toast.successTitle"), life: 3000 }); }) .catch((e) => { console.error(e); - toast.add({ severity: "error", summary: "Error", detail: e.message, life: 3000 }); + toast.add({ + severity: "error", + summary: t("myImageView.copyImage.toast.failedTitle"), + detail: e.message, + life: 3000 + }); }); } }, { - label: "复制链接", + label: t("myImageView.contextMenu.single.copyLink"), icon: "mdi:link", items: [ { @@ -186,8 +191,7 @@ const singleImageContextMenuItems = ref([ if (image.isPrivate) { toast.add({ severity: "warn", - summary: "Warning", - detail: t("myImageView.myImageDialogImageCopyPrivateWarningMessage"), + summary: t("myImageView.copyLink.toast.failedTitle"), life: 3000 }); return; @@ -195,8 +199,7 @@ const singleImageContextMenuItems = ref([ navigator.clipboard.writeText(transToDirect(image.displayName, image.externalUrl!)); toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageCopySuccessMessage"), + summary: t("myImageView.copyLink.toast.successTitle"), life: 3000 }); } @@ -209,8 +212,7 @@ const singleImageContextMenuItems = ref([ if (image.isPrivate) { toast.add({ severity: "warn", - summary: "Warning", - detail: t("myImageView.myImageDialogImageCopyPrivateWarningMessage"), + summary: t("myImageView.copyLink.toast.failedTitle"), life: 3000 }); return; @@ -218,8 +220,7 @@ const singleImageContextMenuItems = ref([ navigator.clipboard.writeText(transToMarkdown(image.displayName, image.externalUrl!)); toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageCopySuccessMessage"), + summary: t("myImageView.copyLink.toast.successTitle"), life: 3000 }); } @@ -232,8 +233,7 @@ const singleImageContextMenuItems = ref([ if (image.isPrivate) { toast.add({ severity: "warn", - summary: "Warning", - detail: t("myImageView.myImageDialogImageCopyPrivateWarningMessage"), + summary: t("myImageView.copyLink.toast.failedTitle"), life: 3000 }); return; @@ -241,8 +241,7 @@ const singleImageContextMenuItems = ref([ navigator.clipboard.writeText(transToMarkdownWithLink(image.displayName, image.externalUrl!)); toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageCopySuccessMessage"), + summary: t("myImageView.copyLink.toast.successTitle"), life: 3000 }); } @@ -255,8 +254,7 @@ const singleImageContextMenuItems = ref([ if (image.isPrivate) { toast.add({ severity: "warn", - summary: "Warning", - detail: t("myImageView.myImageDialogImageCopyPrivateWarningMessage"), + summary: t("myImageView.copyLink.toast.failedTitle"), life: 3000 }); return; @@ -264,8 +262,7 @@ const singleImageContextMenuItems = ref([ navigator.clipboard.writeText(transToHTML(image.displayName, image.externalUrl!)); toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageCopySuccessMessage"), + summary: t("myImageView.copyLink.toast.successTitle"), life: 3000 }); } @@ -278,8 +275,7 @@ const singleImageContextMenuItems = ref([ if (image.isPrivate) { toast.add({ severity: "warn", - summary: "Warning", - detail: t("myImageView.myImageDialogImageCopyPrivateWarningMessage"), + summary: t("myImageView.copyLink.toast.failedTitle"), life: 3000 }); return; @@ -287,8 +283,7 @@ const singleImageContextMenuItems = ref([ navigator.clipboard.writeText(transToBBCode(image.displayName, image.externalUrl!)); toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageCopySuccessMessage"), + summary: t("myImageView.copyLink.toast.successTitle"), life: 3000 }); } @@ -296,7 +291,7 @@ const singleImageContextMenuItems = ref([ ] }, { - label: "移动到相册", + label: t("myImageView.contextMenu.single.moveToAlbum"), icon: "mdi:move-to-inbox", command: () => { isSingleImageChangeAlbum.value = true; @@ -304,21 +299,21 @@ const singleImageContextMenuItems = ref([ } }, { - label: "设为公开", + label: t("myImageView.contextMenu.single.settingAsPublic"), icon: "mdi:visibility-outline", command: () => { handleSingleChangeVisibility(false); } }, { - label: "设为私密", + label: t("myImageView.contextMenu.single.settingAsPrivate"), icon: "mdi:visibility-off-outline", command: () => { handleSingleChangeVisibility(true); } }, { - label: "详细信息", + label: t("myImageView.contextMenu.single.detail"), icon: "mdi:information-slab-box-outline", command: () => { handleImageDetail(); @@ -328,14 +323,14 @@ const singleImageContextMenuItems = ref([ separator: true }, { - label: "重命名", + label: t("myImageView.contextMenu.single.edit"), icon: "mdi:rename-outline", command: () => { - showImageRenameDialog.value = true; + showImageEditDialog.value = true; } }, { - label: "删除", + label: t("myImageView.contextMenu.single.delete"), icon: "mdi:delete-outline", command: () => { isSingleImageDelete.value = true; @@ -345,7 +340,7 @@ const singleImageContextMenuItems = ref([ ]); const multiImageContextMenuItems = ref([ { - label: "移动到相册", + label: t("myImageView.contextMenu.multi.moveToAlbum"), icon: "mdi:move-to-inbox", command: () => { isSingleImageChangeAlbum.value = false; @@ -353,14 +348,14 @@ const multiImageContextMenuItems = ref([ } }, { - label: "设为公开", + label: t("myImageView.contextMenu.multi.settingAsPublic"), icon: "mdi:visibility-outline", command: () => { handleMultiChangeVisibility(false); } }, { - label: "设为私密", + label: t("myImageView.contextMenu.multi.settingAsPrivate"), icon: "mdi:visibility-off-outline", command: () => { handleMultiChangeVisibility(true); @@ -370,7 +365,7 @@ const multiImageContextMenuItems = ref([ separator: true }, { - label: "删除", + label: t("myImageView.contextMenu.multi.delete"), icon: "mdi:delete-outline", command: () => { isSingleImageDelete.value = false; @@ -381,11 +376,9 @@ const multiImageContextMenuItems = ref([ const showImageDetailDialog = ref(false); const showImageChangeAlbumDialog = ref(false); -const showImageRenameDialog = ref(false); +const showImageEditDialog = ref(false); const showImageDeleteConfirmDialog = ref(false); -const newImageName = ref(""); - const albumPage = ref(1); const albumPageSize = ref(10); const albumPageRequest = computed(() => { @@ -459,8 +452,7 @@ function handleSingleImageChangeAlbumDialogSubmit() { if (selectedAlbum.value === undefined) { toast.add({ severity: "warn", - summary: "Warning", - detail: t("myImageView.myImageDialogImageChangeAlbumWarningMessage"), + summary: t("myImageView.changeAlbum.dialog.form.verify.album.required"), life: 3000 }); return; @@ -476,8 +468,7 @@ function handleMultiImageChangeAlbumDialogSubmit() { if (selectedAlbum.value === undefined) { toast.add({ severity: "warn", - summary: "Warning", - detail: t("myImageView.myImageDialogImageChangeAlbumWarningMessage"), + summary: t("myImageView.changeAlbum.dialog.form.verify.album.required"), life: 3000 }); return; @@ -497,7 +488,7 @@ function handleImageDetail() { }); } -async function handleSingleChangeAlbum(imageId: number, albumId: number): Promise { +async function handleSingleChangeAlbum(imageId: number, albumId: number) { return imageApi .apiImageImageIdPatch({ imageId: imageId, @@ -510,14 +501,13 @@ async function handleSingleChangeAlbum(imageId: number, albumId: number): Promis if (resp.isSuccessful) { toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageChangeAlbumSuccessMessage"), + summary: t("myImageView.changeAlbum.toast.successTitle"), life: 3000 }); } else { toast.add({ severity: "warn", - summary: t("myImageView.myImageDialogImageChangeAlbumFailedTitle"), + summary: t("myImageView.changeAlbum.toast.failedTitle"), detail: `imageId: ${imageDisplayList.value[curRightClickImageIdx.value].id}, ${resp.message}`, life: 3000 }); @@ -542,15 +532,14 @@ function handleSingleChangeVisibility(isPrivate: boolean) { if (resp.isSuccessful) { toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageChangeVisibleSuccessMessage"), + summary: t("myImageView.changeVisible.toast.successTitle"), life: 3000 }); pageUserImage(pageRequest.value); } else { toast.add({ severity: "warn", - summary: t("myImageView.myImageDialogImageChangeVisibleFailedTitle"), + summary: t("myImageView.changeVisible.toast.failedTitle"), detail: `imageId: ${imageDisplayList.value[curRightClickImageIdx.value].id}, ${resp.message}`, life: 3000 }); @@ -577,14 +566,13 @@ function handleMultiChangeVisibility(isPrivate: boolean) { if (resp.isSuccessful) { toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageChangeVisibleSuccessMessage"), + summary: t("myImageView.changeVisible.toast.successTitle"), life: 3000 }); } else { toast.add({ severity: "warn", - summary: t("myImageView.myImageDialogImageChangeVisibleFailedTitle"), + summary: t("myImageView.changeVisible.toast.failedTitle"), detail: `imageId: ${imageDisplayList.value[curRightClickImageIdx.value].id}, ${resp.message}`, life: 3000 }); @@ -603,34 +591,39 @@ function handleMultiChangeVisibility(isPrivate: boolean) { }); } -function handleRenameImage() { - imageApi - .apiImageImageIdPatch({ - imageId: curRightClickImageId.value, - imagePatchRequest: { - displayName: newImageName.value - } - }) +const onEditFormSubmit = (values: any) => { + const patchRequest: ImageApiApiImageImageIdPatchRequest = { + imageId: curRightClickImageId.value, + imagePatchRequest: { + displayName: values.name, + description: values.description + } + }; + handleRenameImage(patchRequest).then(() => { + showImageEditDialog.value = false; + }); +}; + +async function handleRenameImage(patchRequest: ImageApiApiImageImageIdPatchRequest) { + return imageApi + .apiImageImageIdPatch(patchRequest) .then((response) => { const resp = response.data; if (resp.isSuccessful) { toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageRenameSuccessMessage"), + summary: t("myImageView.edit.toast.successTitle"), life: 3000 }); pageUserImage(pageRequest.value); } else { toast.add({ severity: "warn", - summary: t("myImageView.myImageDialogImageRenameFailedTitle"), + summary: t("myImageView.edit.toast.failedTitle"), detail: resp.message, life: 3000 }); } - showImageRenameDialog.value = false; - newImageName.value = ""; }) .catch((e) => { console.error(e); @@ -646,15 +639,14 @@ function handleDeleteSingleImage() { if (resp.isSuccessful) { toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageDeleteConfirmSuccessTitle"), + summary: t("myImageView.delete.toast.successTitle"), life: 3000 }); pageUserImage(pageRequest.value); } else { toast.add({ severity: "warn", - summary: t("myImageView.myImageDialogImageDeleteConfirmFailedTitle"), + summary: t("myImageView.delete.toast.failedTitle"), detail: resp.message, life: 3000 }); @@ -665,7 +657,7 @@ function handleDeleteSingleImage() { console.error(e); toast.add({ severity: "error", - summary: t("myImageView.myImageDialogImageDeleteConfirmFailedTitle"), + summary: "Error", detail: e.message, life: 3000 }); @@ -682,14 +674,13 @@ function handleDeleteMultiImage() { if (resp.isSuccessful) { toast.add({ severity: "success", - summary: "Success", - detail: t("myImageView.myImageDialogImageDeleteConfirmSuccessTitle"), + summary: t("myImageView.delete.toast.successTitle"), life: 3000 }); } else { toast.add({ severity: "warn", - summary: t("myImageView.myImageDialogImageDeleteConfirmFailedTitle"), + summary: t("myImageView.delete.toast.failedTitle"), detail: resp.message, life: 3000 }); @@ -756,6 +747,13 @@ async function fetchImageInfo(imageId: number): Promise { const resp = response.data!; if (resp.isSuccessful) { imageInfo.value = resp.data!; + } else { + toast.add({ + severity: "warn", + summary: t("myImageView.detail.toast.failedTitle"), + detail: resp.message, + life: 3000 + }); } }) .catch((error) => { @@ -822,7 +820,7 @@ async function fetchThumbnails() { }) ); const results = await Promise.all(promises); - imageDisplayList.value = results.filter(item => item !== null); + imageDisplayList.value = results.filter((item) => item !== null); } @@ -835,7 +833,7 @@ async function fetchThumbnails() { @click="handleShowAlbumDrawer" > - {{ t("myImageView.myImageFilterAlbumButton") }} + {{ t("myImageView.filter.album.button") }} @@ -881,7 +879,15 @@ async function fetchThumbnails() { @dblclick="showRawImage(idx)" @contextmenu="handleImageRightClick($event, imageDisplay.id, idx)" /> - + @@ -892,338 +898,330 @@ async function fetchThumbnails() { :cur-page="curPage" :total-record="totalRecord" /> + - - -
- - - - + + +
+ + + + +
+
+ + +
+ + + +
+
+ + +