generated from template/astro-template
feat: add ai-html
This commit is contained in:
215
src/apps/draw/store/index.ts
Normal file
215
src/apps/draw/store/index.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
import { StoreManager } from '@kevisual/store';
|
||||
import { useContextKey } from '@kevisual/store/context';
|
||||
import { StateCreator, StoreApi, UseBoundStore } from 'zustand';
|
||||
import { queryMark } from '../modules/query';
|
||||
import { useStore, BoundStore } from '@kevisual/store/react';
|
||||
import { createStore, set as setCache, get as getCache } from 'idb-keyval';
|
||||
import { OrderedExcalidrawElement } from '@excalidraw/excalidraw/element/types';
|
||||
import { toast } from 'react-toastify';
|
||||
import { BinaryFileData, ExcalidrawImperativeAPI } from '@excalidraw/excalidraw/types';
|
||||
export const cacheStore = createStore('excalidraw-store', 'excalidraw');
|
||||
|
||||
export const store = useContextKey('store', () => {
|
||||
return new StoreManager();
|
||||
});
|
||||
|
||||
type MarkStore = {
|
||||
id: string;
|
||||
setId: (id: string) => void;
|
||||
mark: any;
|
||||
setMark: (mark: any) => void;
|
||||
info: any;
|
||||
setInfo: (info: any) => void;
|
||||
getList: () => Promise<void>;
|
||||
list: any[];
|
||||
setList: (list: any[]) => void;
|
||||
getMark: (markId: string) => Promise<void>;
|
||||
updateMark: () => Promise<void>;
|
||||
getCache: (
|
||||
id: string,
|
||||
updateApiData?: boolean,
|
||||
) => Promise<
|
||||
| {
|
||||
elements: OrderedExcalidrawElement[];
|
||||
filesObject: Record<string, any>;
|
||||
}
|
||||
| undefined
|
||||
>;
|
||||
setCache: (cache: any, version?: number) => Promise<void>;
|
||||
loading: boolean;
|
||||
setLoading: (loading: boolean) => void;
|
||||
// excalidraw
|
||||
|
||||
api: ExcalidrawImperativeAPI | null;
|
||||
setApi: (api: ExcalidrawImperativeAPI) => void;
|
||||
};
|
||||
export const createMarkStore: StateCreator<MarkStore, [], [], MarkStore> = (set, get, store) => {
|
||||
return {
|
||||
id: '',
|
||||
setId: (id: string) => set(() => ({ id })),
|
||||
mark: null,
|
||||
setMark: (mark: any) => set(() => ({ mark })),
|
||||
loading: true,
|
||||
setLoading: (loading: boolean) => set(() => ({ loading })),
|
||||
info: null,
|
||||
setCache: async (cache: any, version?: number) => {
|
||||
const { id, mark } = get();
|
||||
console.log('cacheData setCache ,id', cache, id);
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
const cacheData = (await getCache(`${id}`, cacheStore)) || {};
|
||||
await setCache(
|
||||
`${id}`,
|
||||
{
|
||||
...cacheData,
|
||||
...cache,
|
||||
data: {
|
||||
...cacheData?.data,
|
||||
...cache?.data,
|
||||
},
|
||||
version: version || mark?.version || 0,
|
||||
},
|
||||
cacheStore,
|
||||
);
|
||||
},
|
||||
updateMark: async () => {
|
||||
const { id } = get();
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cacheData = await getCache(id, cacheStore);
|
||||
let mark = cacheData || {};
|
||||
if (!mark) {
|
||||
return;
|
||||
}
|
||||
const { data } = mark;
|
||||
const { elements, filesObject } = data;
|
||||
console.log('updateMark', elements, filesObject);
|
||||
const res = await queryMark.updateMark({ id, data });
|
||||
if (res.code === 200) {
|
||||
set(() => ({ mark: res.data }));
|
||||
toast.success('更新成功');
|
||||
get().setCache({}, res.data!.version);
|
||||
}
|
||||
},
|
||||
getCache: async (id: string, updateApiData?: boolean) => {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
// 获取缓存
|
||||
let cacheData = (await getCache(`${id}`, cacheStore)) || { data: { elements: [], filesObject: {} } };
|
||||
console.log('getCache', id, cacheData);
|
||||
if (cacheData) {
|
||||
if (updateApiData) {
|
||||
const api = get().api;
|
||||
if (api) {
|
||||
const files = Object.values(cacheData.data.filesObject || {}) as BinaryFileData[];
|
||||
api.addFiles(files || []);
|
||||
api.updateScene({
|
||||
elements: [...(cacheData.data?.elements || [])],
|
||||
appState: {},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
elements: cacheData.data.elements || [],
|
||||
filesObject: cacheData.data.filesObject || {},
|
||||
};
|
||||
},
|
||||
setInfo: (info: any) => set(() => ({ info })),
|
||||
getList: async () => {
|
||||
const res = await queryMark.getMarkList({ page: 1, pageSize: 10 });
|
||||
console.log(res);
|
||||
},
|
||||
list: [],
|
||||
setList: (list: any[]) => set(() => ({ list })),
|
||||
getMark: async (markId: string) => {
|
||||
set(() => ({ loading: true, id: markId }));
|
||||
const toastId = toast.loading(`获取数据中...`);
|
||||
const now = new Date().getTime();
|
||||
const cacheData = await getCache(markId, cacheStore);
|
||||
const checkVersion = await queryMark.checkVersion(markId, cacheData?.version);
|
||||
if (checkVersion) {
|
||||
const res = await queryMark.getMark(markId);
|
||||
if (res.code === 200) {
|
||||
set(() => ({
|
||||
mark: res.data,
|
||||
id: markId,
|
||||
}));
|
||||
const mark = res.data!;
|
||||
const excalidrawData = mark.data || {};
|
||||
await get().setCache({
|
||||
data: {
|
||||
elements: excalidrawData.elements,
|
||||
filesObject: excalidrawData.filesObject,
|
||||
},
|
||||
version: mark.version,
|
||||
});
|
||||
get().getCache(markId, true);
|
||||
} else {
|
||||
toast.error(res.message || '获取数据失败');
|
||||
}
|
||||
}
|
||||
|
||||
const end = new Date().getTime();
|
||||
const getTime = end - now;
|
||||
if (getTime < 2 * 1000) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 2 * 1000 - getTime));
|
||||
}
|
||||
toast.dismiss(toastId);
|
||||
set(() => ({ loading: false }));
|
||||
},
|
||||
api: null,
|
||||
setApi: (api: ExcalidrawImperativeAPI) => set(() => ({ api })),
|
||||
};
|
||||
};
|
||||
|
||||
export const useMarkStore = useStore as BoundStore<MarkStore>;
|
||||
|
||||
export const fileDemo = {
|
||||
abc: {
|
||||
dataURL: 'https://kevisual.xiongxiao.me/root/center/panda.png' as any,
|
||||
// @ts-ignore
|
||||
id: 'abc',
|
||||
name: 'test2.png',
|
||||
type: 'image/png',
|
||||
},
|
||||
};
|
||||
export const demoElements: OrderedExcalidrawElement[] = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'image',
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fileId: 'abc' as any,
|
||||
version: 2,
|
||||
versionNonce: 28180243,
|
||||
index: 'a0' as any,
|
||||
isDeleted: false,
|
||||
fillStyle: 'solid',
|
||||
strokeWidth: 2,
|
||||
strokeStyle: 'solid',
|
||||
roughness: 1,
|
||||
opacity: 100,
|
||||
angle: 0,
|
||||
strokeColor: '#1e1e1e',
|
||||
backgroundColor: 'transparent',
|
||||
seed: 1,
|
||||
groupIds: [],
|
||||
frameId: null,
|
||||
roundness: null,
|
||||
boundElements: [],
|
||||
updated: 1743219351869,
|
||||
link: null,
|
||||
locked: false,
|
||||
status: 'pending',
|
||||
scale: [1, 1],
|
||||
crop: null,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user