import { useEffect, useMemo, useState } from 'react' import { Button, Modal, Space, Table, message, Typography, Input, Form, Tooltip, Popconfirm } from 'antd' import { PlusOutlined, ReloadOutlined, DeleteOutlined, EditOutlined, EyeOutlined } from '@ant-design/icons' import { useNavigate } from 'react-router-dom' import api, { type ApiResp } from '../utils/axios' import dayjs from 'dayjs' interface FlowSummary { id: string; name: string; code?: string; remark?: string; created_at: string; updated_at: string; last_modified_by?: string } // 新增:扩展 Doc 以便复用 interface FlowDoc { id: string; yaml: string } // 后端创建/更新入参 interface FlowCreateReq { name?: string; yaml?: string; design_json?: any; code?: string; remark?: string } interface FlowUpdateReq { name?: string; yaml?: string; design_json?: any; code?: string; remark?: string } interface PageResp { items: T[]; total: number; page: number; page_size: number } export default function FlowList() { const [loading, setLoading] = useState(false) const [list, setList] = useState([]) const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(10) const [total, setTotal] = useState(0) const [keyword, setKeyword] = useState('') const [searchForm] = Form.useForm() const navigate = useNavigate() // 编辑基础信息弹窗状态 const [editOpen, setEditOpen] = useState(false) const [editing, setEditing] = useState(false) const [editRow, setEditRow] = useState(null) const [editName, setEditName] = useState('') // 新建弹窗状态 const [createOpen, setCreateOpen] = useState(false) const [createForm] = Form.useForm() // 编辑表单 const [editForm] = Form.useForm() const fetchList = async (p: number = page, ps: number = pageSize, kw: string = keyword) => { setLoading(true) try { const { data } = await api.get>>('/flows', { params: { page: p, page_size: ps, keyword: kw || undefined } }) if (data?.code === 0) { setList(data.data?.items || []) setTotal(data.data?.total || 0) setPage(data.data?.page || p) setPageSize(data.data?.page_size || ps) } } catch (e: any) { message.error(e?.message || '加载失败') } finally { setLoading(false) } } const openEdit = (row: FlowSummary) => { setEditRow(row) setEditName(row.name || '') // 先重置表单,避免上一次的 code/remark 残留 editForm.resetFields() // 预填表单为当前行已有数据(若无则为空) editForm.setFieldsValue({ name: row.name || '', code: row.code || undefined, remark: row.remark || undefined }) setEditOpen(true) // 尝试拉取详情以补充 code/remark ;(async () => { try { const { data } = await api.get(`/flows/${row.id}`) // 兼容后端仅返回 yaml 的场景 const detail: any = data?.data || {} const patch: any = {} if (detail?.name !== undefined) patch.name = detail.name if (detail?.code !== undefined) patch.code = detail.code if (detail?.remark !== undefined) patch.remark = detail.remark if (Object.keys(patch).length) editForm.setFieldsValue(patch) } catch {} })() } const handleEditOk = async () => { if (!editRow) return try { const values = await editForm.validateFields() const payload: FlowUpdateReq = { name: (values.name || '').trim(), code: values.code ? String(values.code).trim() : undefined, remark: values.remark ? String(values.remark).trim() : undefined, } setEditing(true) const { data } = await api.put(`/flows/${editRow.id}`, payload) if (data?.code === 0) { message.success('已保存') setEditOpen(false) // 保存成功后刷新列表,保证时间与最近修改人同步更新 fetchList(page, pageSize, keyword) // 重置编辑状态 editForm.resetFields() setEditRow(null) setEditName('') } else { throw new Error(data?.message || '保存失败') } } catch (e: any) { if (e?.errorFields) return // 表单校验错误 message.error(e?.message || '保存失败') } finally { setEditing(false) } } const columns = useMemo(() => [ { title: '流程编号', dataIndex: 'code', width: 160 }, { title: '名称', dataIndex: 'name', width: 280, ellipsis: { showTitle: false }, render: (text: string) => ( {text || '-'} ) }, { title: '备注', dataIndex: 'remark', width: 220, ellipsis: { showTitle: false }, render: (text?: string) => ( {text || '-'} ) }, { title: '新建时间', dataIndex: 'created_at', width: 180, render: (v: string) => v ? dayjs(v).format('YYYY-MM-DD HH:mm:ss') : '' }, { title: '最近修改时间', dataIndex: 'updated_at', width: 180, render: (v: string) => v ? dayjs(v).format('YYYY-MM-DD HH:mm:ss') : '' }, { title: '最近修改人', dataIndex: 'last_modified_by', width: 140 }, { title: '操作', key: 'action', width: 320, render: (_: any, row: FlowSummary) => ( onDelete(row)}> 删除 ) } ], []) useEffect(() => { fetchList(1, 10, '') }, []) const onCreate = async () => { // 打开新建弹窗,让用户填写名称/编号/备注 createForm.resetFields() setCreateOpen(true) } const handleCreateOk = async () => { try{ const values = await createForm.validateFields() const payload: FlowCreateReq = { name: (values.name || '').trim(), code: values.code ? String(values.code).trim() : undefined, remark: values.remark ? String(values.remark).trim() : undefined } const { data } = await api.post('/flows', payload) if(data?.code === 0){ message.success('创建成功') setCreateOpen(false) fetchList(page, pageSize, keyword) }else{ throw new Error(data?.message || '创建失败') } }catch(e: any){ if(e?.errorFields) return; // 表单校验未通过 message.error(e?.message || '创建失败') } } const onDelete = async (row: FlowSummary) => { try { const { data } = await api.delete>(`/flows/${row.id}`) if (data?.code === 0) { message.success('删除成功') fetchList(page, pageSize, keyword) } else { throw new Error(data?.message || '删除失败') } } catch (e: any) { message.error(e?.message || '删除失败') } } const onView = async (row: FlowSummary) => { try { const { data } = await api.get>(`/flows/${row.id}`) if (data?.code === 0) { Modal.info({ title: `流程内容 - ${row.name}`, width: 720, content: (
{data.data?.yaml}
            
) }) } } catch (e: any) { message.error(e?.message || '加载失败') } } return (
{ const kw = String(vals?.keyword ?? '').trim(); setKeyword(kw) fetchList(1, pageSize, kw) }} >
fetchList(p, ps ?? pageSize, keyword) }} /> {/* 编辑基础信息弹窗 */} { setEditOpen(false); setEditRow(null); setEditName(''); editForm.resetFields() }} okText="保存" destroyOnHidden maskClosable={false} >
{/* 新建弹窗 */} setCreateOpen(false)} destroyOnHidden maskClosable={false} >
{/* 编辑弹窗(冗余,禁用) */} setEditOpen(false)} okText="保存" >
名称 setEditName(e.target.value)} placeholder="请输入流程名称" maxLength={50} showCount />
) }