feat: add head_images
This commit is contained in:
@@ -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}`;
|
||||
},
|
||||
};
|
||||
@@ -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'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -229,6 +271,36 @@ const formatFileSize = (bytes) => {
|
||||
|
||||
<div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Add Head Images Selection before Title -->
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">展示图片</label>
|
||||
<div class="p-4 border border-gray-200 rounded-md">
|
||||
<div v-if="post.head_images.length === 0"
|
||||
class="flex justify-center items-center flex-col space-y-3 py-6">
|
||||
<i class="pi pi-image text-gray-400 text-5xl!"></i>
|
||||
<p class="text-gray-500">请选择展示图片</p>
|
||||
<Button label="选择图片" icon="pi pi-plus" @click="openMediaDialog('headImages')" outlined />
|
||||
<small v-if="errors.head_images" class="text-red-500">{{ errors.head_images }}</small>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="mb-4">
|
||||
<Button label="更换图片" icon="pi pi-plus" @click="openMediaDialog('headImages')"
|
||||
outlined />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<div v-for="(media, index) in post.head_images" :key="media.id"
|
||||
class="relative group aspect-video">
|
||||
<img v-if="headImageUrls[index]" :src="headImageUrls[index].url"
|
||||
class="w-full h-full object-cover rounded" :alt="media.name">
|
||||
<Button icon="pi pi-times"
|
||||
class="absolute top-2 right-2 p-button-rounded p-button-danger p-button-sm opacity-0 group-hover:opacity-100"
|
||||
@click="removeHeadImage(media)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<div class="col-span-2">
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 mb-1">标题</label>
|
||||
|
||||
Reference in New Issue
Block a user