隐患详情重新设计,检查计划重新设计成做题排查式

This commit is contained in:
王利强
2026-06-21 16:30:12 +08:00
parent 1fe87ec438
commit cc94d3e3e9
256 changed files with 12542 additions and 5956 deletions

158
utils/useDraftCache.js Normal file
View File

@@ -0,0 +1,158 @@
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
};
}