mirror of https://github.com/halo-dev/halo
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
parent
e8a9f063f1
commit
6ee5503643
|
@ -27,7 +27,7 @@ import { useRouteQuery } from "@vueuse/router";
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { randomUUID } from "@/utils/id";
|
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 { useEditorExtensionPoints } from "@/composables/use-editor-extension-points";
|
||||||
import type { EditorProvider } from "@halo-dev/console-shared";
|
import type { EditorProvider } from "@halo-dev/console-shared";
|
||||||
import { useLocalStorage } from "@vueuse/core";
|
import { useLocalStorage } from "@vueuse/core";
|
||||||
|
@ -36,7 +36,7 @@ import { useI18n } from "vue-i18n";
|
||||||
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
|
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
|
||||||
import { contentAnnotations } from "@/constants/annotations";
|
import { contentAnnotations } from "@/constants/annotations";
|
||||||
import { usePageUpdateMutate } from "./composables/use-page-update-mutate";
|
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 { useContentSnapshot } from "@console/composables/use-content-snapshot";
|
||||||
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
|
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
|
||||||
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { apiClient } from "@/utils/api-client";
|
||||||
import { useRouteQuery } from "@vueuse/router";
|
import { useRouteQuery } from "@vueuse/router";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { randomUUID } from "@/utils/id";
|
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 { useEditorExtensionPoints } from "@/composables/use-editor-extension-points";
|
||||||
import type { EditorProvider } from "@halo-dev/console-shared";
|
import type { EditorProvider } from "@halo-dev/console-shared";
|
||||||
import { useLocalStorage } from "@vueuse/core";
|
import { useLocalStorage } from "@vueuse/core";
|
||||||
|
@ -36,7 +36,7 @@ import { useI18n } from "vue-i18n";
|
||||||
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
|
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
|
||||||
import { usePostUpdateMutate } from "./composables/use-post-update-mutate";
|
import { usePostUpdateMutate } from "./composables/use-post-update-mutate";
|
||||||
import { contentAnnotations } from "@/constants/annotations";
|
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 { useContentSnapshot } from "@console/composables/use-content-snapshot";
|
||||||
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
|
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
|
||||||
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
VSpace,
|
VSpace,
|
||||||
} from "@halo-dev/components";
|
} from "@halo-dev/components";
|
||||||
import EditorProviderSelector from "@/components/dropdown-selector/EditorProviderSelector.vue";
|
import EditorProviderSelector from "@/components/dropdown-selector/EditorProviderSelector.vue";
|
||||||
import { ref } from "vue";
|
import { ref, toRef } from "vue";
|
||||||
import { useLocalStorage } from "@vueuse/core";
|
import { useLocalStorage } from "@vueuse/core";
|
||||||
import type { Post, Content, Snapshot } from "@halo-dev/api-client";
|
import type { Post, Content, Snapshot } from "@halo-dev/api-client";
|
||||||
import { randomUUID } from "@/utils/id";
|
import { randomUUID } from "@/utils/id";
|
||||||
|
@ -35,6 +35,8 @@ import type { ComputedRef } from "vue";
|
||||||
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
||||||
import { usePermission } from "@/utils/permission";
|
import { usePermission } from "@/utils/permission";
|
||||||
import type { AxiosRequestConfig } from "axios";
|
import type { AxiosRequestConfig } from "axios";
|
||||||
|
import { useContentCache } from "@/composables/use-content-cache";
|
||||||
|
import { useAutoSaveContent } from "@/composables/use-auto-save-content";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -126,6 +128,7 @@ onMounted(async () => {
|
||||||
formState.value = post;
|
formState.value = post;
|
||||||
|
|
||||||
await handleFetchContent();
|
await handleFetchContent();
|
||||||
|
handleResetCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +145,48 @@ onMounted(async () => {
|
||||||
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
|
[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
|
// Update route query params
|
||||||
name.value = data.metadata.name;
|
name.value = data.metadata.name;
|
||||||
await handleFetchContent();
|
await handleFetchContent();
|
||||||
|
handleClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save post
|
// Save post
|
||||||
|
@ -276,6 +322,7 @@ const { mutateAsync: handleSave, isLoading: isSaving } = useMutation({
|
||||||
onSuccess(_, variables) {
|
onSuccess(_, variables) {
|
||||||
if (!variables.mute) Toast.success(t("core.common.toast.save_success"));
|
if (!variables.mute) Toast.success(t("core.common.toast.save_success"));
|
||||||
handleFetchContent();
|
handleFetchContent();
|
||||||
|
handleClearCache(name.value);
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
Toast.error(t("core.common.toast.save_failed_and_retry"));
|
Toast.error(t("core.common.toast.save_failed_and_retry"));
|
||||||
|
@ -297,6 +344,7 @@ function handlePublishClick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPublishPostSuccess() {
|
function onPublishPostSuccess() {
|
||||||
|
handleClearCache();
|
||||||
router.push({ name: "Posts" });
|
router.push({ name: "Posts" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +361,7 @@ const { mutateAsync: handlePublish, isLoading: isPublishing } = useMutation({
|
||||||
Toast.success(t("core.common.toast.publish_success"), {
|
Toast.success(t("core.common.toast.publish_success"), {
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
});
|
});
|
||||||
|
handleClearCache(formState.value.metadata.name);
|
||||||
router.push({ name: "Posts" });
|
router.push({ name: "Posts" });
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
|
@ -332,6 +380,7 @@ function handleOpenPostSettingEditModal() {
|
||||||
function onUpdatePostSuccess(data: Post) {
|
function onUpdatePostSuccess(data: Post) {
|
||||||
formState.value = data;
|
formState.value = data;
|
||||||
handleFetchContent();
|
handleFetchContent();
|
||||||
|
handleClearCache(data.metadata.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload image
|
// Upload image
|
||||||
|
@ -433,6 +482,7 @@ useSessionKeepAlive();
|
||||||
v-model:content="content.content"
|
v-model:content="content.content"
|
||||||
:upload-image="handleUploadImage"
|
:upload-image="handleUploadImage"
|
||||||
class="h-full"
|
class="h-full"
|
||||||
|
@update="handleSetContentCache"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue