feat: 2.6.0

1. 添加删除功能
2. 添加开关工作流功能
3. 新增复制按钮待实现
This commit is contained in:
byteblogs168 2023-12-29 23:27:23 +08:00
parent a6352e498e
commit 426063dd23
7 changed files with 119 additions and 59 deletions

View File

@ -37,7 +37,7 @@ public class WorkflowController {
@GetMapping("/page/list") @GetMapping("/page/list")
@LoginRequired(role = RoleEnum.USER) @LoginRequired(role = RoleEnum.USER)
public PageResult<List<WorkflowResponseVO>> listPage(WorkflowQueryVO queryVO) { public PageResult<List<WorkflowResponseVO>> listPage(WorkflowQueryVO queryVO) {
return workflowService.listPage(queryVO); return workflowService.listPage(queryVO);
} }
@PutMapping @PutMapping
@ -49,7 +49,17 @@ public class WorkflowController {
@GetMapping("{id}") @GetMapping("{id}")
@LoginRequired(role = RoleEnum.USER) @LoginRequired(role = RoleEnum.USER)
public WorkflowDetailResponseVO getWorkflowDetail(@PathVariable("id") Long id) throws IOException { public WorkflowDetailResponseVO getWorkflowDetail(@PathVariable("id") Long id) throws IOException {
return workflowService.getWorkflowDetail(id); return workflowService.getWorkflowDetail(id);
}
@PutMapping("/update/status/{id}")
public Boolean updateStatus(@PathVariable("id") Long id) {
return workflowService.updateStatus(id);
}
@DeleteMapping("/{id}")
public Boolean deleteById(@PathVariable("id") Long id) {
return workflowService.deleteById(id);
} }
@PostMapping("/start") @PostMapping("/start")

View File

@ -18,6 +18,11 @@ public class WorkflowDetailResponseVO {
*/ */
private Long id; private Long id;
/**
* 组名称
*/
private String workflowName;
/** /**
* 组名称 * 组名称
*/ */

View File

@ -23,4 +23,8 @@ public interface WorkflowService {
PageResult<List<WorkflowResponseVO>> listPage(WorkflowQueryVO queryVO); PageResult<List<WorkflowResponseVO>> listPage(WorkflowQueryVO queryVO);
Boolean updateWorkflow(WorkflowRequestVO workflowRequestVO); Boolean updateWorkflow(WorkflowRequestVO workflowRequestVO);
Boolean updateStatus(Long id);
Boolean deleteById(Long id);
} }

View File

@ -76,7 +76,7 @@ public class WorkflowServiceImpl implements WorkflowService {
workflow.setNextTriggerAt(calculateNextTriggerAt(workflowRequestVO, DateUtils.toNowMilli())); workflow.setNextTriggerAt(calculateNextTriggerAt(workflowRequestVO, DateUtils.toNowMilli()));
workflow.setFlowInfo(StrUtil.EMPTY); workflow.setFlowInfo(StrUtil.EMPTY);
workflow.setBucketIndex(HashUtil.bkdrHash(workflowRequestVO.getGroupName() + workflowRequestVO.getWorkflowName()) workflow.setBucketIndex(HashUtil.bkdrHash(workflowRequestVO.getGroupName() + workflowRequestVO.getWorkflowName())
% systemProperties.getBucketTotal()); % systemProperties.getBucketTotal());
workflow.setNamespaceId(UserSessionUtils.currentUserSession().getNamespaceId()); workflow.setNamespaceId(UserSessionUtils.currentUserSession().getNamespaceId());
Assert.isTrue(1 == workflowMapper.insert(workflow), () -> new EasyRetryServerException("新增工作流失败")); Assert.isTrue(1 == workflowMapper.insert(workflow), () -> new EasyRetryServerException("新增工作流失败"));
@ -85,7 +85,7 @@ public class WorkflowServiceImpl implements WorkflowService {
// 递归构建图 // 递归构建图
buildGraph(Lists.newArrayList(SystemConstants.ROOT), new LinkedBlockingDeque<>(), buildGraph(Lists.newArrayList(SystemConstants.ROOT), new LinkedBlockingDeque<>(),
workflowRequestVO.getGroupName(), workflow.getId(), nodeConfig, graph); workflowRequestVO.getGroupName(), workflow.getId(), nodeConfig, graph);
log.info("图构建完成. graph:[{}]", graph); log.info("图构建完成. graph:[{}]", graph);
// 保存图信息 // 保存图信息
@ -113,21 +113,21 @@ public class WorkflowServiceImpl implements WorkflowService {
WorkflowDetailResponseVO responseVO = WorkflowConverter.INSTANCE.toWorkflowDetailResponseVO(workflow); WorkflowDetailResponseVO responseVO = WorkflowConverter.INSTANCE.toWorkflowDetailResponseVO(workflow);
List<WorkflowNode> workflowNodes = workflowNodeMapper.selectList(new LambdaQueryWrapper<WorkflowNode>() List<WorkflowNode> workflowNodes = workflowNodeMapper.selectList(new LambdaQueryWrapper<WorkflowNode>()
.eq(WorkflowNode::getDeleted, 0) .eq(WorkflowNode::getDeleted, 0)
.eq(WorkflowNode::getWorkflowId, id) .eq(WorkflowNode::getWorkflowId, id)
.orderByAsc(WorkflowNode::getPriorityLevel)); .orderByAsc(WorkflowNode::getPriorityLevel));
List<WorkflowDetailResponseVO.NodeInfo> nodeInfos = WorkflowConverter.INSTANCE.toNodeInfo(workflowNodes); List<WorkflowDetailResponseVO.NodeInfo> nodeInfos = WorkflowConverter.INSTANCE.toNodeInfo(workflowNodes);
Map<Long, WorkflowDetailResponseVO.NodeInfo> workflowNodeMap = nodeInfos.stream() Map<Long, WorkflowDetailResponseVO.NodeInfo> workflowNodeMap = nodeInfos.stream()
.collect(Collectors.toMap(WorkflowDetailResponseVO.NodeInfo::getId, i -> i)); .collect(Collectors.toMap(WorkflowDetailResponseVO.NodeInfo::getId, i -> i));
String flowInfo = workflow.getFlowInfo(); String flowInfo = workflow.getFlowInfo();
try { try {
MutableGraph<Long> graph = GraphUtils.deserializeJsonToGraph(flowInfo); MutableGraph<Long> graph = GraphUtils.deserializeJsonToGraph(flowInfo);
// 反序列化构建图 // 反序列化构建图
WorkflowDetailResponseVO.NodeConfig config = buildNodeConfig(graph, SystemConstants.ROOT, new HashMap<>(), WorkflowDetailResponseVO.NodeConfig config = buildNodeConfig(graph, SystemConstants.ROOT, new HashMap<>(),
workflowNodeMap); workflowNodeMap);
responseVO.setNodeConfig(config); responseVO.setNodeConfig(config);
} catch (Exception e) { } catch (Exception e) {
log.error("反序列化失败. json:[{}]", flowInfo, e); log.error("反序列化失败. json:[{}]", flowInfo, e);
@ -159,8 +159,8 @@ public class WorkflowServiceImpl implements WorkflowService {
Assert.notNull(workflowRequestVO.getId(), () -> new EasyRetryServerException("工作流ID不能为空")); Assert.notNull(workflowRequestVO.getId(), () -> new EasyRetryServerException("工作流ID不能为空"));
Assert.isTrue(workflowMapper.selectCount(new LambdaQueryWrapper<Workflow>() Assert.isTrue(workflowMapper.selectCount(new LambdaQueryWrapper<Workflow>()
.eq(Workflow::getId, workflowRequestVO.getId())) > 0, .eq(Workflow::getId, workflowRequestVO.getId())) > 0,
() -> new EasyRetryServerException("工作流不存在")); () -> new EasyRetryServerException("工作流不存在"));
MutableGraph<Long> graph = GraphBuilder.directed().allowsSelfLoops(false).build(); MutableGraph<Long> graph = GraphBuilder.directed().allowsSelfLoops(false).build();
// 添加虚拟头节点 // 添加虚拟头节点
@ -171,7 +171,7 @@ public class WorkflowServiceImpl implements WorkflowService {
// 递归构建图 // 递归构建图
buildGraph(Lists.newArrayList(SystemConstants.ROOT), new LinkedBlockingDeque<>(), buildGraph(Lists.newArrayList(SystemConstants.ROOT), new LinkedBlockingDeque<>(),
workflowRequestVO.getGroupName(), workflowRequestVO.getId(), nodeConfig, graph); workflowRequestVO.getGroupName(), workflowRequestVO.getId(), nodeConfig, graph);
log.info("图构建完成. graph:[{}]", graph); log.info("图构建完成. graph:[{}]", graph);
@ -184,10 +184,35 @@ public class WorkflowServiceImpl implements WorkflowService {
return Boolean.TRUE; return Boolean.TRUE;
} }
@Override
public Boolean updateStatus(Long id) {
Workflow workflow = workflowMapper.selectOne(
new LambdaQueryWrapper<Workflow>()
.select(Workflow::getId, Workflow::getWorkflowStatus)
.eq(Workflow::getId, id));
Assert.notNull(workflow, () -> new EasyRetryServerException("工作流不存在"));
if (Objects.equals(workflow.getWorkflowStatus(), StatusEnum.NO.getStatus())) {
workflow.setWorkflowStatus(StatusEnum.YES.getStatus());
} else {
workflow.setWorkflowStatus(StatusEnum.NO.getStatus());
}
return 1 == workflowMapper.updateById(workflow);
}
@Override
public Boolean deleteById(Long id) {
Workflow workflow = new Workflow();
workflow.setId(id);
workflow.setDeleted(StatusEnum.YES.getStatus());
return 1 == workflowMapper.updateById(workflow);
}
private WorkflowDetailResponseVO.NodeConfig buildNodeConfig(MutableGraph<Long> graph, private WorkflowDetailResponseVO.NodeConfig buildNodeConfig(MutableGraph<Long> graph,
Long parentId, Long parentId,
Map<Long, WorkflowDetailResponseVO.NodeConfig> nodeConfigMap, Map<Long, WorkflowDetailResponseVO.NodeConfig> nodeConfigMap,
Map<Long, WorkflowDetailResponseVO.NodeInfo> workflowNodeMap) { Map<Long, WorkflowDetailResponseVO.NodeInfo> workflowNodeMap) {
Set<Long> successors = graph.successors(parentId); Set<Long> successors = graph.successors(parentId);
if (CollectionUtils.isEmpty(successors)) { if (CollectionUtils.isEmpty(successors)) {
@ -254,7 +279,7 @@ public class WorkflowServiceImpl implements WorkflowService {
} }
public void buildGraph(List<Long> parentIds, LinkedBlockingDeque<Long> deque, String groupName, Long workflowId, public void buildGraph(List<Long> parentIds, LinkedBlockingDeque<Long> deque, String groupName, Long workflowId,
NodeConfig nodeConfig, MutableGraph<Long> graph) { NodeConfig nodeConfig, MutableGraph<Long> graph) {
if (Objects.isNull(nodeConfig)) { if (Objects.isNull(nodeConfig)) {
return; return;
@ -273,7 +298,7 @@ public class WorkflowServiceImpl implements WorkflowService {
} }
Assert.isTrue(1 == workflowNodeMapper.insert(workflowNode), Assert.isTrue(1 == workflowNodeMapper.insert(workflowNode),
() -> new EasyRetryServerException("新增工作流节点失败")); () -> new EasyRetryServerException("新增工作流节点失败"));
// 添加节点 // 添加节点
graph.addNode(workflowNode.getId()); graph.addNode(workflowNode.getId());
for (final Long parentId : parentIds) { for (final Long parentId : parentIds) {
@ -281,11 +306,11 @@ public class WorkflowServiceImpl implements WorkflowService {
graph.putEdge(parentId, workflowNode.getId()); graph.putEdge(parentId, workflowNode.getId());
} }
log.warn("workflowNodeId:[{}] parentIds:[{}]", log.warn("workflowNodeId:[{}] parentIds:[{}]",
workflowNode.getId(), JsonUtil.toJsonString(parentIds)); workflowNode.getId(), JsonUtil.toJsonString(parentIds));
NodeConfig childNode = nodeInfo.getChildNode(); NodeConfig childNode = nodeInfo.getChildNode();
if (Objects.nonNull(childNode) && !CollectionUtils.isEmpty(childNode.getConditionNodes())) { if (Objects.nonNull(childNode) && !CollectionUtils.isEmpty(childNode.getConditionNodes())) {
buildGraph(Lists.newArrayList(workflowNode.getId()), deque, groupName, workflowId, childNode, buildGraph(Lists.newArrayList(workflowNode.getId()), deque, groupName, workflowId, childNode,
graph); graph);
} else { } else {
// 叶子节点记录一下 // 叶子节点记录一下
deque.add(workflowNode.getId()); deque.add(workflowNode.getId());

View File

@ -35,11 +35,27 @@ const jobApi = {
updateWorkflow: '/workflow', updateWorkflow: '/workflow',
workflowDetail: '/workflow', workflowDetail: '/workflow',
workflowBatchListPage: '/workflow/batch/page/list', workflowBatchListPage: '/workflow/batch/page/list',
workflowBatchDetail: '/workflow/batch/' workflowBatchDetail: '/workflow/batch/',
updateStatus: '/workflow/update/status/',
delWorkflow: '/workflow/'
} }
export default jobApi export default jobApi
export function delWorkflow (id) {
return request({
url: jobApi.delWorkflow + id,
method: 'delete'
})
}
export function updateWorkflowStatus (id) {
return request({
url: jobApi.updateStatus + id,
method: 'put'
})
}
export function workflowBatchDetail (id) { export function workflowBatchDetail (id) {
return request({ return request({
url: jobApi.workflowBatchDetail + id, url: jobApi.workflowBatchDetail + id,

View File

@ -209,19 +209,6 @@ export const asyncRouterMap = [
component: () => import('@/views/job/JobTaskList'), component: () => import('@/views/job/JobTaskList'),
meta: { title: '任务项', icon: 'profile', permission: ['jobBatch'] } meta: { title: '任务项', icon: 'profile', permission: ['jobBatch'] }
}, },
{
path: '/job/notify/list',
name: 'JobNotifyList',
component: () => import('@/views/job/JobNotifyList'),
meta: { title: '通知列表', icon: 'profile', keepAlive: true, permission: ['jobNotify'] }
},
{
path: '/job/notify/config',
name: 'JobNotifyForm',
hidden: true,
component: () => import('@/views/job/form/JobNotifyForm.vue'),
meta: { title: '通知配置', icon: 'profile', keepAlive: true, permission: ['jobNotify'] }
},
{ {
path: '/job/workflow/list', path: '/job/workflow/list',
name: 'WorkflowList', name: 'WorkflowList',
@ -254,6 +241,18 @@ export const asyncRouterMap = [
hidden: true, hidden: true,
component: () => import('@/views/job/WorkflowBatchDetail'), component: () => import('@/views/job/WorkflowBatchDetail'),
meta: { title: '工作流任务批次详情', icon: 'profile', permission: ['jobBatch'] } meta: { title: '工作流任务批次详情', icon: 'profile', permission: ['jobBatch'] }
}, {
path: '/job/notify/list',
name: 'JobNotifyList',
component: () => import('@/views/job/JobNotifyList'),
meta: { title: '通知列表', icon: 'profile', keepAlive: true, permission: ['jobNotify'] }
},
{
path: '/job/notify/config',
name: 'JobNotifyForm',
hidden: true,
component: () => import('@/views/job/form/JobNotifyForm.vue'),
meta: { title: '通知配置', icon: 'profile', keepAlive: true, permission: ['jobNotify'] }
} }
] ]
}, },

View File

@ -106,28 +106,38 @@
title="是否关闭?" title="是否关闭?"
ok-text="关闭" ok-text="关闭"
cancel-text="取消" cancel-text="取消"
@confirm="handleClose(record)" @confirm="handleOpenOrClose(record)"
> >
<a href="javascript:;" v-if="record.jobStatus === 1">关闭</a> <a href="javascript:;" v-if="record.workflowStatus === 1">关闭</a>
</a-popconfirm> </a-popconfirm>
<a-divider type="vertical" v-if="record.jobStatus === 1" /> <a-divider type="vertical" v-if="record.workflowStatus === 1" />
<a-popconfirm <a-popconfirm
title="是否开启?" title="是否开启?"
ok-text="开启" ok-text="开启"
cancel-text="取消" cancel-text="取消"
@confirm="handleOpen(record)" @confirm="handleOpenOrClose(record)"
> >
<a href="javascript:;" v-if="record.jobStatus === 0">开启</a> <a href="javascript:;" v-if="record.workflowStatus === 0">开启</a>
</a-popconfirm> </a-popconfirm>
<a-divider type="vertical" v-if="record.jobStatus === 0" /> <a-divider type="vertical" v-if="record.workflowStatus === 0" />
<a-popconfirm <a-popconfirm
title="是否删除任务?" title="是否删除工作流?"
ok-text="删除" ok-text="删除"
cancel-text="取消" cancel-text="取消"
@confirm="handleDel(record)" @confirm="handleDel(record)"
v-if="$auth('job.del')" v-if="$auth('job.del')"
> >
<a href="javascript:;" v-if="record.jobStatus === 0">删除</a> <a href="javascript:;" v-if="record.workflowStatus === 0">删除</a>
</a-popconfirm>
<a-divider type="vertical" />
<a-popconfirm
title="是否复制此工作流?"
ok-text="复制"
cancel-text="取消"
@confirm="handleCopy(record)"
v-if="$auth('job.del')"
>
<a href="javascript:;">复制</a>
</a-popconfirm> </a-popconfirm>
</template> </template>
@ -153,13 +163,13 @@
import ATextarea from 'ant-design-vue/es/input/TextArea' import ATextarea from 'ant-design-vue/es/input/TextArea'
import AInput from 'ant-design-vue/es/input/Input' import AInput from 'ant-design-vue/es/input/Input'
import { STable, Drawer } from '@/components' import { STable, Drawer } from '@/components'
import { delJob, workflowListPage, triggerJob, updateJobStatus } from '@/api/jobApi' import { workflowListPage, triggerJob, updateWorkflowStatus, delWorkflow } from '@/api/jobApi'
import { getAllGroupNameList } from '@/api/manage' import { getAllGroupNameList } from '@/api/manage'
import enums from '@/utils/jobEnum' import enums from '@/utils/jobEnum'
import JobInfo from '@/views/job/JobInfo' import JobInfo from '@/views/job/JobInfo'
export default { export default {
name: 'JobList', name: 'WorkflowList',
components: { components: {
AInput, AInput,
ATextarea, ATextarea,
@ -295,17 +305,6 @@ export default {
this.$router.push({ path: '/job/workflow/detail', query: { id: record.id } }) this.$router.push({ path: '/job/workflow/detail', query: { id: record.id } })
}, },
handleOk (record) {}, handleOk (record) {},
handleClose (record) {
updateJobStatus({ id: record.id, jobStatus: 0 }).then((res) => {
const { status } = res
if (status === 0) {
this.$message.error('关闭失败')
} else {
this.$refs.table.refresh(true)
this.$message.success('关闭成功')
}
})
},
handleTrigger (record) { handleTrigger (record) {
triggerJob(record.id).then((res) => { triggerJob(record.id).then((res) => {
const { status } = res const { status } = res
@ -317,19 +316,21 @@ export default {
} }
}) })
}, },
handleOpen (record) { handleOpenOrClose (record) {
updateJobStatus({ id: record.id, jobStatus: 1 }).then((res) => { updateWorkflowStatus(record.id).then((res) => {
const { status } = res const { status } = res
if (status === 0) { if (status === 0) {
this.$message.error('开启失败') this.$message.error('执行失败')
} else { } else {
this.$refs.table.refresh(true) this.$refs.table.refresh(true)
this.$message.success('开启成功') this.$message.success('执行成功')
} }
}) })
}, },
handleCopy (record) {
},
handleDel (record) { handleDel (record) {
delJob(record.id).then((res) => { delWorkflow(record.id).then((res) => {
const { status } = res const { status } = res
if (status === 0) { if (status === 0) {
this.$message.error('删除失败') this.$message.error('删除失败')