generated from template/vite-react-template
	add temp ticket
This commit is contained in:
		| @@ -42,6 +42,7 @@ | ||||
|     "@types/react-dom": "^19.1.1", | ||||
|     "@vitejs/plugin-basic-ssl": "^2.0.0", | ||||
|     "@vitejs/plugin-react": "^4.3.4", | ||||
|     "commander": "^13.1.0", | ||||
|     "tailwindcss": "^4.1.1", | ||||
|     "typescript": "^5.8.2", | ||||
|     "vite": "^6.2.4" | ||||
|   | ||||
| @@ -1,3 +0,0 @@ | ||||
| packages: | ||||
|   - 'submodules/*' | ||||
|   - 'packages/*' | ||||
| @@ -1,5 +1,6 @@ | ||||
| import fs from 'fs'; | ||||
| import path from 'path'; | ||||
| import { program } from 'commander'; | ||||
|  | ||||
| export const root = process.cwd(); | ||||
|  | ||||
| @@ -9,3 +10,11 @@ export const clearWorkspace = () => { | ||||
|     fs.rmSync(path.join(root, file), { recursive: true, force: true }); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // clearWorkspace(); | ||||
| program.option('-c, --clear', 'clear workspace').action((opts) => { | ||||
|   if (opts.clear) { | ||||
|     clearWorkspace(); | ||||
|   } | ||||
| }); | ||||
| program.parse(process.argv); | ||||
|   | ||||
| @@ -1,5 +1,87 @@ | ||||
| import { basename } from '../modules/basename'; | ||||
| console.log('basename', basename); | ||||
| import { useState } from 'react'; | ||||
| import { Box, Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, IconButton } from '@mui/material'; | ||||
| import { Edit, Delete } from 'lucide-react'; | ||||
| import { ModalForm } from './ModalForm'; | ||||
|  | ||||
| // 定义工单类型 | ||||
| interface Ticket { | ||||
|   id: number; | ||||
|   title: string; | ||||
|   status: string; | ||||
|   priority: string; | ||||
|   createTime: string; | ||||
| } | ||||
|  | ||||
| export const App = () => { | ||||
|   return <div className='bg-slate-200 w-full h-full border'>123</div>; | ||||
|   const [tickets, setTickets] = useState<Ticket[]>([]); | ||||
|   const [open, setOpen] = useState(false); | ||||
|   const [selectedTicket, setSelectedTicket] = useState<Ticket | null>(null); | ||||
|  | ||||
|   const handleCreate = () => { | ||||
|     setSelectedTicket(null); | ||||
|     setOpen(true); | ||||
|   }; | ||||
|  | ||||
|   const handleEdit = (ticket: Ticket) => { | ||||
|     setSelectedTicket(ticket); | ||||
|     setOpen(true); | ||||
|   }; | ||||
|  | ||||
|   const handleDelete = (id: number) => { | ||||
|     setTickets(tickets.filter((ticket) => ticket.id !== id)); | ||||
|   }; | ||||
|  | ||||
|   const handleSave = (data: Ticket) => { | ||||
|     if (selectedTicket) { | ||||
|       setTickets(tickets.map((t) => (t.id === selectedTicket.id ? data : t))); | ||||
|     } else { | ||||
|       setTickets([...tickets, { ...data, id: Date.now() }]); | ||||
|     } | ||||
|     setOpen(false); | ||||
|   }; | ||||
|  | ||||
|   return ( | ||||
|     <Box className='p-4'> | ||||
|       <Box className='mb-4 flex justify-between'> | ||||
|         <h1 className='text-2xl font-bold'>工单管理</h1> | ||||
|         <Button variant='contained' onClick={handleCreate}> | ||||
|           创建工单 | ||||
|         </Button> | ||||
|       </Box> | ||||
|  | ||||
|       <TableContainer component={Paper}> | ||||
|         <Table> | ||||
|           <TableHead> | ||||
|             <TableRow> | ||||
|               <TableCell>标题</TableCell> | ||||
|               <TableCell>状态</TableCell> | ||||
|               <TableCell>优先级</TableCell> | ||||
|               <TableCell>创建时间</TableCell> | ||||
|               <TableCell>操作</TableCell> | ||||
|             </TableRow> | ||||
|           </TableHead> | ||||
|           <TableBody> | ||||
|             {tickets.map((ticket) => ( | ||||
|               <TableRow key={ticket.id}> | ||||
|                 <TableCell>{ticket.title}</TableCell> | ||||
|                 <TableCell>{ticket.status}</TableCell> | ||||
|                 <TableCell>{ticket.priority}</TableCell> | ||||
|                 <TableCell>{ticket.createTime}</TableCell> | ||||
|                 <TableCell> | ||||
|                   <IconButton onClick={() => handleEdit(ticket)}> | ||||
|                     <Edit className='w-4 h-4' /> | ||||
|                   </IconButton> | ||||
|                   <IconButton onClick={() => handleDelete(ticket.id)}> | ||||
|                     <Delete className='w-4 h-4' /> | ||||
|                   </IconButton> | ||||
|                 </TableCell> | ||||
|               </TableRow> | ||||
|             ))} | ||||
|           </TableBody> | ||||
|         </Table> | ||||
|       </TableContainer> | ||||
|  | ||||
|       <ModalForm open={open} onClose={() => setOpen(false)} onSave={handleSave} ticket={selectedTicket} /> | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										121
									
								
								src/pages/ModalForm.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/pages/ModalForm.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| import { useEffect } from 'react'; | ||||
| import { useForm, Controller } from 'react-hook-form'; | ||||
| import { | ||||
|   Dialog, | ||||
|   DialogTitle, | ||||
|   DialogContent, | ||||
|   DialogActions, | ||||
|   Button, | ||||
|   TextField, | ||||
|   MenuItem, | ||||
|   Box | ||||
| } from '@mui/material'; | ||||
|  | ||||
| interface Ticket { | ||||
|   id: number; | ||||
|   title: string; | ||||
|   status: string; | ||||
|   priority: string; | ||||
|   createTime: string; | ||||
| } | ||||
|  | ||||
| interface ModalFormProps { | ||||
|   open: boolean; | ||||
|   onClose: () => void; | ||||
|   onSave: (data: Ticket) => void; | ||||
|   ticket: Ticket | null; | ||||
| } | ||||
|  | ||||
| export const ModalForm = ({ open, onClose, onSave, ticket }: ModalFormProps) => { | ||||
|   const { control, handleSubmit, reset } = useForm<Ticket>({ | ||||
|     defaultValues: { | ||||
|       title: '', | ||||
|       status: '待处理', | ||||
|       priority: '中', | ||||
|       createTime: new Date().toLocaleString() | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     if (ticket) { | ||||
|       reset(ticket); | ||||
|     } else { | ||||
|       reset({ | ||||
|         title: '', | ||||
|         status: '待处理', | ||||
|         priority: '中', | ||||
|         createTime: new Date().toLocaleString() | ||||
|       }); | ||||
|     } | ||||
|   }, [ticket, reset]); | ||||
|  | ||||
|   const onSubmit = (data: Ticket) => { | ||||
|     onSave(data); | ||||
|   }; | ||||
|  | ||||
|   return ( | ||||
|     <Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth> | ||||
|       <DialogTitle>{ticket ? '编辑工单' : '创建工单'}</DialogTitle> | ||||
|       <form onSubmit={handleSubmit(onSubmit)}> | ||||
|         <DialogContent> | ||||
|           <Box className="space-y-4"> | ||||
|             <Controller | ||||
|               name="title" | ||||
|               control={control} | ||||
|               rules={{ required: '请输入标题' }} | ||||
|               render={({ field, fieldState }) => ( | ||||
|                 <TextField | ||||
|                   {...field} | ||||
|                   label="标题" | ||||
|                   fullWidth | ||||
|                   error={!!fieldState.error} | ||||
|                   helperText={fieldState.error?.message} | ||||
|                 /> | ||||
|               )} | ||||
|             /> | ||||
|  | ||||
|             <Controller | ||||
|               name="status" | ||||
|               control={control} | ||||
|               render={({ field }) => ( | ||||
|                 <TextField | ||||
|                   {...field} | ||||
|                   select | ||||
|                   label="状态" | ||||
|                   fullWidth | ||||
|                 > | ||||
|                   <MenuItem value="待处理">待处理</MenuItem> | ||||
|                   <MenuItem value="处理中">处理中</MenuItem> | ||||
|                   <MenuItem value="已完成">已完成</MenuItem> | ||||
|                 </TextField> | ||||
|               )} | ||||
|             /> | ||||
|  | ||||
|             <Controller | ||||
|               name="priority" | ||||
|               control={control} | ||||
|               render={({ field }) => ( | ||||
|                 <TextField | ||||
|                   {...field} | ||||
|                   select | ||||
|                   label="优先级" | ||||
|                   fullWidth | ||||
|                 > | ||||
|                   <MenuItem value="高">高</MenuItem> | ||||
|                   <MenuItem value="中">中</MenuItem> | ||||
|                   <MenuItem value="低">低</MenuItem> | ||||
|                 </TextField> | ||||
|               )} | ||||
|             /> | ||||
|           </Box> | ||||
|         </DialogContent> | ||||
|         <DialogActions> | ||||
|           <Button onClick={onClose}>取消</Button> | ||||
|           <Button type="submit" variant="contained"> | ||||
|             保存 | ||||
|           </Button> | ||||
|         </DialogActions> | ||||
|       </form> | ||||
|     </Dialog> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										22
									
								
								turbo.json
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								turbo.json
									
									
									
									
									
								
							| @@ -1,22 +0,0 @@ | ||||
| { | ||||
|   "$schema": "https://turbo.build/schema.json", | ||||
|   "tasks": { | ||||
|     "build": { | ||||
|       "dependsOn": [ | ||||
|         "^build" | ||||
|       ], | ||||
|       "outputs": [ | ||||
|         "dist/**" | ||||
|       ] | ||||
|     }, | ||||
|     "dev:lib": { | ||||
|       "persistent": true, | ||||
|       "cache": true | ||||
|     }, | ||||
|     "build:lib": { | ||||
|       "dependsOn": [ | ||||
|         "^build:lib" | ||||
|       ] | ||||
|     } | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user