1
This commit is contained in:
parent
ecf12a22a0
commit
2d3cd8db92
@ -1,7 +1,7 @@
|
|||||||
import React, {useEffect} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import {Modal, Form, Input, message} from 'antd';
|
import {Modal, Form, Input, message, Select} from 'antd';
|
||||||
import type {WorkflowDefinition} from '../types';
|
import type {WorkflowDefinition, WorkflowCategory} from '../types';
|
||||||
import {saveDefinition, updateDefinition} from '../service';
|
import {saveDefinition, updateDefinition, getWorkflowCategories} from '../service';
|
||||||
|
|
||||||
interface EditModalProps {
|
interface EditModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -13,27 +13,74 @@ interface EditModalProps {
|
|||||||
const EditModal: React.FC<EditModalProps> = ({visible, onClose, onSuccess, record}) => {
|
const EditModal: React.FC<EditModalProps> = ({visible, onClose, onSuccess, record}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const isEdit = !!record;
|
const isEdit = !!record;
|
||||||
|
const [categories, setCategories] = useState<WorkflowCategory[]>([]);
|
||||||
|
const [selectedCategory, setSelectedCategory] = useState<WorkflowCategory>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (visible) {
|
||||||
|
loadCategories();
|
||||||
|
}
|
||||||
|
}, [visible]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible && record) {
|
if (visible && record) {
|
||||||
form.setFieldsValue(record);
|
// 找到当前分类
|
||||||
|
const category = categories.find(c => c.code === record.category);
|
||||||
|
setSelectedCategory(category);
|
||||||
|
|
||||||
|
// 设置表单值,使用lable显示
|
||||||
|
form.setFieldsValue({
|
||||||
|
...record,
|
||||||
|
// 分类显示lable
|
||||||
|
category: {
|
||||||
|
label: category?.lable,
|
||||||
|
value: record.category
|
||||||
|
},
|
||||||
|
// 触发器显示lable
|
||||||
|
triggers: record.triggers?.map(triggerCode => ({
|
||||||
|
label: category?.supportedTriggers.find(t => t.code === triggerCode)?.lable,
|
||||||
|
value: triggerCode
|
||||||
|
})) || []
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [visible, record]);
|
}, [visible, record, categories]);
|
||||||
|
|
||||||
|
const loadCategories = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getWorkflowCategories();
|
||||||
|
setCategories(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载工作流分类失败:', error);
|
||||||
|
message.error('加载工作流分类失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCategoryChange = (selected: { value: string, label: string }) => {
|
||||||
|
const category = categories.find(c => c.code === selected.value);
|
||||||
|
setSelectedCategory(category);
|
||||||
|
// 当切换分类时,清空触发器选择
|
||||||
|
form.setFieldValue('triggers', []);
|
||||||
|
};
|
||||||
|
|
||||||
const handleOk = async () => {
|
const handleOk = async () => {
|
||||||
try {
|
try {
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
|
const submitData = {
|
||||||
|
...values,
|
||||||
|
// 提取code值提交给后端
|
||||||
|
category: values.category.value,
|
||||||
|
triggers: values.triggers.map((t: {value: string}) => t.value),
|
||||||
|
flowVersion: isEdit ? record.flowVersion : 1,
|
||||||
|
status: isEdit ? record.status : 'DRAFT'
|
||||||
|
};
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
await updateDefinition(record.id, {
|
await updateDefinition(record.id, {
|
||||||
...record,
|
...record,
|
||||||
...values,
|
...submitData,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await saveDefinition({
|
await saveDefinition(submitData as WorkflowDefinition);
|
||||||
...values,
|
|
||||||
flowVersion: 1,
|
|
||||||
status: 'DRAFT'
|
|
||||||
} as WorkflowDefinition);
|
|
||||||
}
|
}
|
||||||
message.success(isEdit ? '更新成功' : '保存成功');
|
message.success(isEdit ? '更新成功' : '保存成功');
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
@ -62,6 +109,42 @@ const EditModal: React.FC<EditModalProps> = ({visible, onClose, onSuccess, recor
|
|||||||
layout="vertical"
|
layout="vertical"
|
||||||
preserve={false}
|
preserve={false}
|
||||||
>
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="category"
|
||||||
|
label="流程分类"
|
||||||
|
rules={[{required: true, message: '请选择流程分类'}]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder="请选择流程分类"
|
||||||
|
onChange={handleCategoryChange}
|
||||||
|
disabled={isEdit}
|
||||||
|
labelInValue
|
||||||
|
>
|
||||||
|
{(categories || []).map(category => (
|
||||||
|
<Select.Option key={category.code} value={category.code}>
|
||||||
|
{category.lable}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="triggers"
|
||||||
|
label="触发方式"
|
||||||
|
rules={[{required: true, message: '请选择触发方式'}]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
placeholder="请选择触发方式"
|
||||||
|
disabled={!selectedCategory || isEdit}
|
||||||
|
labelInValue
|
||||||
|
>
|
||||||
|
{(selectedCategory?.supportedTriggers || []).map(trigger => (
|
||||||
|
<Select.Option key={trigger.code} value={trigger.code}>
|
||||||
|
{trigger.lable}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="name"
|
name="name"
|
||||||
label="流程名称"
|
label="流程名称"
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import {Table, Card, Button, Space, Tag, message, Modal} from 'antd';
|
|||||||
import {PlusOutlined, ExclamationCircleOutlined} from '@ant-design/icons';
|
import {PlusOutlined, ExclamationCircleOutlined} from '@ant-design/icons';
|
||||||
import {useNavigate} from 'react-router-dom';
|
import {useNavigate} from 'react-router-dom';
|
||||||
import * as service from './service';
|
import * as service from './service';
|
||||||
import type {WorkflowDefinition, WorkflowDefinitionQuery} from './types';
|
import type {WorkflowDefinition, WorkflowDefinitionQuery, WorkflowCategory} from './types';
|
||||||
import {DEFAULT_PAGE_SIZE, DEFAULT_CURRENT} from '@/utils/page';
|
import {DEFAULT_PAGE_SIZE, DEFAULT_CURRENT} from '@/utils/page';
|
||||||
import EditModal from './components/EditModal';
|
import EditModal from './components/EditModal';
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ const WorkflowDefinitionList: React.FC = () => {
|
|||||||
} | null>(null);
|
} | null>(null);
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
const [currentRecord, setCurrentRecord] = useState<WorkflowDefinition>();
|
const [currentRecord, setCurrentRecord] = useState<WorkflowDefinition>();
|
||||||
|
const [categories, setCategories] = useState<WorkflowCategory[]>([]);
|
||||||
const [query, setQuery] = useState<WorkflowDefinitionQuery>({
|
const [query, setQuery] = useState<WorkflowDefinitionQuery>({
|
||||||
pageNum: DEFAULT_CURRENT - 1,
|
pageNum: DEFAULT_CURRENT - 1,
|
||||||
pageSize: DEFAULT_PAGE_SIZE
|
pageSize: DEFAULT_PAGE_SIZE
|
||||||
@ -39,8 +40,19 @@ const WorkflowDefinitionList: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadCategories = async () => {
|
||||||
|
try {
|
||||||
|
const data = await service.getWorkflowCategories();
|
||||||
|
setCategories(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载工作流分类失败:', error);
|
||||||
|
message.error('加载工作流分类失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadData(query);
|
loadData(query);
|
||||||
|
loadCategories();
|
||||||
}, [query]);
|
}, [query]);
|
||||||
|
|
||||||
const handleCreateFlow = () => {
|
const handleCreateFlow = () => {
|
||||||
@ -62,20 +74,80 @@ const WorkflowDefinitionList: React.FC = () => {
|
|||||||
setCurrentRecord(undefined);
|
setCurrentRecord(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeploy = async (id: number) => {
|
||||||
|
confirm({
|
||||||
|
title: '确认发布',
|
||||||
|
icon: <ExclamationCircleOutlined/>,
|
||||||
|
content: '确定要发布该流程定义吗?发布后将不能修改。',
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await service.publishDefinition(id);
|
||||||
|
message.success('发布成功');
|
||||||
|
loadData(query);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
message.error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async (id: number) => {
|
||||||
|
confirm({
|
||||||
|
title: '确认删除',
|
||||||
|
icon: <ExclamationCircleOutlined/>,
|
||||||
|
content: '确定要删除该流程定义吗?删除后不可恢复。',
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await service.deleteDefinition(id);
|
||||||
|
message.success('删除成功');
|
||||||
|
loadData(query);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
message.error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '流程名称',
|
title: '流程名称',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
render: (text: string, record: WorkflowDefinition) => (
|
|
||||||
<a onClick={() => navigate(`/workflow-definitions/${record.id}`)}>{text}</a>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '流程标识',
|
title: '流程标识',
|
||||||
dataIndex: 'key',
|
dataIndex: 'key',
|
||||||
key: 'key',
|
key: 'key',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '流程分类',
|
||||||
|
dataIndex: 'category',
|
||||||
|
key: 'category',
|
||||||
|
render: (category: string) => {
|
||||||
|
const categoryInfo = categories.find(c => c.code === category);
|
||||||
|
return categoryInfo?.lable || category;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '触发方式',
|
||||||
|
dataIndex: 'triggers',
|
||||||
|
key: 'triggers',
|
||||||
|
render: (triggers: string[], record: WorkflowDefinition) => {
|
||||||
|
const categoryInfo = categories.find(c => c.code === record.category);
|
||||||
|
return (triggers || [])?.map(triggerCode => {
|
||||||
|
const triggerInfo = categoryInfo?.supportedTriggers?.find(t => t.code === triggerCode);
|
||||||
|
return (
|
||||||
|
<Tag key={triggerCode}>
|
||||||
|
{triggerInfo?.lable || triggerCode}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '版本',
|
title: '版本',
|
||||||
dataIndex: 'flowVersion',
|
dataIndex: 'flowVersion',
|
||||||
@ -117,70 +189,30 @@ const WorkflowDefinitionList: React.FC = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleDeploy = async (id: number) => {
|
|
||||||
confirm({
|
|
||||||
title: '确认发布',
|
|
||||||
icon: <ExclamationCircleOutlined/>,
|
|
||||||
content: '确定要发布该流程定义吗?发布后将不能修改。',
|
|
||||||
onOk: async () => {
|
|
||||||
try {
|
|
||||||
await service.publishDefinition(id);
|
|
||||||
message.success('发布成功');
|
|
||||||
loadData(query);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Error) {
|
|
||||||
message.error(error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDelete = async (id: number) => {
|
|
||||||
confirm({
|
|
||||||
title: '确认删除',
|
|
||||||
icon: <ExclamationCircleOutlined/>,
|
|
||||||
content: '确定要删除该流程定义吗?删除后不可恢复。',
|
|
||||||
onOk: async () => {
|
|
||||||
try {
|
|
||||||
await service.deleteDefinition(id);
|
|
||||||
message.success('删除成功');
|
|
||||||
loadData(query);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Error) {
|
|
||||||
message.error(error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={
|
title={
|
||||||
<Button
|
<Button type="primary" icon={<PlusOutlined/>} onClick={handleCreateFlow}>
|
||||||
type="primary"
|
|
||||||
icon={<PlusOutlined/>}
|
|
||||||
onClick={handleCreateFlow}
|
|
||||||
>
|
|
||||||
新建流程
|
新建流程
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
|
||||||
dataSource={pageData?.content}
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
dataSource={pageData?.content}
|
||||||
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
pagination={{
|
pagination={{
|
||||||
total: pageData?.totalElements,
|
total: pageData?.totalElements,
|
||||||
pageSize: pageData?.size || DEFAULT_PAGE_SIZE,
|
pageSize: query.pageSize,
|
||||||
current: (pageData?.number || 0) + 1,
|
current: query.pageNum + 1,
|
||||||
showSizeChanger: true,
|
|
||||||
showQuickJumper: true,
|
|
||||||
onChange: (page, pageSize) => {
|
onChange: (page, pageSize) => {
|
||||||
setQuery({...query, pageNum: page - 1, pageSize});
|
setQuery({
|
||||||
},
|
...query,
|
||||||
|
pageNum: page - 1,
|
||||||
|
pageSize
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<EditModal
|
<EditModal
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import {WorkflowDefinition, WorkflowDefinitionQuery} from './types';
|
import {WorkflowDefinition, WorkflowDefinitionQuery} from './types';
|
||||||
import {Page} from '@/types/base';
|
import {Page} from '@/types/base';
|
||||||
|
import {WorkflowCategory} from './types'; // Add this line
|
||||||
|
|
||||||
const DEFINITION_URL = '/api/v1/workflow/definition';
|
const DEFINITION_URL = '/api/v1/workflow/definition';
|
||||||
|
|
||||||
@ -29,3 +30,18 @@ export const updateDefinition = (id: number, data: WorkflowDefinition) =>
|
|||||||
*/
|
*/
|
||||||
export const publishDefinition = (id: number) =>
|
export const publishDefinition = (id: number) =>
|
||||||
request.post<void>(`${DEFINITION_URL}/${id}/published`);
|
request.post<void>(`${DEFINITION_URL}/${id}/published`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工作流分类列表
|
||||||
|
* @returns Promise<WorkflowCategory[]> 工作流分类列表
|
||||||
|
*/
|
||||||
|
export const getWorkflowCategories = () =>
|
||||||
|
request.get<WorkflowCategory[]>(`${DEFINITION_URL}/categories`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工作流分类
|
||||||
|
* @param id 工作流分类ID
|
||||||
|
* @returns Promise<WorkflowCategory> 工作流分类
|
||||||
|
*/
|
||||||
|
export const getWorkflowCategory = (id: number) =>
|
||||||
|
request.get<WorkflowCategory>(`${DEFINITION_URL}/categories/${id}`);
|
||||||
@ -1,11 +1,14 @@
|
|||||||
import { BaseResponse, BaseQuery } from '@/types/base';
|
import { BaseResponse, BaseQuery } from '@/types/base';
|
||||||
|
|
||||||
export interface WorkflowDefinition extends BaseResponse {
|
export interface WorkflowDefinition extends BaseResponse {
|
||||||
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
key: string;
|
key: string;
|
||||||
flowVersion: number;
|
description?: string;
|
||||||
status: string;
|
flowVersion?: number;
|
||||||
description: string;
|
status?: string;
|
||||||
|
category: string;
|
||||||
|
triggers: string[];
|
||||||
graph: {
|
graph: {
|
||||||
nodes: any[];
|
nodes: any[];
|
||||||
edges: any[];
|
edges: any[];
|
||||||
@ -20,3 +23,21 @@ export interface WorkflowDefinitionQuery extends BaseQuery {
|
|||||||
key?: string;
|
key?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流触发器类型
|
||||||
|
*/
|
||||||
|
export interface WorkflowTrigger {
|
||||||
|
code: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流分类
|
||||||
|
*/
|
||||||
|
export interface WorkflowCategory {
|
||||||
|
code: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
supportedTriggers: WorkflowTrigger[];
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user