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