pref: adapt auto save functionality for articles in the uc (#5272)

#### What type of PR is this?

/kind improvement
/area console
/milestone 2.12.x

#### What this PR does / why we need it:

为个人中心的文章适配自动保存功能

#### How to test it?

新建一个空白文章,测试当失去焦点、切换路由,或者在页面等待 20S 后,是否会自动创建文章草稿。

#### Which issue(s) this PR fixes:

Fixes #5036 

#### Does this PR introduce a user-facing change?
```release-note
为个人中心的文章适配自动保存功能
```
pull/3818/head^2
Takagi 2024-01-29 17:32:25 +08:00 committed by GitHub
parent e8a9f063f1
commit 6ee5503643
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 56 additions and 6 deletions

View File

@ -27,7 +27,7 @@ import { useRouteQuery } from "@vueuse/router";
import { cloneDeep } from "lodash-es";
import { useRouter } from "vue-router";
import { randomUUID } from "@/utils/id";
import { useContentCache } from "@console/composables/use-content-cache";
import { useContentCache } from "@/composables/use-content-cache";
import { useEditorExtensionPoints } from "@/composables/use-editor-extension-points";
import type { EditorProvider } from "@halo-dev/console-shared";
import { useLocalStorage } from "@vueuse/core";
@ -36,7 +36,7 @@ import { useI18n } from "vue-i18n";
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
import { contentAnnotations } from "@/constants/annotations";
import { usePageUpdateMutate } from "./composables/use-page-update-mutate";
import { useAutoSaveContent } from "@console/composables/use-auto-save-content";
import { useAutoSaveContent } from "@/composables/use-auto-save-content";
import { useContentSnapshot } from "@console/composables/use-content-snapshot";
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";

View File

@ -27,7 +27,7 @@ import { apiClient } from "@/utils/api-client";
import { useRouteQuery } from "@vueuse/router";
import { useRouter } from "vue-router";
import { randomUUID } from "@/utils/id";
import { useContentCache } from "@console/composables/use-content-cache";
import { useContentCache } from "@/composables/use-content-cache";
import { useEditorExtensionPoints } from "@/composables/use-editor-extension-points";
import type { EditorProvider } from "@halo-dev/console-shared";
import { useLocalStorage } from "@vueuse/core";
@ -36,7 +36,7 @@ import { useI18n } from "vue-i18n";
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
import { usePostUpdateMutate } from "./composables/use-post-update-mutate";
import { contentAnnotations } from "@/constants/annotations";
import { useAutoSaveContent } from "@console/composables/use-auto-save-content";
import { useAutoSaveContent } from "@/composables/use-auto-save-content";
import { useContentSnapshot } from "@console/composables/use-content-snapshot";
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";

View File

@ -13,7 +13,7 @@ import {
VSpace,
} from "@halo-dev/components";
import EditorProviderSelector from "@/components/dropdown-selector/EditorProviderSelector.vue";
import { ref } from "vue";
import { ref, toRef } from "vue";
import { useLocalStorage } from "@vueuse/core";
import type { Post, Content, Snapshot } from "@halo-dev/api-client";
import { randomUUID } from "@/utils/id";
@ -35,6 +35,8 @@ import type { ComputedRef } from "vue";
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
import { usePermission } from "@/utils/permission";
import type { AxiosRequestConfig } from "axios";
import { useContentCache } from "@/composables/use-content-cache";
import { useAutoSaveContent } from "@/composables/use-auto-save-content";
const router = useRouter();
const { t } = useI18n();
@ -126,6 +128,7 @@ onMounted(async () => {
formState.value = post;
await handleFetchContent();
handleResetCache();
return;
}
@ -142,6 +145,48 @@ onMounted(async () => {
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
};
}
handleResetCache();
});
const snapshotVersion = computed(() => snapshot.value?.metadata.version || 0);
// Post content cache
const {
currentCache,
handleSetContentCache,
handleResetCache,
handleClearCache,
} = useContentCache(
"post-content-cache",
name,
toRef(content.value, "raw"),
snapshotVersion
);
useAutoSaveContent(currentCache, toRef(content.value, "raw"), async () => {
// Do not save when the setting modal is open
if (postSettingEditModal.value) {
return;
}
if (isUpdateMode.value) {
handleSave({ mute: true });
} else {
formState.value.metadata.annotations = {
...formState.value.metadata.annotations,
[contentAnnotations.CONTENT_JSON]: JSON.stringify(content.value),
};
// Set default title and slug
if (!formState.value.spec.title) {
formState.value.spec.title = t("core.post_editor.untitled");
}
if (!formState.value.spec.slug) {
formState.value.spec.slug = new Date().getTime().toString();
}
const { data: createdPost } = await apiClient.uc.post.createMyPost({
post: formState.value,
});
onCreatePostSuccess(createdPost);
}
});
/**
@ -235,6 +280,7 @@ async function onCreatePostSuccess(data: Post) {
// Update route query params
name.value = data.metadata.name;
await handleFetchContent();
handleClearCache();
}
// Save post
@ -276,6 +322,7 @@ const { mutateAsync: handleSave, isLoading: isSaving } = useMutation({
onSuccess(_, variables) {
if (!variables.mute) Toast.success(t("core.common.toast.save_success"));
handleFetchContent();
handleClearCache(name.value);
},
onError() {
Toast.error(t("core.common.toast.save_failed_and_retry"));
@ -297,6 +344,7 @@ function handlePublishClick() {
}
function onPublishPostSuccess() {
handleClearCache();
router.push({ name: "Posts" });
}
@ -313,7 +361,7 @@ const { mutateAsync: handlePublish, isLoading: isPublishing } = useMutation({
Toast.success(t("core.common.toast.publish_success"), {
duration: 2000,
});
handleClearCache(formState.value.metadata.name);
router.push({ name: "Posts" });
},
onError() {
@ -332,6 +380,7 @@ function handleOpenPostSettingEditModal() {
function onUpdatePostSuccess(data: Post) {
formState.value = data;
handleFetchContent();
handleClearCache(data.metadata.name);
}
// Upload image
@ -433,6 +482,7 @@ useSessionKeepAlive();
v-model:content="content.content"
:upload-image="handleUploadImage"
class="h-full"
@update="handleSetContentCache"
/>
</div>