feat: restore postcreate.js
This commit is contained in:
@@ -20,4 +20,8 @@ export const mediaService = {
|
|||||||
uploadedSuccess(data) {
|
uploadedSuccess(data) {
|
||||||
return httpClient.post('/admin/uploads/post-uploaded-action', data);
|
return httpClient.post('/admin/uploads/post-uploaded-action', data);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getMediaPreviewUrl(id) {
|
||||||
|
return `${httpClient.defaults.baseURL}/admin/medias/${id}`;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
@@ -30,7 +30,6 @@ const post = reactive({
|
|||||||
selectedMedia: [],
|
selectedMedia: [],
|
||||||
medias: [],
|
medias: [],
|
||||||
status: 0,
|
status: 0,
|
||||||
head_image: null, // Add head image field
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Validation state
|
// Validation state
|
||||||
@@ -38,8 +37,7 @@ const errors = reactive({
|
|||||||
title: '',
|
title: '',
|
||||||
introduction: '',
|
introduction: '',
|
||||||
selectedMedia: '',
|
selectedMedia: '',
|
||||||
discount: '',
|
discount: ''
|
||||||
head_image: '', // Add head image error field
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Media selection dialog state
|
// Media selection dialog state
|
||||||
@@ -48,7 +46,6 @@ const selectedMediaItems = ref([]);
|
|||||||
const mediaLoading = ref(false);
|
const mediaLoading = ref(false);
|
||||||
const mediaGlobalFilter = ref('');
|
const mediaGlobalFilter = ref('');
|
||||||
const mediaItems = ref([]);
|
const mediaItems = ref([]);
|
||||||
const isHeadImageSelection = ref(false); // Track if we're selecting head image
|
|
||||||
|
|
||||||
// Add pagination state for media dialog
|
// Add pagination state for media dialog
|
||||||
const mediaFirst = ref(0);
|
const mediaFirst = ref(0);
|
||||||
@@ -66,18 +63,8 @@ const statusOptions = [
|
|||||||
{ label: '草稿', value: 0 }
|
{ label: '草稿', value: 0 }
|
||||||
];
|
];
|
||||||
|
|
||||||
// Open media selection dialog for head image
|
|
||||||
const openHeadImageDialog = () => {
|
|
||||||
isHeadImageSelection.value = true;
|
|
||||||
mediaDialogVisible.value = true;
|
|
||||||
mediaCurrentPage.value = 1;
|
|
||||||
mediaFirst.value = 0;
|
|
||||||
loadMediaItems();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Open media selection dialog
|
// Open media selection dialog
|
||||||
const openMediaDialog = () => {
|
const openMediaDialog = () => {
|
||||||
isHeadImageSelection.value = false;
|
|
||||||
mediaDialogVisible.value = true;
|
mediaDialogVisible.value = true;
|
||||||
mediaCurrentPage.value = 1;
|
mediaCurrentPage.value = 1;
|
||||||
mediaFirst.value = 0;
|
mediaFirst.value = 0;
|
||||||
@@ -112,16 +99,10 @@ const onMediaPage = (event) => {
|
|||||||
|
|
||||||
// Confirm media selection
|
// Confirm media selection
|
||||||
const confirmMediaSelection = () => {
|
const confirmMediaSelection = () => {
|
||||||
if (isHeadImageSelection.value) {
|
if (selectedMediaItems.value.length) {
|
||||||
if (selectedMediaItems.value.length) {
|
|
||||||
post.head_image = selectedMediaItems.value[0];
|
|
||||||
errors.head_image = '';
|
|
||||||
}
|
|
||||||
} else if (selectedMediaItems.value.length) {
|
|
||||||
post.selectedMedia = [...selectedMediaItems.value];
|
post.selectedMedia = [...selectedMediaItems.value];
|
||||||
errors.selectedMedia = '';
|
errors.selectedMedia = '';
|
||||||
}
|
}
|
||||||
selectedMediaItems.value = [];
|
|
||||||
mediaDialogVisible.value = false;
|
mediaDialogVisible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,11 +119,6 @@ const removeMedia = (media) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove head image
|
|
||||||
const removeHeadImage = () => {
|
|
||||||
post.head_image = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save the post
|
// Save the post
|
||||||
const savePost = async () => {
|
const savePost = async () => {
|
||||||
// Reset errors
|
// Reset errors
|
||||||
@@ -173,19 +149,13 @@ const savePost = async () => {
|
|||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!post.head_image) {
|
|
||||||
errors.head_image = '请选择封面图片';
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
toast.add({ severity: 'error', summary: '表单错误', detail: '请检查表单中的错误并修正', life: 3000 });
|
toast.add({ severity: 'error', summary: '表单错误', detail: '请检查表单中的错误并修正', life: 3000 });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
post.medias = post.selectedMedia.map(media => media.id);
|
post.medias = post.selectedMedia.map(media => media.id)
|
||||||
post.head_image_id = post.head_image.id; // Add head image ID to submission
|
|
||||||
const resp = await postService.createPost(post);
|
const resp = await postService.createPost(post);
|
||||||
console.log(resp)
|
console.log(resp)
|
||||||
|
|
||||||
@@ -259,34 +229,6 @@ const formatFileSize = (bytes) => {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<!-- Head Image -->
|
|
||||||
<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_image" 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="openHeadImageDialog" outlined />
|
|
||||||
<small v-if="errors.head_image" class="text-red-500">{{ errors.head_image }}</small>
|
|
||||||
</div>
|
|
||||||
<div v-else class="relative">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<img :src="post.head_image.thumbnailUrl" class="w-32 h-32 object-cover rounded mr-4"
|
|
||||||
:alt="post.head_image.name">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<span class="font-medium">{{ post.head_image.name }}</span>
|
|
||||||
<div class="flex gap-2 mt-2">
|
|
||||||
<Button label="更换图片" icon="pi pi-sync" @click="openHeadImageDialog" outlined
|
|
||||||
size="small" />
|
|
||||||
<Button label="移除" icon="pi pi-times" severity="danger" outlined size="small"
|
|
||||||
@click="removeHeadImage" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<label for="title" class="block text-sm font-medium text-gray-700 mb-1">标题</label>
|
<label for="title" class="block text-sm font-medium text-gray-700 mb-1">标题</label>
|
||||||
@@ -374,15 +316,15 @@ const formatFileSize = (bytes) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Media Selection Dialog -->
|
<!-- Media Selection Dialog -->
|
||||||
<Dialog v-model:visible="mediaDialogVisible" :header="isHeadImageSelection ? '选择封面图片' : '选择媒体'" :modal="true"
|
<Dialog v-model:visible="mediaDialogVisible" header="选择媒体" :modal="true" :dismissableMask="true" :closable="true"
|
||||||
:dismissableMask="true" :closable="true" :style="{ width: '80vw' }" :breakpoints="{ '960px': '90vw' }">
|
:style="{ width: '80vw' }" :breakpoints="{ '960px': '90vw' }">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<InputText v-model="mediaGlobalFilter" placeholder="搜索媒体..." class="w-full" />
|
<InputText v-model="mediaGlobalFilter" placeholder="搜索媒体..." class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DataTable v-model:selection="selectedMediaItems" :value="mediaItems" :loading="mediaLoading" dataKey="id"
|
<DataTable v-model:selection="selectedMediaItems" :value="mediaItems" :loading="mediaLoading" dataKey="id"
|
||||||
:paginator="true" v-model:first="mediaFirst" v-model:rows="mediaRows" :totalRecords="mediaTotalRecords"
|
:paginator="true" v-model:first="mediaFirst" v-model:rows="mediaRows" :totalRecords="mediaTotalRecords"
|
||||||
@page="onMediaPage" :selectionMode="isHeadImageSelection ? 'single' : 'multiple'"
|
@page="onMediaPage" selectionMode="multiple"
|
||||||
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport"
|
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport"
|
||||||
:rows-per-page-options="[10, 25, 50]" currentPageReportTemplate="第 {first} 到 {last} 条,共 {totalRecords} 条"
|
:rows-per-page-options="[10, 25, 50]" currentPageReportTemplate="第 {first} 到 {last} 条,共 {totalRecords} 条"
|
||||||
:lazy="true" :showCurrentPageReport="true">
|
:lazy="true" :showCurrentPageReport="true">
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useAuthStore } from '@/stores/auth';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
// Create axios instance with default config
|
// Create axios instance with default config
|
||||||
@@ -13,10 +12,6 @@ const client = axios.create({
|
|||||||
// Request interceptor
|
// Request interceptor
|
||||||
client.interceptors.request.use(
|
client.interceptors.request.use(
|
||||||
config => {
|
config => {
|
||||||
const authStore = useAuthStore();
|
|
||||||
if (authStore.isAuthenticated && authStore.token) {
|
|
||||||
config.headers.Authorization = `Bearer ${authStore.token}`;
|
|
||||||
}
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
|
|||||||
Reference in New Issue
Block a user