import { SelectedState, EditState, Column, DataSource, } from './type'; import { deepCopy } from "./util" import { watch, onMounted, onBeforeUnmount } from "vue" interface SaveOptions { columns: Column[] dataSource: DataSource[] selectedState: SelectedState editState: EditState } export default class { private storeIndex: number = 0 private storeData: SaveOptions[] = [] private limitCount: number = 30 private autoSaveTimer: any private freezeAutoSaveTimer: any private stopWatchHandeler: any private config: { beforeRedoUndo?: (type: 'redo' | 'undo') => Promise redoUndoCallback: Function } constructor(config: { beforeRedoUndo?: (type: 'redo' | 'undo') => Promise redoUndoCallback: Function }){ this.config = config const keydownHandel = async () => { // CTRL + Z if ((event?.ctrlKey || event?.metaKey) && event?.keyCode === 90) { event.preventDefault(); this.undo(); } // CTRL + Y if ((event?.ctrlKey || event?.metaKey) && event?.keyCode === 89) { event.preventDefault(); this.redo() } } onMounted(() => { document.addEventListener('keydown', keydownHandel); }); onBeforeUnmount(() => { this.destory(); document.removeEventListener('keydown', keydownHandel); }); } /** * 恢复 * @returns */ async redo(){ await this.config?.beforeRedoUndo?.('redo'); if(!this.can_redo()) return; this.startFreezeAutoSave(); this.storeIndex = this.storeIndex + 1; const params = deepCopy(this.storeData[this.storeIndex]) params && this.config.redoUndoCallback(params) // console.log("数据重做了", this.storeData, this.storeIndex) } can_redo(){ return this.storeIndex < this.storeData.length - 1; } /** * 撤销 * @returns */ async undo(){ await this.config?.beforeRedoUndo?.('undo'); if(!this.can_undo()) return; this.startFreezeAutoSave(); this.storeIndex = this.storeIndex - 1; const params = deepCopy(this.storeData[this.storeIndex]) params && this.config.redoUndoCallback(params) // console.log("数据撤销了", this.storeData, this.storeIndex) } can_undo(){ return this.storeIndex > 0 } /** * 保存快照数据 * @param option 快照数据 * @param callback 保存成功回调 * @returns */ save(option: SaveOptions, callback?: () => void){ if (JSON.stringify(option) === JSON.stringify(this.storeData.at(-1))) { this.storeIndex = this.storeData.length - 1; return }; const DATA = deepCopy(option) this.storeData.splice(this.storeIndex + 1, this.limitCount * 2, DATA) this.storeIndex++; if(this.storeData.length > this.limitCount){ this.storeData.shift() } if(typeof callback === 'function') callback() // console.log("数据快照更新了", this.storeData, this.storeIndex) } /** * 自动记录历史快照 * @param getter () => Record * @param interval 探测到变化,记录getter返回值的延迟时间。 */ autoSaveChange(getter: any, interval: number = 300){ this.stopWatchHandeler = watch(getter, (data: SaveOptions) => { if(this.autoSaveTimer || this.freezeAutoSaveTimer) return; this.save(data) this.autoSaveTimer = setTimeout(() => { this.clearAutoSaveTimer() }, interval) },{ deep: true, }) } /** * 销毁历史记录 */ destory(){ this.stopWatchHandeler?.(); this.storeIndex = 0; this.storeData = [] this.clearAutoSaveTimer() this.clearFreezeAutoSave() } getLength(){ return this.storeData.length; } private startFreezeAutoSave(){ this.clearFreezeAutoSave() this.freezeAutoSaveTimer = setTimeout(() => { this.clearFreezeAutoSave() }, 300) } private clearFreezeAutoSave(){ clearTimeout(this.freezeAutoSaveTimer) this.freezeAutoSaveTimer = null } private clearAutoSaveTimer(){ clearTimeout(this.autoSaveTimer) this.autoSaveTimer = null } }