feat: add preview and change edit and flow
This commit is contained in:
@@ -4,7 +4,8 @@ import { TextArea } from '../components/TextArea';
|
||||
import { useContainerStore } from '../store';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { Form } from 'antd';
|
||||
|
||||
import copy from 'copy-to-clipboard';
|
||||
import { useNavigate } from 'react-router';
|
||||
const FormModal = () => {
|
||||
const [form] = Form.useForm();
|
||||
const containerStore = useContainerStore(
|
||||
@@ -73,6 +74,7 @@ const FormModal = () => {
|
||||
);
|
||||
};
|
||||
export const ContainerList = () => {
|
||||
const navicate = useNavigate();
|
||||
const containerStore = useContainerStore(
|
||||
useShallow((state) => {
|
||||
return {
|
||||
@@ -90,10 +92,23 @@ export const ContainerList = () => {
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
// {
|
||||
// title: 'ID',
|
||||
// dataIndex: 'id',
|
||||
// },
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
render: (text: string) => {
|
||||
return (
|
||||
<div
|
||||
className='w-40 truncate cursor-pointer'
|
||||
title={text}
|
||||
onClick={() => {
|
||||
copy(text);
|
||||
message.success('copy success');
|
||||
}}>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Title',
|
||||
dataIndex: 'title',
|
||||
@@ -124,6 +139,12 @@ export const ContainerList = () => {
|
||||
}}>
|
||||
Edit
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
navicate('/container/preview/' + record.id);
|
||||
}}>
|
||||
Preview
|
||||
</Button>
|
||||
<Button
|
||||
danger
|
||||
onClick={() => {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||
import { ContainerList } from './edit/List';
|
||||
import { Main } from './layouts';
|
||||
|
||||
import { Preview } from './preview';
|
||||
export const App = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route element={<Main />}>
|
||||
<Route path='/' element={<Navigate to='/container/edit/list' />}></Route>
|
||||
<Route path='edit/list' element={<ContainerList />} />
|
||||
<Route path='preview/:id' element={<Preview />} />
|
||||
|
||||
<Route path='/' element={<div>Home</div>} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
61
src/pages/container/preview/index.tsx
Normal file
61
src/pages/container/preview/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Container } from '@abearxiong/container';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
import { query } from '@/modules';
|
||||
import { message } from 'antd';
|
||||
|
||||
export const Preview = () => {
|
||||
const params = useParams<{ id: string }>();
|
||||
const id = params.id;
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const containerRef = useRef<any>(null);
|
||||
const [data, setData] = useState<any>({});
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return;
|
||||
fetch();
|
||||
}, []);
|
||||
const fetch = async () => {
|
||||
const res = await query.post({
|
||||
path: 'container',
|
||||
key: 'get',
|
||||
id,
|
||||
});
|
||||
if (res.code === 200) {
|
||||
const data = res.data;
|
||||
// setData([data]);
|
||||
console.log('data', data);
|
||||
const code = {
|
||||
id: data.id,
|
||||
title: data.title,
|
||||
code: data.code,
|
||||
data: data.data,
|
||||
};
|
||||
init([code]);
|
||||
} else {
|
||||
message.error(res.msg || 'Failed to fetch data');
|
||||
}
|
||||
};
|
||||
const init = async (data: any[]) => {
|
||||
// console.log('data', data, ref.current);
|
||||
const container = new Container({
|
||||
root: ref.current!,
|
||||
data: data as any,
|
||||
showChild: false,
|
||||
});
|
||||
container.render(id!);
|
||||
containerRef.current = container;
|
||||
};
|
||||
return (
|
||||
<div className='w-full h-full bg-gray-200'>
|
||||
<div className='text-center mb-10 font-bold text-4xl mt-4 '>Preview</div>
|
||||
<div
|
||||
className='flex '
|
||||
style={{
|
||||
height: 'calc(100% - 32px)',
|
||||
}}>
|
||||
<div className='mx-auto border bg-white h-h-full w-[80%] h-[80%]' ref={ref}></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Container } from '@abearxiong/container';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
import { query } from '@/modules';
|
||||
import { message } from 'antd';
|
||||
|
||||
export const Deck = () => {
|
||||
const params = useParams<{ id: string }>();
|
||||
const id = params.id;
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const containerRef = useRef<any>(null);
|
||||
const [data, setData] = useState<any>({});
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return;
|
||||
fetch();
|
||||
}, []);
|
||||
const fetch = async () => {
|
||||
const res = await query.post({
|
||||
path: 'page',
|
||||
key: 'getDeck',
|
||||
id,
|
||||
});
|
||||
if (res.code === 200) {
|
||||
const data = res.data;
|
||||
console.log('data', data);
|
||||
const { page, containerList } = data;
|
||||
const { edges, nodes } = page.data;
|
||||
for (let edge of edges) {
|
||||
const { source, target } = edge;
|
||||
const node = nodes.find((node: any) => node.id === source);
|
||||
if (!node) continue;
|
||||
node.children = node.children || [];
|
||||
node.children.push(target);
|
||||
}
|
||||
for (let node of nodes) {
|
||||
const container = containerList.find((container: any) => container.id === node.data?.cid);
|
||||
if (container) {
|
||||
node.container = container;
|
||||
}
|
||||
}
|
||||
const codes = nodes.map((node: any) => {
|
||||
const container = node.container;
|
||||
const data = container?.data || {};
|
||||
return {
|
||||
id: node.id,
|
||||
title: node.title,
|
||||
code: container?.code || '',
|
||||
data: data,
|
||||
children: node.children,
|
||||
...data, // style className shadowRoot showChild
|
||||
};
|
||||
});
|
||||
// const code = {
|
||||
// id: data.id,
|
||||
// title: data.title,
|
||||
// code: data.code,
|
||||
// data: data.data,
|
||||
// };
|
||||
// init([code]);
|
||||
init(codes);
|
||||
console.log('codes', codes);
|
||||
}
|
||||
// if (res.code === 200) {
|
||||
// const data = res.data;
|
||||
// // setData([data]);
|
||||
// console.log('data', data);
|
||||
// const code = {
|
||||
// id: data.id,
|
||||
// title: data.title,
|
||||
// code: data.code,
|
||||
// data: data.data,
|
||||
// };
|
||||
// init([code]);
|
||||
// } else {
|
||||
// message.error(res.msg || 'Failed to fetch data');
|
||||
// }
|
||||
};
|
||||
const init = async (data: any[]) => {
|
||||
// console.log('data', data, ref.current);
|
||||
const container = new Container({
|
||||
root: ref.current!,
|
||||
data: data as any,
|
||||
showChild: true,
|
||||
});
|
||||
container.render(id!);
|
||||
containerRef.current = container;
|
||||
};
|
||||
return (
|
||||
<div className='w-full h-full bg-gray-200'>
|
||||
<div className='text-center mb-10 font-bold text-4xl mt-4 '>Preview</div>
|
||||
<div
|
||||
className='flex '
|
||||
style={{
|
||||
height: 'calc(100% - 32px)',
|
||||
}}>
|
||||
<div className='mx-auto border bg-white h-h-full w-[80%] h-[80%]' ref={ref}></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,172 @@
|
||||
export const List = () => {
|
||||
return <div>List</div>;
|
||||
import { useEditStore } from '../store';
|
||||
import { Button, Input, message, Modal, Table } from 'antd';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { Form } from 'antd';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import { useNavigate } from 'react-router';
|
||||
|
||||
|
||||
const FormModal = () => {
|
||||
const [form] = Form.useForm();
|
||||
const editStore = useEditStore(
|
||||
useShallow((state) => {
|
||||
return {
|
||||
showEdit: state.showEditModal,
|
||||
setShowEdit: state.setShowEditModal,
|
||||
formData: state.formData,
|
||||
updateData: state.updateData,
|
||||
};
|
||||
}),
|
||||
);
|
||||
useEffect(() => {
|
||||
const open = editStore.showEdit;
|
||||
if (open) {
|
||||
form.setFieldsValue(editStore.formData || {});
|
||||
} else {
|
||||
form.resetFields();
|
||||
}
|
||||
}, [editStore.showEdit]);
|
||||
const onFinish = async (values: any) => {
|
||||
editStore.updateData(values);
|
||||
};
|
||||
const onClose = () => {
|
||||
editStore.setShowEdit(false);
|
||||
form.resetFields();
|
||||
};
|
||||
const isEdit = editStore.formData.id;
|
||||
return (
|
||||
<Modal title={isEdit ? 'Edit' : 'Add'} open={editStore.showEdit} onClose={onClose} destroyOnClose footer={false} width={800} onCancel={onClose}>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
labelCol={{
|
||||
span: 4,
|
||||
}}
|
||||
wrapperCol={{
|
||||
span: 20,
|
||||
}}>
|
||||
<Form.Item name='id' hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name='title' label='title'>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
{/* <Form.Item name='code' label='code'>
|
||||
<TextArea value={containerStore.formData.code} />
|
||||
</Form.Item> */}
|
||||
<Form.Item label=' ' colon={false}>
|
||||
<Button type='primary' htmlType='submit'>
|
||||
Submit
|
||||
</Button>
|
||||
<Button className='ml-2' htmlType='reset' onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
export const List = () => {
|
||||
const navicate = useNavigate();
|
||||
const editStore = useEditStore(
|
||||
useShallow((state) => {
|
||||
return {
|
||||
setFormData: state.setFormData,
|
||||
setShowEdit: state.setShowEditModal,
|
||||
list: state.list,
|
||||
deleteData: state.deleteData,
|
||||
getList: state.getList,
|
||||
loading: state.loading,
|
||||
};
|
||||
}),
|
||||
);
|
||||
useEffect(() => {
|
||||
editStore.getList();
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
render: (text: string) => {
|
||||
return (
|
||||
<div
|
||||
className='w-40 truncate cursor-pointer'
|
||||
title={text}
|
||||
onClick={() => {
|
||||
copy(text);
|
||||
message.success('copy success');
|
||||
}}>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Title',
|
||||
dataIndex: 'title',
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Operation',
|
||||
dataIndex: 'operation',
|
||||
render: (text: string, record: any) => {
|
||||
return (
|
||||
<div className='flex gap-2'>
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
editStore.setFormData(record);
|
||||
editStore.setShowEdit(true);
|
||||
}}>
|
||||
Edit
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
navicate('/container/preview/' + record.id);
|
||||
}}>
|
||||
Preview
|
||||
</Button>
|
||||
<Button
|
||||
danger
|
||||
onClick={() => {
|
||||
editStore.deleteData(record.id);
|
||||
}}>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className='w-full h-full flex flex-col'>
|
||||
<div className='mb-2 w-full p-2 bg-white rounded-lg'>
|
||||
<Button
|
||||
className='w-20 '
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
editStore.setFormData({});
|
||||
editStore.setShowEdit(true);
|
||||
}}>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
<div className='flex-grow overflow-scroll'>
|
||||
<Table
|
||||
pagination={false}
|
||||
scroll={{
|
||||
y: 600,
|
||||
}}
|
||||
loading={editStore.loading}
|
||||
dataSource={editStore.list}
|
||||
rowKey='id'
|
||||
columns={columns}
|
||||
/>
|
||||
</div>
|
||||
<div className='h-2'></div>
|
||||
<FormModal />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,33 +14,17 @@ import {
|
||||
useStoreApi,
|
||||
Panel,
|
||||
} from '@xyflow/react';
|
||||
import type { Node } from '@xyflow/react';
|
||||
import '@xyflow/react/dist/style.css';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useAddNode } from '@abearxiong/flows';
|
||||
import { Router, Container } from '@abearxiong/flows';
|
||||
console.log("R", Router);
|
||||
import { useContainerMenu, useRouterMenu } from '@abearxiong/flows';
|
||||
import { Container, useAddNode, ContainerMenusList, useMenuFlow } from '@abearxiong/flows';
|
||||
import { useMenuEmitter, ContainerMenusKeys } from '@abearxiong/flows';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { Button } from 'antd';
|
||||
import { usePanelStore } from '../store';
|
||||
// router: Router
|
||||
const nodeTypes = {
|
||||
container: Container,
|
||||
};
|
||||
export const initialNodes: Node[] = [
|
||||
{ id: '1', position: { x: 100, y: 100 }, data: { label: '1' } },
|
||||
{ id: '2', position: { x: 100, y: 400 }, data: { label: '2' } },
|
||||
{ id: '3', position: { x: 100, y: 700 }, data: { label: '3' }, drag: true },
|
||||
].map((node) => ({
|
||||
...node,
|
||||
// type: 'router',
|
||||
type: 'container',
|
||||
position: {
|
||||
x: node.position.y,
|
||||
y: node.position.x,
|
||||
},
|
||||
}));
|
||||
|
||||
export const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
|
||||
|
||||
export const Flow = () => {
|
||||
return (
|
||||
@@ -50,17 +34,58 @@ export const Flow = () => {
|
||||
);
|
||||
};
|
||||
const ReactFlowApp = () => {
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([...initialNodes]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState<any>([...initialEdges]);
|
||||
|
||||
const reactFlow = useReactFlow();
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState<any>([]);
|
||||
|
||||
const onConnect = useCallback((params) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
||||
const panelStore = usePanelStore(
|
||||
useShallow((state) => {
|
||||
return {
|
||||
data: state.data,
|
||||
saveNodesEdges: state.saveNodesEdges,
|
||||
};
|
||||
}),
|
||||
);
|
||||
useEffect(() => {
|
||||
if (panelStore.data?.id) {
|
||||
const { data } = panelStore.data || {};
|
||||
const nodes = data.nodes || [];
|
||||
const edges = data.edges || [];
|
||||
setNodes(nodes);
|
||||
setEdges(edges);
|
||||
} else {
|
||||
setNodes([]);
|
||||
setEdges([]);
|
||||
}
|
||||
}, [panelStore.data]);
|
||||
const { menuCom, onContextMenu, onClose } = useMenuFlow(
|
||||
(item, cacheData) => {
|
||||
emit({
|
||||
menu: item,
|
||||
data: cacheData,
|
||||
});
|
||||
},
|
||||
{
|
||||
menusList: ContainerMenusList,
|
||||
},
|
||||
);
|
||||
|
||||
const { menuCom, onContextMenu, onClose } = useContainerMenu((item, cacheData) => {
|
||||
console.log(item, cacheData);
|
||||
const { emit } = useMenuEmitter<ContainerMenusKeys>({
|
||||
preview: ({ menu, data }) => {
|
||||
console.log('preview', data);
|
||||
if (data?.data?.cid) {
|
||||
window.open(`/container/preview/${data.data.cid}`, '_blank');
|
||||
}
|
||||
},
|
||||
});
|
||||
const { onNeedAdd, onAdd, onMouseMove, adding } = useAddNode();
|
||||
const onSave = useCallback(() => {
|
||||
panelStore.saveNodesEdges({
|
||||
nodes,
|
||||
edges,
|
||||
});
|
||||
}, [nodes, edges]);
|
||||
|
||||
return (
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
@@ -99,16 +124,25 @@ const ReactFlowApp = () => {
|
||||
}}>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background gap={[14, 14]} size={2} color='#E4E5E7' />
|
||||
{/* <Background gap={[14, 14]} size={2} color='#E4E5E7' /> */}
|
||||
<Background color='#000' />
|
||||
<Panel>{menuCom}</Panel>
|
||||
<Panel>
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={(e) => {
|
||||
onNeedAdd({ id: '5', data: { label: '测试添加按钮' }, type: 'router' }, e);
|
||||
}}>
|
||||
测试添加按钮
|
||||
</Button>
|
||||
<div className='flex gap-2'>
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={(e) => {
|
||||
onNeedAdd({ id: nanoid(6), data: { label: '容器' }, type: 'container' }, e);
|
||||
}}>
|
||||
测试添加按钮
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onSave();
|
||||
}}>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</Panel>
|
||||
</ReactFlow>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
import { useParams } from 'react-router';
|
||||
import Flow from './Flow';
|
||||
import { usePanelStore } from '../store';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const App = () => {
|
||||
const param = useParams();
|
||||
const id = param.id;
|
||||
|
||||
const panel = usePanelStore(
|
||||
useShallow((state) => {
|
||||
return {
|
||||
getPanel: state.getPanel,
|
||||
};
|
||||
}),
|
||||
);
|
||||
useEffect(() => {
|
||||
id && panel.getPanel(id);
|
||||
}, []);
|
||||
if (!id) {
|
||||
return <>No ID</>;
|
||||
}
|
||||
return (
|
||||
<div className='w-full h-full'>
|
||||
sdf
|
||||
<Flow />
|
||||
<div className='w-full h-full p-4'>
|
||||
<div className='w-full h-full'>
|
||||
<Flow />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,14 +2,15 @@ import { Navigate, Route, Routes } from 'react-router-dom';
|
||||
import { List } from './edit/List';
|
||||
import { Main } from './layouts';
|
||||
import { App as FlowApp } from './flow';
|
||||
|
||||
import { Deck } from './deck';
|
||||
export const App = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route element={<Main />}>
|
||||
<Route path='/' element={<Navigate to='/panel/edit/list' />}></Route>
|
||||
<Route path='edit/list' element={<List />} />
|
||||
<Route path='flow' element={<FlowApp />} />
|
||||
<Route path='flow/:id' element={<FlowApp />} />
|
||||
<Route path='deck/:id' element={<Deck />} />
|
||||
<Route path='*' element={'Not Found'}></Route>
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
@@ -26,7 +26,7 @@ export const useEditStore = create<EditStore>((set, get) => {
|
||||
getList: async () => {
|
||||
set({ loading: true });
|
||||
|
||||
const res = await query.post({ path: 'panel', key: 'list' });
|
||||
const res = await query.post({ path: 'page', key: 'list' });
|
||||
set({ loading: false });
|
||||
if (res.code === 200) {
|
||||
set({ list: res.data });
|
||||
@@ -37,7 +37,7 @@ export const useEditStore = create<EditStore>((set, get) => {
|
||||
updateData: async (data) => {
|
||||
const { getList } = get();
|
||||
const res = await query.post({
|
||||
path: 'panel',
|
||||
path: 'page',
|
||||
key: 'update',
|
||||
data,
|
||||
});
|
||||
@@ -52,7 +52,7 @@ export const useEditStore = create<EditStore>((set, get) => {
|
||||
deleteData: async (id) => {
|
||||
const { getList } = get();
|
||||
const res = await query.post({
|
||||
path: 'panel',
|
||||
path: 'page',
|
||||
key: 'delete',
|
||||
id,
|
||||
});
|
||||
|
||||
@@ -1,14 +1,82 @@
|
||||
import { create } from 'zustand';
|
||||
import { query } from '@/modules';
|
||||
import { message } from 'antd';
|
||||
import { produce } from 'immer';
|
||||
|
||||
type PanelStore = {
|
||||
id: string;
|
||||
setId: (id: string) => void;
|
||||
loading: boolean;
|
||||
setLoading: (loading: boolean) => void;
|
||||
data: any;
|
||||
setData: (data: any) => void;
|
||||
getPanel: (id?: string) => Promise<void>;
|
||||
saveNodesEdges: (data: { nodes?: any[]; edges?: any[]; viewport?: any }) => Promise<void>;
|
||||
};
|
||||
export const usePanelStore = create<PanelStore>((set, get) => {
|
||||
return {
|
||||
id: '',
|
||||
setId: (id) => set({ id }),
|
||||
loading: false,
|
||||
setLoading: (loading) => set({ loading }),
|
||||
data: {},
|
||||
setData: (data) => set({ data }),
|
||||
getPanel: async (pid) => {
|
||||
const id = pid || get().id;
|
||||
if (!id) {
|
||||
message.error('ID is required');
|
||||
return;
|
||||
}
|
||||
set(
|
||||
produce((state) => {
|
||||
state.data = {};
|
||||
state.loading = true;
|
||||
}),
|
||||
);
|
||||
const res = await query.post({
|
||||
path: 'page',
|
||||
key: 'get',
|
||||
id,
|
||||
});
|
||||
set({ loading: false });
|
||||
console.log('res', res);
|
||||
if (res.code === 200) {
|
||||
set(
|
||||
produce((state) => {
|
||||
state.data = res.data;
|
||||
state.id = res.data.id;
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
message.error(res.msg || 'Request failed');
|
||||
}
|
||||
},
|
||||
saveNodesEdges: async ({ edges, nodes, viewport }) => {
|
||||
const { id, data: panelData } = get();
|
||||
const { data } = panelData || {};
|
||||
const res = await query.post({
|
||||
path: 'page',
|
||||
key: 'update',
|
||||
data: {
|
||||
id,
|
||||
data: {
|
||||
...data.data,
|
||||
edges,
|
||||
nodes,
|
||||
viewport,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (res.code === 200) {
|
||||
message.success('Success');
|
||||
set(
|
||||
produce((state) => {
|
||||
state.data = res.data;
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
message.error(res.msg || 'Request failed');
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user