Pre Merge pull request !679 from 愿丶/dev-n

This commit is contained in:
愿丶 2025-05-20 06:19:28 +00:00 committed by Gitee
commit fce997411e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
17 changed files with 1299 additions and 0 deletions

View File

@ -0,0 +1,127 @@
package org.dromara.workflow.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.workflow.domain.vo.DynamicFormDefinitionVo;
import org.dromara.workflow.domain.bo.DynamicFormDefinitionBo;
import org.dromara.workflow.service.IDynamicFormDefinitionService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 表单定义
*
* @author Yann
* @date 2025-05-10
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/formDefinition")
public class DynamicFormDefinitionController extends BaseController {
private final IDynamicFormDefinitionService dynamicFormDefinitionService;
/**
* 查询表单定义列表
*/
@SaCheckPermission("workflow:formDefinition:list")
@GetMapping("/list")
public TableDataInfo<DynamicFormDefinitionVo> list(DynamicFormDefinitionBo bo, PageQuery pageQuery) {
return dynamicFormDefinitionService.queryPageList(bo, pageQuery);
}
/**
* 获取表单定义详细信息
*
* @param id 主键
*/
@SaCheckPermission("workflow:formDefinition:query")
@GetMapping("/{id}")
public R<DynamicFormDefinitionVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(dynamicFormDefinitionService.queryById(id));
}
/**
* 新增表单定义
*/
@SaCheckPermission("workflow:formDefinition:add")
@Log(title = "表单定义", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody DynamicFormDefinitionBo bo) {
return toAjax(dynamicFormDefinitionService.insertByBo(bo));
}
/**
* 修改表单定义
*/
@SaCheckPermission("workflow:formDefinition:edit")
@Log(title = "表单定义", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody DynamicFormDefinitionBo bo) {
return toAjax(dynamicFormDefinitionService.updateByBo(bo));
}
/**
* 修改表单定义结构
*/
@SaCheckPermission("workflow:formDefinition:edit")
@Log(title = "表单定义", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/editFormSchema")
public R<Void> editFormSchema(@Validated(EditGroup.class) @RequestBody DynamicFormDefinitionBo bo) {
if (StringUtils.isBlank(bo.getFormSchema())) {
throw new ServiceException("表单结构不能为空.");
}
return toAjax(dynamicFormDefinitionService.updateFormSchema(bo));
}
/**
* 删除表单定义
*
* @param ids 主键串
*/
@SaCheckPermission("workflow:formDefinition:remove")
@Log(title = "表单定义", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(dynamicFormDefinitionService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 变更表单定义状态
*/
@SaCheckPermission("workflow:formDefinition:edit")
@Log(title = "表单定义", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/changeStatus")
public R<Void> changeStatus(@RequestBody DynamicFormDefinitionBo bo) {
if (bo.getId() == null) {
throw new ServiceException("主键不能为空");
}
if (StringUtils.isBlank(bo.getStatus())) {
throw new ServiceException("变更状态不能为空");
}
return toAjax(dynamicFormDefinitionService.changeStatus(bo.getId(), bo.getStatus()));
}
}

View File

@ -0,0 +1,105 @@
package org.dromara.workflow.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.workflow.domain.vo.DynamicFormInstanceVo;
import org.dromara.workflow.domain.bo.DynamicFormInstanceBo;
import org.dromara.workflow.service.IDynamicFormInstanceService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 表单实例
*
* @author Yann
* @date 2025-05-10
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/formInstance")
public class DynamicFormInstanceController extends BaseController {
private final IDynamicFormInstanceService dynamicFormInstanceService;
/**
* 查询表单实例列表
*/
@SaCheckPermission("workflow:formInstance:list")
@GetMapping("/list")
public TableDataInfo<DynamicFormInstanceVo> list(DynamicFormInstanceBo bo, PageQuery pageQuery) {
return dynamicFormInstanceService.queryPageList(bo, pageQuery);
}
/**
* 导出表单实例列表
*/
@SaCheckPermission("workflow:formInstance:export")
@Log(title = "表单实例", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(DynamicFormInstanceBo bo, HttpServletResponse response) {
List<DynamicFormInstanceVo> list = dynamicFormInstanceService.queryList(bo);
ExcelUtil.exportExcel(list, "表单实例", DynamicFormInstanceVo.class, response);
}
/**
* 获取表单实例详细信息
*
* @param id 主键
*/
@SaCheckPermission("workflow:formInstance:query")
@GetMapping("/{id}")
public R<DynamicFormInstanceVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(dynamicFormInstanceService.queryById(id));
}
/**
* 新增表单实例
*/
@SaCheckPermission("workflow:formInstance:add")
@Log(title = "表单实例", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<DynamicFormInstanceVo> add(@Validated(AddGroup.class) @RequestBody DynamicFormInstanceBo bo) {
return R.ok(dynamicFormInstanceService.insertByBo(bo));
}
/**
* 修改表单实例
*/
@SaCheckPermission("workflow:formInstance:edit")
@Log(title = "表单实例", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<DynamicFormInstanceVo> edit(@Validated(EditGroup.class) @RequestBody DynamicFormInstanceBo bo) {
return R.ok(dynamicFormInstanceService.updateByBo(bo));
}
/**
* 删除表单实例
*
* @param ids 主键串
*/
@SaCheckPermission("workflow:formInstance:remove")
@Log(title = "表单实例", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(dynamicFormInstanceService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,77 @@
package org.dromara.workflow.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 表单定义对象 dynamic_form_definition
*
* @author Yann
* @date 2025-05-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("dynamic_form_definition")
public class DynamicFormDefinition extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 表单标识
*/
private String formKey;
/**
* 表单名称
*/
private String formName;
/**
* 版本号
*/
private Long version;
/**
* 表单结构
*/
private String formSchema;
/**
* 状态
*/
private String status;
/**
* 扩展字段1
*/
private String ext1;
/**
* 扩展字段2
*/
private String ext2;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,61 @@
package org.dromara.workflow.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 表单实例对象 dynamic_form_instance
*
* @author Yann
* @date 2025-05-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("dynamic_form_instance")
public class DynamicFormInstance extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 表单定义ID
*/
private Long definitionId;
/**
* 表单定义KEY
*/
private String formKey;
/**
* 表单结构
*/
private String formSchema;
/**
* 表单数据
*/
private String formData;
/**
* 状态
*/
private String status;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,62 @@
package org.dromara.workflow.domain.bo;
import org.dromara.workflow.domain.DynamicFormDefinition;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 表单定义业务对象 dynamic_form_definition
*
* @author Yann
* @date 2025-05-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = DynamicFormDefinition.class, reverseConvertGenerate = false)
public class DynamicFormDefinitionBo extends BaseEntity {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 表单标识
*/
@NotBlank(message = "表单标识不能为空", groups = { AddGroup.class, EditGroup.class })
private String formKey;
/**
* 表单名称
*/
@NotBlank(message = "表单名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String formName;
/**
* 版本号
*/
private Long version;
/**
* 表单结构
*/
private String formSchema;
/**
* 状态
*/
private String status;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,60 @@
package org.dromara.workflow.domain.bo;
import org.dromara.workflow.domain.DynamicFormInstance;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 表单实例业务对象 dynamic_form_instance
*
* @author Yann
* @date 2025-05-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = DynamicFormInstance.class, reverseConvertGenerate = false)
public class DynamicFormInstanceBo extends BaseEntity {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 表单定义ID
*/
private Long definitionId;
/**
* 表单定义KEY
*/
private String formKey;
/**
* 表单结构
*/
private String formSchema;
/**
* 表单数据
*/
private String formData;
/**
* 状态
*/
private String status;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,74 @@
package org.dromara.workflow.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.workflow.domain.DynamicFormDefinition;
import java.io.Serial;
import java.io.Serializable;
/**
* 表单定义视图对象 dynamic_form_definition
*
* @author Yann
* @date 2025-05-10
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = DynamicFormDefinition.class)
public class DynamicFormDefinitionVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 表单标识
*/
@ExcelProperty(value = "表单标识")
private String formKey;
/**
* 表单名称
*/
@ExcelProperty(value = "表单名称")
private String formName;
/**
* 版本号
*/
@ExcelProperty(value = "版本号")
private Long version;
/**
* 表单结构
*/
@ExcelProperty(value = "表单结构")
private String formSchema;
/**
* 状态
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wf_form_definition_status")
private String status;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,89 @@
package org.dromara.workflow.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.workflow.domain.DynamicFormInstance;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 表单实例视图对象 dynamic_form_instance
*
* @author Yann
* @date 2025-05-10
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = DynamicFormInstance.class)
public class DynamicFormInstanceVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 表单定义ID
*/
@ExcelProperty(value = "表单定义ID")
private Long definitionId;
/**
* 表单名称
*/
private String formName;
/**
* 表单定义KEY
*/
@ExcelProperty(value = "表单定义KEY")
private String formKey;
/**
* 表单结构
*/
@ExcelProperty(value = "表单结构")
private String formSchema;
/**
* 表单数据
*/
@ExcelProperty(value = "表单数据")
private String formData;
/**
* 状态
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wf_business_status")
private String status;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建人
*/
private Long createBy;
@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
private String createName;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,15 @@
package org.dromara.workflow.mapper;
import org.dromara.workflow.domain.DynamicFormDefinition;
import org.dromara.workflow.domain.vo.DynamicFormDefinitionVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 表单定义Mapper接口
*
* @author Yann
* @date 2025-05-10
*/
public interface DynamicFormDefinitionMapper extends BaseMapperPlus<DynamicFormDefinition, DynamicFormDefinitionVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.workflow.mapper;
import org.dromara.workflow.domain.DynamicFormInstance;
import org.dromara.workflow.domain.vo.DynamicFormInstanceVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 表单实例Mapper接口
*
* @author Yann
* @date 2025-05-10
*/
public interface DynamicFormInstanceMapper extends BaseMapperPlus<DynamicFormInstance, DynamicFormInstanceVo> {
}

View File

@ -0,0 +1,84 @@
package org.dromara.workflow.service;
import org.dromara.workflow.domain.vo.DynamicFormDefinitionVo;
import org.dromara.workflow.domain.bo.DynamicFormDefinitionBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 表单定义Service接口
*
* @author Yann
* @date 2025-05-10
*/
public interface IDynamicFormDefinitionService {
/**
* 查询表单定义
*
* @param id 主键
* @return 表单定义
*/
DynamicFormDefinitionVo queryById(Long id);
/**
* 分页查询表单定义列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 表单定义分页列表
*/
TableDataInfo<DynamicFormDefinitionVo> queryPageList(DynamicFormDefinitionBo bo, PageQuery pageQuery);
/**
* 查询符合条件的表单定义列表
*
* @param bo 查询条件
* @return 表单定义列表
*/
List<DynamicFormDefinitionVo> queryList(DynamicFormDefinitionBo bo);
/**
* 新增表单定义
*
* @param bo 表单定义
* @return 是否新增成功
*/
Boolean insertByBo(DynamicFormDefinitionBo bo);
/**
* 修改表单定义
*
* @param bo 表单定义
* @return 是否修改成功
*/
Boolean updateByBo(DynamicFormDefinitionBo bo);
/**
* 修改表单版本
* @param bo 表单定义对象
* @return 是否成功
*/
Boolean updateFormSchema(DynamicFormDefinitionBo bo);
/**
* 校验并批量删除表单定义信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 变更状态
*
* @param id 主键
* @param status 状态
* @return 是否成功
*/
Boolean changeStatus(Long id, String status);
}

View File

@ -0,0 +1,68 @@
package org.dromara.workflow.service;
import org.dromara.workflow.domain.vo.DynamicFormInstanceVo;
import org.dromara.workflow.domain.bo.DynamicFormInstanceBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 表单实例Service接口
*
* @author Yann
* @date 2025-05-10
*/
public interface IDynamicFormInstanceService {
/**
* 查询表单实例
*
* @param id 主键
* @return 表单实例
*/
DynamicFormInstanceVo queryById(Long id);
/**
* 分页查询表单实例列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 表单实例分页列表
*/
TableDataInfo<DynamicFormInstanceVo> queryPageList(DynamicFormInstanceBo bo, PageQuery pageQuery);
/**
* 查询符合条件的表单实例列表
*
* @param bo 查询条件
* @return 表单实例列表
*/
List<DynamicFormInstanceVo> queryList(DynamicFormInstanceBo bo);
/**
* 新增表单实例
*
* @param bo 表单实例
* @return 是否新增成功
*/
DynamicFormInstanceVo insertByBo(DynamicFormInstanceBo bo);
/**
* 修改表单实例
*
* @param bo 表单实例
* @return 是否修改成功
*/
DynamicFormInstanceVo updateByBo(DynamicFormInstanceBo bo);
/**
* 校验并批量删除表单实例信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,169 @@
package org.dromara.workflow.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.workflow.domain.bo.DynamicFormDefinitionBo;
import org.dromara.workflow.domain.vo.DynamicFormDefinitionVo;
import org.dromara.workflow.domain.DynamicFormDefinition;
import org.dromara.workflow.mapper.DynamicFormDefinitionMapper;
import org.dromara.workflow.service.IDynamicFormDefinitionService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 表单定义Service业务层处理
*
* @author Yann
* @date 2025-05-10
*/
@RequiredArgsConstructor
@Service
public class DynamicFormDefinitionServiceImpl implements IDynamicFormDefinitionService {
private final DynamicFormDefinitionMapper baseMapper;
private static final String FORM_KEY_PREFIX = "dyn_form_";
/**
* 查询表单定义
*
* @param id 主键
* @return 表单定义
*/
@Override
public DynamicFormDefinitionVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询表单定义列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 表单定义分页列表
*/
@Override
public TableDataInfo<DynamicFormDefinitionVo> queryPageList(DynamicFormDefinitionBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<DynamicFormDefinition> lqw = buildQueryWrapper(bo);
Page<DynamicFormDefinitionVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的表单定义列表
*
* @param bo 查询条件
* @return 表单定义列表
*/
@Override
public List<DynamicFormDefinitionVo> queryList(DynamicFormDefinitionBo bo) {
LambdaQueryWrapper<DynamicFormDefinition> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<DynamicFormDefinition> buildQueryWrapper(DynamicFormDefinitionBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<DynamicFormDefinition> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(DynamicFormDefinition::getId);
lqw.eq(StringUtils.isNotBlank(bo.getFormKey()), DynamicFormDefinition::getFormKey, bo.getFormKey());
lqw.like(StringUtils.isNotBlank(bo.getFormName()), DynamicFormDefinition::getFormName, bo.getFormName());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), DynamicFormDefinition::getStatus, bo.getStatus());
return lqw;
}
/**
* 新增表单定义
*
* @param bo 表单定义
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(DynamicFormDefinitionBo bo) {
DynamicFormDefinition add = MapstructUtils.convert(bo, DynamicFormDefinition.class);
validEntityBeforeSave(add);
// 增加标识前缀
add.setFormKey(FORM_KEY_PREFIX + add.getFormKey());
add.setVersion(1L);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改表单定义
*
* @param bo 表单定义
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(DynamicFormDefinitionBo bo) {
DynamicFormDefinition update = MapstructUtils.convert(bo, DynamicFormDefinition.class);
validEntityBeforeSave(update);
// 增加前缀
update.setFormKey(FORM_KEY_PREFIX + update.getFormKey());
return baseMapper.updateById(update) > 0;
}
@Override
public Boolean updateFormSchema(DynamicFormDefinitionBo bo) {
return baseMapper.update(new LambdaUpdateWrapper<DynamicFormDefinition>()
.set(DynamicFormDefinition::getFormSchema, bo.getFormSchema())
.set(DynamicFormDefinition::getVersion, bo.getVersion() + 1)
.eq(DynamicFormDefinition::getId, bo.getId())) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(DynamicFormDefinition entity){
// 做一些数据校验,如唯一约束
LambdaQueryWrapper<DynamicFormDefinition> wrapper = new LambdaQueryWrapper<DynamicFormDefinition>()
.eq(DynamicFormDefinition::getFormKey, entity.getFormKey())
.ne(entity.getId() != null, DynamicFormDefinition::getId, entity.getId());
if (baseMapper.exists(wrapper)) {
throw new ServiceException("表单标识重复,请检查!");
}
}
/**
* 校验并批量删除表单定义信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 变更状态
* @param id 主键
* @param status 状态
* @return 是否成功
*/
@Override
public Boolean changeStatus(Long id, String status) {
return baseMapper.update(new LambdaUpdateWrapper<DynamicFormDefinition>()
.set(DynamicFormDefinition::getStatus, status)
.eq(DynamicFormDefinition::getId, id)) > 0;
}
}

View File

@ -0,0 +1,218 @@
package org.dromara.workflow.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.event.ProcessCreateTaskEvent;
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.service.WorkflowService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.DynamicFormDefinition;
import org.dromara.workflow.domain.DynamicFormInstance;
import org.dromara.workflow.domain.bo.DynamicFormInstanceBo;
import org.dromara.workflow.domain.vo.DynamicFormInstanceVo;
import org.dromara.workflow.mapper.DynamicFormDefinitionMapper;
import org.dromara.workflow.mapper.DynamicFormInstanceMapper;
import org.dromara.workflow.service.IDynamicFormInstanceService;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 表单实例Service业务层处理
*
* @author Yann
* @date 2025-05-10
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class DynamicFormInstanceServiceImpl implements IDynamicFormInstanceService {
private final DynamicFormInstanceMapper baseMapper;
private final DynamicFormDefinitionMapper definitionMapper;
private final WorkflowService workflowService;
/**
* 查询表单实例
*
* @param id 主键
* @return 表单实例
*/
@Override
public DynamicFormInstanceVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询表单实例列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 表单实例分页列表
*/
@Override
public TableDataInfo<DynamicFormInstanceVo> queryPageList(DynamicFormInstanceBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<DynamicFormInstance> lqw = buildQueryWrapper(bo);
Page<DynamicFormInstanceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
result.getRecords().forEach(item -> {
DynamicFormDefinition dynamicFormDefinition = definitionMapper.selectById(item.getDefinitionId());
if (dynamicFormDefinition != null) {
item.setFormName(dynamicFormDefinition.getFormName());
}
});
return TableDataInfo.build(result);
}
/**
* 查询符合条件的表单实例列表
*
* @param bo 查询条件
* @return 表单实例列表
*/
@Override
public List<DynamicFormInstanceVo> queryList(DynamicFormInstanceBo bo) {
LambdaQueryWrapper<DynamicFormInstance> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<DynamicFormInstance> buildQueryWrapper(DynamicFormInstanceBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<DynamicFormInstance> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(DynamicFormInstance::getId);
lqw.eq(bo.getDefinitionId() != null, DynamicFormInstance::getDefinitionId, bo.getDefinitionId());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), DynamicFormInstance::getStatus, bo.getStatus());
return lqw;
}
/**
* 新增表单实例
*
* @param bo 表单实例
* @return 是否新增成功
*/
@Override
public DynamicFormInstanceVo insertByBo(DynamicFormInstanceBo bo) {
DynamicFormInstance add = MapstructUtils.convert(bo, DynamicFormInstance.class);
validEntityBeforeSave(add);
if (StringUtils.isBlank(add.getStatus())) {
add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
}
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return MapstructUtils.convert(add, DynamicFormInstanceVo.class);
}
/**
* 修改表单实例
*
* @param bo 表单实例
* @return 是否修改成功
*/
@Override
public DynamicFormInstanceVo updateByBo(DynamicFormInstanceBo bo) {
DynamicFormInstance update = MapstructUtils.convert(bo, DynamicFormInstance.class);
validEntityBeforeSave(update);
boolean flag = baseMapper.updateById(update) > 0;
if (flag) {
}
return MapstructUtils.convert(update, DynamicFormInstanceVo.class);
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(DynamicFormInstance entity){
// 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除表单实例信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
// 做一些业务上的校验,判断是否需要校验
}
workflowService.deleteInstance((List<Long>) ids);
return baseMapper.deleteByIds(ids) > 0;
}
// ==================== 流程流转需要
/**
* 总体流程监听(例如: 草稿撤销退回作废终止已完成单任务完成等)
* 正常使用只需#processEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processEvent 参数
*/
@EventListener(condition = "#processEvent.flowCode.startsWith('dyn_form_')")
public void processHandler(ProcessEvent processEvent) {
log.debug("当前任务执行了{}", processEvent.toString());
// 获取业务数据
DynamicFormInstance dynamicFormInstance = baseMapper.selectById(processEvent.getBusinessId());
dynamicFormInstance.setStatus(processEvent.getStatus());
// #TODO 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程
if (processEvent.getSubmit()) {
dynamicFormInstance.setStatus(BusinessStatusEnum.WAITING.getStatus());
}
baseMapper.updateById(dynamicFormInstance);
}
/**
* 执行任务创建监听
* 示例也可通过 @EventListener(condition = "#processCreateTaskEvent.flowCode=='leave1'")进行判断
* 在方法中判断流程节点key
* if ("xxx".equals(processCreateTaskEvent.getNodeCode())) {
* //执行业务逻辑
* }
*
* @param processCreateTaskEvent 参数
*/
@EventListener(condition = "#processCreateTaskEvent.flowCode.startsWith('dyn_form_')")
public void processCreateTaskHandler(ProcessCreateTaskEvent processCreateTaskEvent) {
log.debug("当前任务创建了{}", processCreateTaskEvent.toString());
DynamicFormInstance dynamicFormInstance = baseMapper.selectById(processCreateTaskEvent.getBusinessId());
if (dynamicFormInstance != null) {
dynamicFormInstance.setStatus(BusinessStatusEnum.WAITING.getStatus());
baseMapper.updateById(dynamicFormInstance);
}
}
/**
* 监听删除流程事件
* 正常使用只需#processDeleteEvent.flowCode=='leave1'
* 示例为了方便则使用startsWith匹配了全部示例key
*
* @param processDeleteEvent 参数
*/
@EventListener(condition = "#processDeleteEvent.flowCode.startsWith('dyn_form_')")
public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) {
log.debug("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString());
DynamicFormInstance dynamicFormInstance = baseMapper.selectById(processDeleteEvent.getBusinessId());
if (dynamicFormInstance != null) {
baseMapper.deleteById(dynamicFormInstance.getId());
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.workflow.mapper.DynamicFormDefinitionMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.workflow.mapper.DynamicFormInstanceMapper">
</mapper>

View File

@ -203,6 +203,51 @@ create table test_leave
PRIMARY KEY (id) USING BTREE
) ENGINE = InnoDB COMMENT = '请假申请表';
-- 动态表单
-- --------------------------------
-- 表单定义表
-- --------------------------------
CREATE TABLE `dynamic_form_definition` (
`id` bigint NOT NULL COMMENT '主键',
`tenant_id` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '租户ID',
`form_key` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '表单唯一标识',
`form_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '表单名称',
`version` int DEFAULT NULL COMMENT '版本号',
`form_schema` json DEFAULT NULL COMMENT '表单结构',
`status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '状态(0未发布1已发布2已停用)',
`ext1` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '扩展字段1',
`ext2` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '扩展字段2',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标志0代表存在 1代表删除',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`create_by` bigint DEFAULT NULL COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='动态表单定义表';
-- ----------------------------------------
-- 表单实例表
-- ----------------------------------------
CREATE TABLE `dynamic_form_instance` (
`id` bigint NOT NULL COMMENT '主键',
`tenant_id` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '租户ID',
`definition_id` bigint DEFAULT NULL COMMENT '表单定义ID',
`form_key` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '表单KEY',
`form_schema` json DEFAULT NULL COMMENT '表单结构',
`form_data` json DEFAULT NULL COMMENT '表单数据',
`status` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '状态',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`create_by` bigint DEFAULT NULL COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` bigint DEFAULT NULL COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='动态表单实例表';
insert into sys_menu values ('11616', '工作流', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, sysdate(),NULL, NULL, '');
insert into sys_menu values ('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, sysdate(), NULL, NULL, '');
insert into sys_menu values ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, '');
@ -253,3 +298,19 @@ INSERT INTO sys_dict_data VALUES (57, '000000', 10, '加签', 'sign', 'wf_task_s
INSERT INTO sys_dict_data VALUES (58, '000000', 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '减签');
INSERT INTO sys_dict_data VALUES (59, '000000', 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '超时');
INSERT INTO `sys_menu` VALUES (11711, '表单定义查询', 11710, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formDefinition:query', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11710, '表单定义', 11616, 10, 'formDefinition', 'workflow/formDefinition/index', NULL, 1, 0, 'C', '0', '0', 'workflow:formInstance:list', 'build', 103, 1, sysdate(), NULL, NULL, '表单定义菜单');
INSERT INTO `sys_menu` VALUES (11712, '表单定义新增', 11710, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formDefinition:add', '#', 103, 1, sysdate() NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11713, '表单定义修改', 11710, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formDefinition:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11714, '表单定义删除', 11710, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formDefinition:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11720, '表单实例', 11616, 11, 'formInstance', 'workflow/formInstance/index', NULL, 1, 0, 'C', '0', '0', 'workflow:formInstance:list', 'nested', 103, 1, sysdate(), NULL, NULL, '表单实例菜单');
INSERT INTO `sys_menu` VALUES (11721, '表单实例查询', 11720, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formInstance:query', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11722, '表单实例新增', 11720, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formInstance:add', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11723, '表单实例修改', 11720, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formInstance:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11724, '表单实例删除', 11720, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formInstance:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (11725, '表单实例导出', 11720, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:formInstance:export', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_dict_type` VALUES (16, '000000', '表单定义状态', 'wf_form_definition_status', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_dict_data` VALUES (61, '000000', 1, '已发布', '1', 'wf_form_definition_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_dict_data` VALUES (62, '000000', 2, '已停用', '2', 'wf_form_definition_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO `sys_dict_data` VALUES (60, '000000', 0, '未发布', '0', 'wf_form_definition_status', '', 'info', 'N', 103, 1, sysdate(), NULL, NULL, '');