123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- import mitt from "mitt";
- import { SingleHistory } from "../history";
- import { installGlobalVar } from "./use-global-vars";
- import { Ref, ref, watch } from "vue";
- import { copy } from "@/utils/shared";
- import { getEmptyStoreData, StoreData, useStoreRaw } from "../store/store";
- type HistoryItem = { attachs: string; data: string };
- export class DrawHistory {
- history = new SingleHistory<HistoryItem>();
- hasUndo = this.history.hasUndo;
- hasRedo = this.history.hasRedo;
- get list() {
- return this.history.list()
- }
- get currentId() {
- return this.history.currentId
- }
- get current() {
- return this.list.find(item => item.id === this.currentId)?.data
- }
- private preventFlag = 0;
- private onceFlag = 0;
- private onceHistory: string | null = null;
- initData: string | null = null;
- clearData: string = ''
- renderer: (data: HistoryItem) => void;
- bus = mitt<{
- attachs: Record<string, any>;
- renderer: void;
- push: void;
- pushed: void;
- redo: void;
- undo: void;
- init: void;
- clear: void;
- currentChange: void
- }>();
- private pushAttachs: Record<string, any> = {};
- constructor(renderer: (data: string) => void) {
- this.renderer = ({ data, attachs }: HistoryItem) => {
- renderer(data);
- this.bus.emit("renderer");
- this.bus.emit("attachs", attachs ? JSON.parse(attachs) : {});
- };
- }
- setClearData(data:string = '') {
- this.clearData = data
- }
-
- clearHistoryAttach(id: string, name: string) {
- const history = this.history.history as any
- if (!history.$chunks[id]) return
- const data = JSON.parse(history.$chunks[id]).data as HistoryItem
- if (!data.attachs) return;
- const attachs = JSON.parse(data.attachs)
- if (attachs[name]) {
- delete attachs[name]
- data.attachs = JSON.stringify(attachs)
- history.$chunks[id] = JSON.stringify({ data })
- }
- }
- setPushAttach(name: string, data: any) {
- this.pushAttachs[name] = data;
- }
- setInit(data: string) {
- this.initData = data;
- this.history.reset();
- this.push(data);
- }
- private preventTrackCallback() {
- this.preventFlag--
- }
- preventTrack(fn: () => any) {
- this.preventFlag++
- const result = fn();
- if (result instanceof Promise) {
- result.then(() => this.preventTrackCallback())
- } else {
- this.preventTrackCallback()
- }
- }
- private saveKeyPrev = '__history__'
- private saveKeyId: string | null = null
- get saveKey() {
- if (!this.saveKeyId) {
- throw '未设置本地保存key'
- }
- return this.saveKeyPrev + this.saveKeyId
- }
- setLocalId(id: string) {
- this.saveKeyId = id
- }
- getLocalId() {
- return this.saveKeyId
- }
-
- saveLocal() {
- localStorage.setItem(this.saveKey, JSON.stringify(this.list.map(item => item.data)))
- }
- clearLocal() {
- localStorage.removeItem(this.saveKey)
- }
- hasLocal() {
- for (let i = 0, len = localStorage.length; i < len; i++) {
- if (localStorage.key(i) === this.saveKey) {
- return true
- }
- }
- return false
- }
- loadLocalStorage() {
- const list = JSON.parse(localStorage.getItem(this.saveKey)!)
- if (!list.length) {
- this.clear()
- return;
- }
- this.history.reset()
- this.setInit(list[0].data)
- for (let i = 1; i < list.length; i++) {
- this.push(list[i].data)
- }
- this.renderer(list[list.length - 1])
- }
- push(data: string) {
- if (this.preventFlag) return;
- if (this.onceFlag) {
- this.onceHistory = data;
- } else if (data !== this.current?.data) {
- // console.log(data, this.current?.data)
- this.bus.emit("push");
- this.history.push({ attachs: JSON.stringify(this.pushAttachs), data });
- this.pushAttachs = {};
- this.bus.emit("pushed");
- }
- }
- redo() {
- const data = this.history.redo();
- this.bus.emit("redo");
- this.bus.emit('currentChange')
- this.renderer(data);
- return data;
- }
- undo() {
- const data = this.history.undo();
- this.bus.emit("undo");
- this.bus.emit('currentChange')
- this.renderer(data);
- return data;
- }
- private onceTrackCallback() {
- this.onceFlag--
- if (this.onceHistory) {
- this.push(this.onceHistory);
- this.onceHistory = null;
- }
- }
- onceTrack(fn: () => any) {
- this.onceFlag++
- const result = fn();
- if (result instanceof Promise) {
- result.then(() => this.onceTrackCallback())
- } else {
- this.onceTrackCallback()
- }
- }
- clearCurrent(): void {
- this.renderer({ data: this.clearData, attachs: "" });
- this.push(this.clearData);
- }
- clear(): void {
- this.history.reset()
- this.clearCurrent()
- this.bus.emit('clear')
- this.bus.emit('currentChange')
- }
-
- init() {
- if (this.initData) {
- this.renderer({ data: this.initData, attachs: "" });
- this.push(this.initData);
- this.bus.emit('init')
- this.bus.emit('currentChange')
- }
- }
- }
- export const useHistory = installGlobalVar(() => {
- const store = useStoreRaw();
- const history = new DrawHistory((dataStr: string) => {
- const data: StoreData = dataStr ? JSON.parse(dataStr) : getEmptyStoreData()
- store.$patch((state) => {
- state.data = data;
- });
- });
- return history;
- }, Symbol("history"));
- export const useHistoryAttach = <T>(
- name: string,
- isRuning: Ref<boolean> = ref(true),
- getInit: () => T,
- cleanup = true
- ) => {
- const history = useHistory();
- const current = ref<T>(copy(getInit()!));
- const setIds = [] as string[]
- const addSetIds = () => setIds.push(history.currentId)
- const pushHandler = () => {
- history.setPushAttach(name, current.value);
- };
- const attachsHandler = (attachs: any) => {
- current.value = attachs && attachs[name] ? attachs[name] : getInit();
- };
- const cleanupAttach = () => {
- setIds.forEach(id => history.clearHistoryAttach(id, name))
- setIds.length = 0
- }
- watch(
- isRuning,
- (isRun, _, onCleanup) => {
- console.log('isRun', isRun)
- if (!isRun) return;
- history.bus.on("push", pushHandler);
- history.bus.on("attachs", attachsHandler);
- if (cleanup) {
- history.bus.on('pushed', addSetIds)
- }
- onCleanup(() => {
- history.bus.off("push", pushHandler);
- history.bus.off("attachs", attachsHandler);
- current.value = void 0;
-
- if (cleanup) {
- history.bus.off('pushed', pushHandler);
- cleanupAttach()
- }
- });
- },
- { immediate: true, flush: "sync" }
- );
- return current;
- };
|