From f07c5f38c7262129adb1dfe916956dcc4ab2c140 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期六, 07 三月 2026 14:25:40 +0800
Subject: [PATCH] #任务步骤
---
rsf-admin/src/page/task/FlowStepInstanceModal.jsx | 243 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 243 insertions(+), 0 deletions(-)
diff --git a/rsf-admin/src/page/task/FlowStepInstanceModal.jsx b/rsf-admin/src/page/task/FlowStepInstanceModal.jsx
new file mode 100644
index 0000000..fa71460
--- /dev/null
+++ b/rsf-admin/src/page/task/FlowStepInstanceModal.jsx
@@ -0,0 +1,243 @@
+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;
--
Gitblit v1.9.1