From 55ae68be34914f4f4160fee2548f3453d8a7f013 Mon Sep 17 00:00:00 2001 From: yanghao05 Date: Fri, 18 Apr 2025 15:31:37 +0800 Subject: [PATCH] feat: add head_images --- backend/app/middlewares/mid_auth.go | 5 +- frontend/admin/src/api/mediaService.js | 3 +- frontend/admin/src/pages/PostCreatePage.vue | 82 +++++++++++++++++++-- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/backend/app/middlewares/mid_auth.go b/backend/app/middlewares/mid_auth.go index fc2a826..cf2d7e2 100644 --- a/backend/app/middlewares/mid_auth.go +++ b/backend/app/middlewares/mid_auth.go @@ -18,7 +18,10 @@ func (f *Middlewares) Auth(ctx fiber.Ctx) error { if strings.HasPrefix(ctx.Path(), "/v1/admin/") { token := ctx.Get("Authorization") if token == "" { - return ctx.Status(fiber.StatusUnauthorized).SendString("Unauthorized") + token = ctx.Query("token") + if token == "" { + return ctx.Status(fiber.StatusUnauthorized).SendString("Unauthorized") + } } jwt, err := f.jwt.Parse(token) if err != nil { diff --git a/frontend/admin/src/api/mediaService.js b/frontend/admin/src/api/mediaService.js index 3ed4070..e73991f 100644 --- a/frontend/admin/src/api/mediaService.js +++ b/frontend/admin/src/api/mediaService.js @@ -22,6 +22,7 @@ export const mediaService = { }, getMediaPreviewUrl(id) { - return `${httpClient.defaults.baseURL}/admin/medias/${id}`; + const token = localStorage.getItem('__token'); + return `${httpClient.defaults.baseURL}/admin/medias/${id}?token=${token}`; }, }; \ No newline at end of file diff --git a/frontend/admin/src/pages/PostCreatePage.vue b/frontend/admin/src/pages/PostCreatePage.vue index 11cc85b..8b6b9db 100644 --- a/frontend/admin/src/pages/PostCreatePage.vue +++ b/frontend/admin/src/pages/PostCreatePage.vue @@ -30,6 +30,7 @@ const post = reactive({ selectedMedia: [], medias: [], status: 0, + head_images: [], // Add head images array }); // Validation state @@ -37,9 +38,12 @@ const errors = reactive({ title: '', introduction: '', selectedMedia: '', - discount: '' + discount: '', + head_images: '', }); +const headImageUrls = ref([]); // Store preview URLs + // Media selection dialog state const mediaDialogVisible = ref(false); const selectedMediaItems = ref([]); @@ -64,7 +68,8 @@ const statusOptions = [ ]; // Open media selection dialog -const openMediaDialog = () => { +const openMediaDialog = (target = 'content') => { + mediaSelectionTarget.value = target; mediaDialogVisible.value = true; mediaCurrentPage.value = 1; mediaFirst.value = 0; @@ -100,8 +105,14 @@ const onMediaPage = (event) => { // Confirm media selection const confirmMediaSelection = () => { if (selectedMediaItems.value.length) { - post.selectedMedia = [...selectedMediaItems.value]; - errors.selectedMedia = ''; + if (mediaSelectionTarget.value === 'headImages') { + post.head_images = [...selectedMediaItems.value]; + errors.head_images = ''; + loadHeadImagePreviews(); + } else { + post.selectedMedia = [...selectedMediaItems.value]; + errors.selectedMedia = ''; + } } mediaDialogVisible.value = false; }; @@ -119,6 +130,15 @@ const removeMedia = (media) => { } }; +// Remove head image +const removeHeadImage = (media) => { + const index = post.head_images.findIndex(item => item.id === media.id); + if (index > -1) { + post.head_images.splice(index, 1); + loadHeadImagePreviews(); + } +}; + // Save the post const savePost = async () => { // Reset errors @@ -149,13 +169,19 @@ const savePost = async () => { valid = false; } + if (post.head_images.length === 0) { + errors.head_images = '请选择至少一张展示图片'; + valid = false; + } + if (!valid) { toast.add({ severity: 'error', summary: '表单错误', detail: '请检查表单中的错误并修正', life: 3000 }); return; } try { - post.medias = post.selectedMedia.map(media => media.id) + post.medias = post.selectedMedia.map(media => media.id); + post.head_image_ids = post.head_images.map(media => media.id); // Add head image IDs const resp = await postService.createPost(post); console.log(resp) @@ -213,6 +239,22 @@ const formatFileSize = (bytes) => { size = size / Math.pow(base, i); return `${size.toFixed(2)} ${sizes[i]}`; }; + +// Add head image preview loading +const loadHeadImagePreviews = async () => { + headImageUrls.value = []; + for (const media of post.head_images) { + try { + const url = await mediaService.getMediaPreviewUrl(media.id); + headImageUrls.value.push({ id: media.id, url }); + } catch (error) { + console.error('Failed to load preview for media:', media.id); + } + } +}; + +// Add media selection target +const mediaSelectionTarget = ref('content'); // 'content' or 'headImages'