feat: add query-login
This commit is contained in:
		
							
								
								
									
										238
									
								
								src/pages/config/edit/List.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								src/pages/config/edit/List.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,238 @@ | ||||
| import { useEffect, useState } from 'react'; | ||||
| import { useConfigStore } from '../store/config'; | ||||
| import { CardBlank } from '@/components/card'; | ||||
| import { Button, ButtonGroup, Divider, Drawer, Tab, Tabs, Tooltip } from '@mui/material'; | ||||
| import { Edit, Plus, Save, Trash, X } from 'lucide-react'; | ||||
| import { useModal } from '@kevisual/center-components/modal/Confirm.tsx'; | ||||
| import { useForm, Controller } from 'react-hook-form'; | ||||
| import { TextField } from '@mui/material'; | ||||
| import { useTranslation } from 'react-i18next'; | ||||
| import { IconButton } from '@kevisual/center-components/button/index.tsx'; | ||||
| import { useShallow } from 'zustand/shallow'; | ||||
| import { load, dump } from 'js-yaml'; | ||||
| import CodeEditor from '@uiw/react-textarea-code-editor'; | ||||
| import { toast } from 'react-toastify'; | ||||
| import { isEmpty, pick } from 'lodash-es'; | ||||
|  | ||||
| type DataYamlEditProps = { | ||||
|   onSave: (data: any) => Promise<void>; | ||||
|   type?: 'yaml' | 'json'; | ||||
| }; | ||||
| export const DataYamlEdit = ({ onSave, type }: DataYamlEditProps) => { | ||||
|   const { formData } = useConfigStore( | ||||
|     useShallow((state) => { | ||||
|       return { | ||||
|         formData: state.formData, | ||||
|       }; | ||||
|     }), | ||||
|   ); | ||||
|   const [yaml, setYaml] = useState(formData.data); | ||||
|   useEffect(() => { | ||||
|     const _fromData = formData.data || {}; | ||||
|     if (isEmpty(_fromData)) { | ||||
|       setYaml(''); | ||||
|       return; | ||||
|     } else { | ||||
|       if (type === 'yaml') { | ||||
|         const data = dump(_fromData); | ||||
|         setYaml(data); | ||||
|       } else { | ||||
|         const data = JSON.stringify(_fromData, null, 2); | ||||
|         setYaml(data); | ||||
|       } | ||||
|     } | ||||
|   }, [formData]); | ||||
|   console.log(formData); | ||||
|   const handleSave = () => { | ||||
|     let data: any = {}; | ||||
|     try { | ||||
|       if (type === 'yaml') { | ||||
|         data = load(yaml); | ||||
|       } else { | ||||
|         data = JSON.parse(yaml); | ||||
|       } | ||||
|       onSave({ data }); | ||||
|     } catch (error: any) { | ||||
|       console.error(error); | ||||
|       const errorMessage = error.message.toString(); | ||||
|       toast.error(errorMessage || '解析失败,请检查格式'); | ||||
|     } | ||||
|   }; | ||||
|   return ( | ||||
|     <> | ||||
|       <div className='flex gap-2 items-center'> | ||||
|         <Tooltip title='保存'> | ||||
|           <IconButton sx={{ width: 24, height: 24, padding: '8px' }} onClick={handleSave}> | ||||
|             <Save /> | ||||
|           </IconButton> | ||||
|         </Tooltip> | ||||
|         <div className='text-sm'>{type === 'yaml' ? 'Yaml' : 'Json'} 配置</div> | ||||
|       </div> | ||||
|       <CodeEditor value={yaml} onChange={(e) => setYaml(e.target.value)} className='w-full h-full grow' language={type === 'yaml' ? 'yaml' : 'json'} /> | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| export const DrawerEdit = () => { | ||||
|   const { t } = useTranslation(); | ||||
|   const { showEdit, setShowEdit, formData, updateData } = useConfigStore( | ||||
|     useShallow((state) => { | ||||
|       return { | ||||
|         showEdit: state.showEdit, | ||||
|         setShowEdit: state.setShowEdit, | ||||
|         formData: state.formData, | ||||
|         updateData: state.updateData, | ||||
|       }; | ||||
|     }), | ||||
|   ); | ||||
|   const [tab, setTab] = useState<'base' | 'yaml' | 'json'>('base'); | ||||
|  | ||||
|   const { control, handleSubmit, reset } = useForm({ | ||||
|     defaultValues: { | ||||
|       title: formData.title || '', | ||||
|       description: formData.description || '', | ||||
|       key: formData.key || '', | ||||
|     }, | ||||
|   }); | ||||
|   useEffect(() => { | ||||
|     if (showEdit) { | ||||
|       const _formData = { | ||||
|         id: formData.id || '', | ||||
|         title: formData.title || '', | ||||
|         description: formData.description || '', | ||||
|         key: formData.key || '', | ||||
|       }; | ||||
|       reset(_formData); | ||||
|     } | ||||
|   }, [showEdit, formData]); | ||||
|   const isEdit = !!formData?.id; | ||||
|   const onSave = async (values: any) => { | ||||
|     await updateData({ ...values, id: formData.id }, { refresh: true }); | ||||
|   }; | ||||
|   const onSubmit = (data) => { | ||||
|     console.log('Form Data:', data); | ||||
|     const pickValue = pick(data, ['title', 'key', 'description']); | ||||
|     onSave(pickValue); | ||||
|   }; | ||||
|   return ( | ||||
|     <Drawer | ||||
|       open={showEdit} | ||||
|       anchor='right' | ||||
|       slotProps={{ | ||||
|         paper: { | ||||
|           sx: { | ||||
|             width: '50%', | ||||
|             height: '100%', | ||||
|           }, | ||||
|         }, | ||||
|       }}> | ||||
|       <div className='h-full bg-white rounded-lg p-2  w-full overflow-hidden'> | ||||
|         <div className='text-2xl font-bold px-2 py-4 flex gap-2 items-center'> | ||||
|           <IconButton onClick={() => setShowEdit(false)} size='small'> | ||||
|             <X /> | ||||
|           </IconButton> | ||||
|           <div>{formData.title}</div> | ||||
|         </div> | ||||
|         <Divider /> | ||||
|         <Tabs value={tab} onChange={(_, value) => setTab(value)}> | ||||
|           <Tab label='基本信息' value='base' /> | ||||
|           <Tab label='Yaml Config' value='yaml' /> | ||||
|           <Tab label='JSON Config' value='json' /> | ||||
|         </Tabs> | ||||
|         {tab === 'base' && ( | ||||
|           <form onSubmit={handleSubmit(onSubmit)} className='w-full p-2'> | ||||
|             <Controller | ||||
|               name='title' | ||||
|               control={control} | ||||
|               render={({ field }) => <TextField {...field} label='Title' variant='outlined' fullWidth margin='normal' />} | ||||
|             /> | ||||
|             <Controller | ||||
|               name='key' | ||||
|               control={control} | ||||
|               render={({ field }) => <TextField {...field} label='Key' variant='outlined' fullWidth margin='normal' />} | ||||
|             /> | ||||
|             <Controller | ||||
|               name='description' | ||||
|               control={control} | ||||
|               render={({ field }) => <TextField {...field} label='Description' variant='outlined' fullWidth margin='normal' multiline rows={4} />} | ||||
|             /> | ||||
|             <Button type='submit' variant='contained' color='primary'> | ||||
|               {t('Submit')} | ||||
|             </Button> | ||||
|           </form> | ||||
|         )} | ||||
|         {tab === 'yaml' && ( | ||||
|           <div className='w-full flex flex-col gap-2 px-4 py-2' style={{ height: 'calc(100% - 120px)' }}> | ||||
|             <DataYamlEdit onSave={onSave} type='yaml' /> | ||||
|           </div> | ||||
|         )} | ||||
|         {tab === 'json' && ( | ||||
|           <div className='w-full flex flex-col gap-2 px-4 py-2' style={{ height: 'calc(100% - 120px)' }}> | ||||
|             <DataYamlEdit onSave={onSave} type='json' /> | ||||
|           </div> | ||||
|         )} | ||||
|       </div> | ||||
|     </Drawer> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| export const List = () => { | ||||
|   const { list, getConfig, setShowEdit, setFormData, deleteConfig } = useConfigStore(); | ||||
|   const [modal, contextHolder] = useModal(); | ||||
|   useEffect(() => { | ||||
|     getConfig(); | ||||
|   }, []); | ||||
|   console.log(list); | ||||
|   return ( | ||||
|     <div className='w-full h-full flex bg-gray-100'> | ||||
|       <div className='h-full bg-white'> | ||||
|         <div className='p-2'> | ||||
|           <IconButton | ||||
|             onClick={() => { | ||||
|               setShowEdit(true); | ||||
|               setFormData({}); | ||||
|             }}> | ||||
|             <Plus /> | ||||
|           </IconButton> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div className=' grow p-4'> | ||||
|         <div className='w-full h-full bg-white rounded-lg p-2 scrollbar '> | ||||
|           <div className='flex flex-wrap gap-2'> | ||||
|             {list.map((item) => ( | ||||
|               <div className='card w-[300px]' key={item.id}> | ||||
|                 <div className='card-title flex font-bold justify-between'>{item.title}</div> | ||||
|                 <div className='card-content'>{item.description}</div> | ||||
|                 <div className='card-footer flex justify-end'> | ||||
|                   <ButtonGroup variant='contained'> | ||||
|                     <Button | ||||
|                       onClick={() => { | ||||
|                         setShowEdit(true); | ||||
|                         setFormData(item); | ||||
|                       }}> | ||||
|                       <Edit /> | ||||
|                     </Button> | ||||
|                     <Button | ||||
|                       onClick={() => { | ||||
|                         modal.confirm({ | ||||
|                           title: 'Delete', | ||||
|                           content: 'Are you sure delete this data?', | ||||
|                           onOk: () => { | ||||
|                             deleteConfig(item.id); | ||||
|                           }, | ||||
|                         }); | ||||
|                       }}> | ||||
|                       <Trash /> | ||||
|                     </Button> | ||||
|                   </ButtonGroup> | ||||
|                 </div> | ||||
|               </div> | ||||
|             ))} | ||||
|             <CardBlank /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <DrawerEdit /> | ||||
|       {contextHolder} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user