2025-03-02 23:32:07 +08:00

205 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { create } from 'zustand';
import { XYPosition } from '@xyflow/react';
import { getWallData, setWallData } from '../utils/db';
import { useUserWallStore } from './user-wall';
import { redirectToLogin } from '@/modules/require-to-login';
import { message } from '@/modules/message';
import { randomId } from '../utils/random';
import { DOCS_NODE } from '../docs';
import { toast } from 'react-toastify';
import { SplitButtons } from '../components/SplitToast';
type NodeData<T = { [key: string]: any }> = {
id: string;
position: XYPosition;
data: T;
type?: string; // wall
};
export const getNodeData = (nodes: NodeData[]) => {
return nodes.map((node) => ({
id: node.id,
position: node.position,
data: node.data,
type: node.type,
}));
};
interface WallState {
// 只做传递
nodes: NodeData[];
setNodes: (nodes: NodeData[]) => void;
saveNodes: (nodes: NodeData[], opts?: { showMessage?: boolean }) => Promise<void>;
open: boolean;
setOpen: (open: boolean) => void;
checkAndOpen: (open?: boolean, data?: any) => void;
selectedNode: NodeData | null;
setSelectedNode: (node: NodeData | null) => void;
editValue: string;
setEditValue: (value: string, init?: boolean) => void;
hasEdited: boolean;
setHasEdited: (hasEdited: boolean) => void;
data?: any;
setData: (data: any) => void;
init: (id?: string | null) => Promise<void>;
id: string | null;
setId: (id: string | null) => void;
loading: boolean;
setLoading: (loading: boolean) => void;
loaded: boolean | 'error';
toolbarOpen: boolean;
setToolbarOpen: (open: boolean) => void;
showFormDialog: boolean;
setShowFormDialog: (show: boolean) => void;
formDialogData: any;
setFormDialogData: (data: any) => void;
clear: () => Promise<void>;
exportWall: (nodes: NodeData[]) => Promise<void>;
clearQueryWall: () => Promise<void>;
clearId: () => Promise<void>;
mouseSelect: boolean;
setMouseSelect: (mouseSelect: boolean) => void;
}
export const useWallStore = create<WallState>((set, get) => ({
nodes: [],
loading: false,
setLoading: (loading) => set({ loading }),
setNodes: (nodes) => {
set({ nodes });
},
saveNodes: async (nodes: NodeData[], opts) => {
const showMessage = opts?.showMessage ?? true;
set({ hasEdited: false });
if (!get().id) {
const covertData = getNodeData(nodes);
setWallData({ nodes: covertData });
showMessage && message.success('保存到本地');
} else {
const { id } = get();
const userWallStore = useUserWallStore.getState();
if (id) {
const covertData = getNodeData(nodes);
const res = await userWallStore.saveWall({
id,
data: {
nodes: covertData,
},
});
if (res.code === 200) {
// console.log('saveNodes res', res);
showMessage &&
message.success('保存成功', {
closeOnClick: true,
});
}
}
}
},
open: false,
setOpen: (open) => {
set({ open });
},
checkAndOpen: (open, data) => {
const state = get();
if (state.hasEdited || state.open) {
toast(SplitButtons, {
closeButton: false,
className: 'p-0 w-[400px] border border-purple-600/40',
ariaLabel: 'Email received',
onClose: (reason) => {
if (reason === 'success') {
set({ open: true, selectedNode: data, hasEdited: false });
}
},
});
return;
} else set({ open, selectedNode: data });
},
selectedNode: null,
setSelectedNode: (node) => set({ selectedNode: node }),
editValue: '',
setEditValue: (value, init = false) => {
set({ editValue: value });
if (!init) {
set({ hasEdited: true });
}
},
hasEdited: false,
setHasEdited: (hasEdited) => set({ hasEdited }),
data: null,
setData: (data) => set({ data }),
id: null,
setId: (id) => set({ id }),
loaded: false,
init: async (id?: string | null) => {
// 如果登陆了且如果有id从服务器获取
// 没有id获取缓存
const hasLogin = localStorage.getItem('token');
if (hasLogin && id) {
const res = await useUserWallStore.getState().queryWall(id);
if (res.code === 200) {
set({ nodes: res.data?.data?.nodes || [], loaded: true, id, data: res.data });
} else {
// message.error('获取失败,请稍后刷新重试');
set({ loaded: 'error' });
}
} else if (!hasLogin && id) {
// 没有登陆但是有id从服务器获取
// 跳转到登陆页面
redirectToLogin();
} else {
const data = await getWallData();
const nodes = data?.nodes || [];
if (nodes.length === 0) {
set({
nodes: [...DOCS_NODE], //
loaded: true,
id: null,
data: null,
});
} else {
set({ nodes, loaded: true, id: null, data: null });
}
}
},
toolbarOpen: false,
setToolbarOpen: (open) => set({ toolbarOpen: open }),
showFormDialog: false,
setShowFormDialog: (show) => set({ showFormDialog: show }),
formDialogData: null,
setFormDialogData: (data) => set({ formDialogData: data }),
clear: async () => {
if (get().id) {
set({ nodes: [], selectedNode: null, editValue: '', data: null });
await useUserWallStore.getState().saveWall({
id: get().id!,
data: {
nodes: [],
},
});
} else {
set({ nodes: [], id: null, selectedNode: null, editValue: '', data: null });
await setWallData({ nodes: [] });
}
},
clearId: async () => {
set({ id: null, data: null });
},
exportWall: async (nodes: NodeData[]) => {
const covertData = getNodeData(nodes);
setWallData({ nodes: covertData });
// 导出为json
const json = JSON.stringify(covertData);
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'wall.json';
a.click();
},
clearQueryWall: async () => {
set({ nodes: [], id: null, selectedNode: null, editValue: '', data: null, toolbarOpen: false, loaded: false });
},
mouseSelect: true,
setMouseSelect: (mouseSelect) => set({ mouseSelect }),
}));