mirror of https://github.com/halo-dev/halo-admin
parent
dc101e8183
commit
fd56f24b1f
|
@ -14,8 +14,6 @@ import { apiClient } from "@halo-dev/admin-shared";
|
|||
import { useRouteQuery } from "@vueuse/router";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
const name = useRouteQuery("name");
|
||||
|
||||
const initialFormState: PostRequest = {
|
||||
post: {
|
||||
spec: {
|
||||
|
@ -60,10 +58,13 @@ const isUpdateMode = computed(() => {
|
|||
return !!formState.value.post.metadata.creationTimestamp;
|
||||
});
|
||||
|
||||
const handleSavePost = async () => {
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
|
||||
// Set rendered content
|
||||
formState.value.content.content = formState.value.content.raw;
|
||||
|
||||
if (isUpdateMode.value) {
|
||||
const { data } = await apiClient.post.updateDraftPost(
|
||||
formState.value.post.metadata.name,
|
||||
|
@ -75,20 +76,38 @@ const handleSavePost = async () => {
|
|||
formState.value.post = data;
|
||||
name.value = data.metadata.name;
|
||||
}
|
||||
|
||||
await handleFetchContent();
|
||||
} catch (e) {
|
||||
alert(`保存异常: ${e}`);
|
||||
console.error("Failed to save post", e);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onSettingSaved = (post: PostRequest) => {
|
||||
formState.value = post;
|
||||
settingModal.value = false;
|
||||
handleSavePost();
|
||||
const handleFetchContent = async () => {
|
||||
if (!formState.value.post.spec.headSnapshot) {
|
||||
return;
|
||||
}
|
||||
const { data } = await apiClient.content.obtainSnapshotContent(
|
||||
formState.value.post.spec.headSnapshot
|
||||
);
|
||||
|
||||
formState.value.content = data;
|
||||
};
|
||||
|
||||
const onSettingSaved = (post: PostRequest) => {
|
||||
// Set route query parameter
|
||||
if (!isUpdateMode.value) {
|
||||
name.value = post.post.metadata.name;
|
||||
}
|
||||
|
||||
formState.value = post;
|
||||
settingModal.value = false;
|
||||
};
|
||||
|
||||
// Get post data when the route contains the name parameter
|
||||
const name = useRouteQuery("name");
|
||||
onMounted(async () => {
|
||||
if (name.value) {
|
||||
// fetch post
|
||||
|
@ -98,12 +117,8 @@ onMounted(async () => {
|
|||
);
|
||||
formState.value.post = post;
|
||||
|
||||
if (formState.value.post.spec.headSnapshot) {
|
||||
const { data: content } = await apiClient.content.obtainSnapshotContent(
|
||||
formState.value.post.spec.headSnapshot
|
||||
);
|
||||
formState.value.content = content;
|
||||
}
|
||||
// fetch post content
|
||||
await handleFetchContent();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -111,7 +126,6 @@ onMounted(async () => {
|
|||
<template>
|
||||
<PostSettingModal
|
||||
v-model:visible="settingModal"
|
||||
:only-emit="true"
|
||||
:post="formState"
|
||||
@saved="onSettingSaved"
|
||||
/>
|
||||
|
@ -121,12 +135,7 @@ onMounted(async () => {
|
|||
</template>
|
||||
<template #actions>
|
||||
<VSpace>
|
||||
<VButton
|
||||
:loading="saving"
|
||||
size="sm"
|
||||
type="default"
|
||||
@click="handleSavePost"
|
||||
>
|
||||
<VButton :loading="saving" size="sm" type="default" @click="handleSave">
|
||||
保存
|
||||
</VButton>
|
||||
<VButton type="secondary" @click="settingModal = true">
|
||||
|
|
|
@ -101,13 +101,17 @@ const handlePaginationChange = ({
|
|||
handleFetchPosts();
|
||||
};
|
||||
|
||||
const handleOpenSettingModal = (post: Post) => {
|
||||
selectedPost.value = post;
|
||||
const handleOpenSettingModal = async (post: Post) => {
|
||||
const { data } = await apiClient.extension.post.getcontentHaloRunV1alpha1Post(
|
||||
post.metadata.name
|
||||
);
|
||||
selectedPost.value = data;
|
||||
settingModal.value = true;
|
||||
};
|
||||
|
||||
const onSettingModalClose = () => {
|
||||
selectedPost.value = null;
|
||||
selectedPostWithContent.value = null;
|
||||
handleFetchPosts();
|
||||
};
|
||||
|
||||
|
@ -117,7 +121,11 @@ const handleSelectPrevious = async () => {
|
|||
(post) => post.post.metadata.name === selectedPost.value?.metadata.name
|
||||
);
|
||||
if (index > 0) {
|
||||
selectedPost.value = items[index - 1].post;
|
||||
const { data } =
|
||||
await apiClient.extension.post.getcontentHaloRunV1alpha1Post(
|
||||
items[index - 1].post.metadata.name
|
||||
);
|
||||
selectedPost.value = data;
|
||||
return;
|
||||
}
|
||||
if (index === 0 && hasPrevious) {
|
||||
|
@ -133,7 +141,11 @@ const handleSelectNext = async () => {
|
|||
(post) => post.post.metadata.name === selectedPost.value?.metadata.name
|
||||
);
|
||||
if (index < items.length - 1) {
|
||||
selectedPost.value = items[index + 1].post;
|
||||
const { data } =
|
||||
await apiClient.extension.post.getcontentHaloRunV1alpha1Post(
|
||||
items[index + 1].post.metadata.name
|
||||
);
|
||||
selectedPost.value = data;
|
||||
return;
|
||||
}
|
||||
if (index === items.length - 1 && hasNext) {
|
||||
|
@ -625,7 +637,7 @@ function handlePhaseFilterItemChange(filterItem: FilterItem) {
|
|||
<template #actions>
|
||||
<VSpace>
|
||||
<VButton @click="handleFetchPosts">刷新</VButton>
|
||||
<VButton type="primary" :route="{ name: 'PostEditor' }">
|
||||
<VButton :route="{ name: 'PostEditor' }" type="primary">
|
||||
<template #icon>
|
||||
<IconAddCircle class="h-full w-full" />
|
||||
</template>
|
||||
|
|
|
@ -88,6 +88,12 @@ const onVisibleChange = (visible: boolean) => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleResetForm = () => {
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
formState.value.metadata.name = uuid();
|
||||
reset("category-form");
|
||||
};
|
||||
|
||||
const { Command_Enter } = useMagicKeys();
|
||||
|
||||
watchEffect(() => {
|
||||
|
@ -99,13 +105,20 @@ watchEffect(() => {
|
|||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible && props.category) {
|
||||
formState.value = cloneDeep(props.category);
|
||||
return;
|
||||
if (!visible) {
|
||||
handleResetForm();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.category,
|
||||
(category) => {
|
||||
if (category) {
|
||||
formState.value = cloneDeep(category);
|
||||
} else {
|
||||
handleResetForm();
|
||||
}
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
reset("category-form");
|
||||
formState.value.metadata.name = uuid();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -88,7 +88,9 @@ function onDelete(category: CategoryTree) {
|
|||
</div>
|
||||
<template #popper> 删除中</template>
|
||||
</FloatingTooltip>
|
||||
<!--TODO: Get post count-->
|
||||
<div
|
||||
v-if="false"
|
||||
class="cursor-pointer text-sm text-gray-500 hover:text-gray-900"
|
||||
>
|
||||
20 篇文章
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VModal, VSpace, VTabItem, VTabs } from "@halo-dev/components";
|
||||
import { computed, ref, watch, watchEffect } from "vue";
|
||||
import { computed, ref, watchEffect } from "vue";
|
||||
import type { PostRequest } from "@halo-dev/api-client";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag";
|
||||
|
@ -48,12 +48,10 @@ const props = withDefaults(
|
|||
defineProps<{
|
||||
visible: boolean;
|
||||
post?: PostRequest | null;
|
||||
onlyEmit?: boolean;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
post: null,
|
||||
onlyEmit: false,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -100,11 +98,7 @@ const handleVisibleChange = (visible: boolean) => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleSaveOnly = async () => {
|
||||
if (props.onlyEmit) {
|
||||
emit("saved", formState.value);
|
||||
return;
|
||||
}
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
if (isUpdateMode.value) {
|
||||
|
@ -129,13 +123,24 @@ const handleSaveOnly = async () => {
|
|||
const handlePublish = async () => {
|
||||
try {
|
||||
publishing.value = true;
|
||||
|
||||
// Save post
|
||||
await handleSave();
|
||||
|
||||
// Get latest version post
|
||||
const { data: latestData } =
|
||||
await apiClient.extension.post.getcontentHaloRunV1alpha1Post(
|
||||
formState.value.post.metadata.name
|
||||
);
|
||||
formState.value.post = latestData;
|
||||
|
||||
// Publish post
|
||||
const { data } = await apiClient.post.publishPost(
|
||||
formState.value.post.metadata.name
|
||||
);
|
||||
formState.value.post = data;
|
||||
emit("saved", formState.value);
|
||||
} catch (e) {
|
||||
alert(`发布异常: ${e}`);
|
||||
console.error("Failed to publish post", e);
|
||||
} finally {
|
||||
publishing.value = false;
|
||||
|
@ -145,15 +150,22 @@ const handlePublish = async () => {
|
|||
const handlePublishCanceling = async () => {
|
||||
try {
|
||||
publishCanceling.value = true;
|
||||
|
||||
// Update published spec = false
|
||||
const postToUpdate = cloneDeep(formState.value);
|
||||
postToUpdate.post.spec.published = false;
|
||||
|
||||
const { data } = await apiClient.post.updateDraftPost(
|
||||
await apiClient.post.updateDraftPost(
|
||||
postToUpdate.post.metadata.name,
|
||||
postToUpdate
|
||||
);
|
||||
|
||||
formState.value.post = data;
|
||||
// Get latest version post
|
||||
const { data: latestData } =
|
||||
await apiClient.extension.post.getcontentHaloRunV1alpha1Post(
|
||||
formState.value.post.metadata.name
|
||||
);
|
||||
|
||||
formState.value.post = latestData;
|
||||
emit("saved", formState.value);
|
||||
} catch (e) {
|
||||
console.log("Failed to cancel publish", e);
|
||||
|
@ -162,18 +174,6 @@ const handlePublishCanceling = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible && props.post) {
|
||||
formState.value = cloneDeep(props.post);
|
||||
}
|
||||
if (!visible) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.post) {
|
||||
formState.value = cloneDeep(props.post);
|
||||
|
@ -288,27 +288,7 @@ watchEffect(() => {
|
|||
></FormKit>
|
||||
</FormKit>
|
||||
</VTabItem>
|
||||
<VTabItem id="seo" label="SEO">
|
||||
<FormKit id="seo" :actions="false" :preserve="true" type="form">
|
||||
<FormKit
|
||||
label="自定义关键词"
|
||||
name="metaKeywords"
|
||||
type="textarea"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
label="自定义描述"
|
||||
name="metaDescription"
|
||||
type="textarea"
|
||||
></FormKit>
|
||||
</FormKit>
|
||||
</VTabItem>
|
||||
<VTabItem id="metas" label="元数据"></VTabItem>
|
||||
<VTabItem id="inject-code" label="代码注入">
|
||||
<FormKit id="inject-code" :actions="false" :preserve="true" type="form">
|
||||
<FormKit label="CSS" type="textarea"></FormKit>
|
||||
<FormKit label="JavaScript" type="textarea"></FormKit>
|
||||
</FormKit>
|
||||
</VTabItem>
|
||||
<!--TODO: add SEO/Metas/Inject Code form-->
|
||||
</VTabs>
|
||||
|
||||
<template #footer>
|
||||
|
@ -323,7 +303,6 @@ watchEffect(() => {
|
|||
</VButton>
|
||||
<VButton
|
||||
v-else
|
||||
:disabled="!isUpdateMode"
|
||||
:loading="publishing"
|
||||
type="secondary"
|
||||
@click="handlePublish"
|
||||
|
@ -334,7 +313,7 @@ watchEffect(() => {
|
|||
:loading="saving"
|
||||
size="sm"
|
||||
type="secondary"
|
||||
@click="handleSaveOnly"
|
||||
@click="handleSave"
|
||||
>
|
||||
仅保存
|
||||
</VButton>
|
||||
|
|
|
@ -207,7 +207,9 @@ onMounted(async () => {
|
|||
</div>
|
||||
<template #popper> 删除中</template>
|
||||
</FloatingTooltip>
|
||||
<!--TODO: Get post count-->
|
||||
<div
|
||||
v-if="false"
|
||||
class="cursor-pointer text-sm text-gray-500 hover:text-gray-900"
|
||||
>
|
||||
20 篇文章
|
||||
|
|
Loading…
Reference in New Issue