159 lines
3.8 KiB
JavaScript
159 lines
3.8 KiB
JavaScript
import { ref, nextTick, watch } from 'vue';
|
||
import {
|
||
loadDraftWithFallback,
|
||
saveDraftToStorage,
|
||
removeDraft,
|
||
defaultHasContent
|
||
} from './draftCache.js';
|
||
|
||
/**
|
||
* 页面草稿 Composable:统一 save / restore / clear 流程
|
||
*
|
||
* @param {Object} options
|
||
* @param {() => string} options.getKey 返回 Storage key
|
||
* @param {() => Object} options.getPayload 返回要保存的数据
|
||
* @param {(payload: Object) => boolean} [options.hasContent] 判断是否有有效草稿
|
||
* @param {(payload: Object) => void} options.applyPayload 恢复草稿到表单
|
||
* @param {() => void} options.clearForm 清空表单
|
||
* @param {() => boolean} [options.canSave] 是否允许保存(如 hazardId 未就绪时为 false)
|
||
* @param {boolean} [options.requireInitialized=false] 为 true 时,restore 完成前不自动 save
|
||
* @param {string} [options.restoreToast]
|
||
* @param {string} [options.clearToast]
|
||
* @param {boolean} [options.showRestoreToast=true]
|
||
* @param {(payload: Object) => void} [options.onAfterRestore] 恢复并 apply 后的额外处理
|
||
* @param {() => string[]} [options.getFallbackKeys] 读取草稿时的兼容 key 列表
|
||
*/
|
||
export function useDraftCache(options) {
|
||
const {
|
||
getKey,
|
||
getPayload,
|
||
hasContent = defaultHasContent,
|
||
applyPayload,
|
||
clearForm,
|
||
canSave = () => true,
|
||
requireInitialized = false,
|
||
restoreToast = '已自动恢复您上次未提交的内容',
|
||
clearToast = '草稿已清空',
|
||
showRestoreToast = true,
|
||
onAfterRestore,
|
||
getFallbackKeys
|
||
} = options;
|
||
|
||
const hasDraft = ref(false);
|
||
const showRestoreBanner = ref(false);
|
||
const isRestoring = ref(false);
|
||
const isInitialized = ref(false);
|
||
|
||
const finishRestoreState = (callback) => {
|
||
nextTick(() => {
|
||
isRestoring.value = false;
|
||
isInitialized.value = true;
|
||
callback?.();
|
||
});
|
||
};
|
||
|
||
const save = () => {
|
||
if (isRestoring.value) return;
|
||
if (requireInitialized && !isInitialized.value) return;
|
||
if (!canSave()) return;
|
||
|
||
const key = getKey();
|
||
const payload = getPayload();
|
||
|
||
if (!hasContent(payload)) {
|
||
removeDraft(key);
|
||
hasDraft.value = false;
|
||
return;
|
||
}
|
||
|
||
saveDraftToStorage(key, payload);
|
||
hasDraft.value = true;
|
||
};
|
||
|
||
const clear = (showToast = true) => {
|
||
removeDraft(getKey());
|
||
hasDraft.value = false;
|
||
showRestoreBanner.value = false;
|
||
isRestoring.value = true;
|
||
clearForm();
|
||
finishRestoreState();
|
||
|
||
if (showToast) {
|
||
uni.showToast({ title: clearToast, icon: 'none' });
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 恢复草稿
|
||
* @returns {boolean} 是否成功恢复
|
||
*/
|
||
const restore = () => {
|
||
const key = getKey();
|
||
const { data, fromFallback, fallbackKey } = loadDraftWithFallback(
|
||
key,
|
||
getFallbackKeys?.() || []
|
||
);
|
||
|
||
if (!data || !hasContent(data)) {
|
||
isInitialized.value = true;
|
||
return false;
|
||
}
|
||
|
||
isRestoring.value = true;
|
||
|
||
try {
|
||
applyPayload(data);
|
||
hasDraft.value = true;
|
||
showRestoreBanner.value = true;
|
||
onAfterRestore?.(data);
|
||
|
||
// 从兼容 key 读到后,立即写回标准 key 并清理旧 key
|
||
if (fromFallback && fallbackKey) {
|
||
saveDraftToStorage(key, data);
|
||
removeDraft(fallbackKey);
|
||
}
|
||
|
||
finishRestoreState(() => {
|
||
if (showRestoreToast) {
|
||
uni.showToast({
|
||
title: restoreToast,
|
||
icon: 'none',
|
||
duration: 2500
|
||
});
|
||
}
|
||
});
|
||
|
||
return true;
|
||
} catch (error) {
|
||
console.error('[useDraftCache] 恢复草稿失败:', error);
|
||
isRestoring.value = false;
|
||
isInitialized.value = true;
|
||
return false;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 绑定自动保存(等价于页面里的 watch + saveDraft)
|
||
* @param {import('vue').WatchSource|import('vue').WatchSource[]} source
|
||
* @param {import('vue').WatchOptions} [watchOptions]
|
||
*/
|
||
const bindAutoSave = (source, watchOptions = {}) => {
|
||
watch(
|
||
source,
|
||
() => save(),
|
||
{ deep: true, ...watchOptions }
|
||
);
|
||
};
|
||
|
||
return {
|
||
hasDraft,
|
||
showRestoreBanner,
|
||
isRestoring,
|
||
isInitialized,
|
||
save,
|
||
clear,
|
||
restore,
|
||
bindAutoSave
|
||
};
|
||
}
|