| New file |
| | |
| | | import React, { useState, useEffect } from "react"; |
| | | import { |
| | | useTranslate, |
| | | useNotify, |
| | | useRefresh, |
| | | Button, |
| | | DatagridConfigurable, |
| | | TextField, |
| | | NumberField, |
| | | DateField, |
| | | EditButton, |
| | | Toolbar, |
| | | useRecordContext, |
| | | SimpleForm, |
| | | TextInput, |
| | | NumberInput, |
| | | SelectInput, |
| | | WrapperField |
| | | } from 'react-admin'; |
| | | |
| | | import { Box, DialogContent, DialogTitle, DialogActions, Dialog, IconButton, Tooltip } from '@mui/material'; |
| | | import { styled } from '@mui/material/styles'; |
| | | import DialogCloseButton from "../components/DialogCloseButton"; |
| | | import request from '@/utils/request'; |
| | | import AddIcon from '@mui/icons-material/Add'; |
| | | import DeleteIcon from '@mui/icons-material/Delete'; |
| | | import EditIcon from '@mui/icons-material/Edit'; |
| | | |
| | | const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ |
| | | '& .css-1vooibu-MuiSvgIcon-root': { |
| | | height: '.9em' |
| | | }, |
| | | '& .RaDatagrid-row': { |
| | | cursor: 'auto' |
| | | }, |
| | | '& .opt': { |
| | | width: 150 |
| | | }, |
| | | })); |
| | | |
| | | const FlowStepInstanceModal = (props) => { |
| | | const { open, setOpen, record } = props; |
| | | const translate = useTranslate(); |
| | | const notify = useNotify(); |
| | | const [data, setData] = useState([]); |
| | | const [loading, setLoading] = useState(false); |
| | | |
| | | // Form states |
| | | const [formOpen, setFormOpen] = useState(false); |
| | | const [isEdit, setIsEdit] = useState(false); |
| | | const [formData, setFormData] = useState({}); |
| | | |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | } |
| | | }; |
| | | |
| | | const fetchData = async () => { |
| | | if (!record?.taskCode) return; |
| | | setLoading(true); |
| | | try { |
| | | const res = await request.post(`/flowStepInstance/page`, { |
| | | taskNo: record.taskCode, |
| | | current: 1, |
| | | pageSize: 999 |
| | | }); |
| | | if (res.data.code === 200) { |
| | | setData(res.data.data.records || []); |
| | | } else { |
| | | notify(res.data.msg, { type: 'error' }); |
| | | } |
| | | } catch (error) { |
| | | notify('Failed to fetch data', { type: 'error' }); |
| | | } finally { |
| | | setLoading(false); |
| | | } |
| | | }; |
| | | |
| | | useEffect(() => { |
| | | if (open && record) { |
| | | fetchData(); |
| | | } |
| | | }, [open, record]); |
| | | |
| | | const handleCreate = () => { |
| | | setFormData({ taskNo: record?.taskCode, status: 0 }); // Default values |
| | | setIsEdit(false); |
| | | setFormOpen(true); |
| | | }; |
| | | |
| | | const handleEdit = (item) => { |
| | | setFormData(item); |
| | | setIsEdit(true); |
| | | setFormOpen(true); |
| | | }; |
| | | |
| | | const handleDelete = async (item) => { |
| | | try { |
| | | const res = await request.post(`/flowStepInstance/remove/${item.id}`); |
| | | if (res.data.code === 200) { |
| | | notify('Deleted successfully', { type: 'success' }); |
| | | fetchData(); |
| | | } else { |
| | | notify(res.data.msg, { type: 'error' }); |
| | | } |
| | | } catch (error) { |
| | | notify('Delete failed', { type: 'error' }); |
| | | } |
| | | }; |
| | | |
| | | const handleFormClose = () => { |
| | | setFormOpen(false); |
| | | setFormData({}); |
| | | }; |
| | | |
| | | const handleSave = async (dataToSave) => { |
| | | try { |
| | | let res; |
| | | if (isEdit) { |
| | | res = await request.post(`/flowStepInstance/update`, dataToSave); |
| | | } else { |
| | | res = await request.post(`/flowStepInstance/save`, dataToSave); |
| | | } |
| | | |
| | | if (res.data.code === 200) { |
| | | notify(isEdit ? 'Updated successfully' : 'Created successfully', { type: 'success' }); |
| | | setFormOpen(false); |
| | | fetchData(); |
| | | } else { |
| | | notify(res.data.msg, { type: 'error' }); |
| | | } |
| | | } catch (error) { |
| | | notify('Save failed', { type: 'error' }); |
| | | } |
| | | }; |
| | | |
| | | return ( |
| | | <React.Fragment> |
| | | <Dialog |
| | | open={open} |
| | | onClose={handleClose} |
| | | aria-labelledby="form-dialog-title" |
| | | fullWidth |
| | | maxWidth="lg" |
| | | > |
| | | <DialogTitle id="form-dialog-title" sx={{ |
| | | position: 'sticky', |
| | | top: 0, |
| | | backgroundColor: 'background.paper', |
| | | zIndex: 1000 |
| | | }}> |
| | | {translate('menu.missionFlowStepInstance')} |
| | | <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> |
| | | <DialogCloseButton onClose={handleClose} /> |
| | | </Box> |
| | | </DialogTitle> |
| | | <DialogContent sx={{ minHeight: 400 }}> |
| | | <Box sx={{ mb: 2, display: 'flex', justifyContent: 'flex-end' }}> |
| | | <Button variant="contained" label="ra.action.create" onClick={handleCreate}> |
| | | <AddIcon /> |
| | | </Button> |
| | | </Box> |
| | | <StyledDatagrid |
| | | data={data} |
| | | isLoading={loading} |
| | | bulkActionButtons={false} |
| | | rowClick={false} |
| | | > |
| | | <NumberField source="id" label={translate("table.field.flowStepInstance.id")} /> |
| | | <NumberField source="stepOrder" label={translate("table.field.flowStepInstance.stepOrder")} /> |
| | | <TextField source="stepCode" label={translate("table.field.flowStepInstance.stepCode")} /> |
| | | <TextField source="stepName" label={translate("table.field.flowStepInstance.stepName")} /> |
| | | <TextField source="stepType" label={translate("table.field.flowStepInstance.stepType")} /> |
| | | <NumberField source="status" label={translate("table.field.flowStepInstance.status")} /> |
| | | <TextField source="executeResult" label={translate("table.field.flowStepInstance.executeResult")} /> |
| | | <TextField source="taskNo" label={translate("table.field.flowStepInstance.taskNo")} /> |
| | | <DateField source="createTime" label={translate("table.field.flowStepInstance.createTime")} showTime /> |
| | | <WrapperField cellClassName="opt" label="common.field.opt" onClick={(e) => e.stopPropagation()} > |
| | | <RowActions onEdit={handleEdit} onDelete={handleDelete} /> |
| | | </WrapperField> |
| | | </StyledDatagrid> |
| | | </DialogContent> |
| | | <DialogActions> |
| | | <Button label="ra.action.close" onClick={handleClose} /> |
| | | </DialogActions> |
| | | </Dialog> |
| | | |
| | | {/* Nested Form Dialog */} |
| | | <Dialog open={formOpen} onClose={handleFormClose} fullWidth maxWidth="sm"> |
| | | <DialogTitle> |
| | | {isEdit ? translate("ra.action.edit") : translate("ra.action.create")} |
| | | </DialogTitle> |
| | | <DialogContent> |
| | | <SimpleForm record={formData} onSubmit={handleSave} toolbar={<CustomToolbar />}> |
| | | <TextInput source="taskNo" disabled fullWidth label={translate("table.field.flowStepInstance.taskNo")} /> |
| | | <NumberInput source="stepOrder" required fullWidth label={translate("table.field.flowStepInstance.stepOrder")} /> |
| | | <TextInput source="stepCode" required fullWidth label={translate("table.field.flowStepInstance.stepCode")} /> |
| | | <TextInput source="stepName" required fullWidth label={translate("table.field.flowStepInstance.stepName")} /> |
| | | <TextInput source="stepType" required fullWidth label={translate("table.field.flowStepInstance.stepType")} /> |
| | | <SelectInput source="status" label={translate("table.field.flowStepInstance.status")} choices={[ |
| | | { id: 0, name: '排队中' }, |
| | | { id: 1, name: '待执行' }, |
| | | { id: 2, name: '执行中' }, |
| | | { id: 3, name: '执行成功' }, |
| | | { id: 4, name: '执行失败' }, |
| | | { id: 5, name: '已跳过' }, |
| | | { id: 6, name: '已取消' } |
| | | ]} required fullWidth /> |
| | | <TextInput source="executeResult" fullWidth label={translate("table.field.flowStepInstance.executeResult")} /> |
| | | </SimpleForm> |
| | | </DialogContent> |
| | | </Dialog> |
| | | </React.Fragment> |
| | | ); |
| | | }; |
| | | |
| | | const RowActions = ({ onEdit, onDelete }) => { |
| | | const record = useRecordContext(); |
| | | return ( |
| | | <Box display="flex"> |
| | | <Tooltip title="Edit"> |
| | | <IconButton onClick={() => onEdit(record)} size="small" color="primary"> |
| | | <EditIcon fontSize="small" /> |
| | | </IconButton> |
| | | </Tooltip> |
| | | {/* If there's an issue with event propagation you might need to handle it in onClick */} |
| | | <Tooltip title="Delete"> |
| | | <IconButton onClick={() => onDelete(record)} size="small" color="error"> |
| | | <DeleteIcon fontSize="small" /> |
| | | </IconButton> |
| | | </Tooltip> |
| | | </Box> |
| | | ); |
| | | }; |
| | | |
| | | const CustomToolbar = props => ( |
| | | <Toolbar {...props}> |
| | | <Button label="ra.action.save" type="submit" variant="contained" /> |
| | | </Toolbar> |
| | | ); |
| | | |
| | | export default FlowStepInstanceModal; |