增加form表单
This commit is contained in:
parent
03d4d21424
commit
96296270bb
@ -149,7 +149,11 @@ public enum ResponseCode {
|
|||||||
/**
|
/**
|
||||||
* 工作流变量反序列化错误
|
* 工作流变量反序列化错误
|
||||||
*/
|
*/
|
||||||
WORKFLOW_VARIABLE_DESERIALIZE_ERROR(50302, "workflow.variable.deserialize.error");
|
WORKFLOW_VARIABLE_DESERIALIZE_ERROR(50302, "workflow.variable.deserialize.error"),
|
||||||
|
|
||||||
|
// 表单管理相关错误码 (2800-2899)
|
||||||
|
FORM_DEFINITION_NOT_FOUND(2800, "form.definition.not.found"),
|
||||||
|
FORM_DATA_NOT_FOUND(2801, "form.data.not.found");
|
||||||
|
|
||||||
private final int code;
|
private final int code;
|
||||||
private final String messageKey; // 国际化消息key
|
private final String messageKey; // 国际化消息key
|
||||||
|
|||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.api;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.api.Response;
|
||||||
|
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDataDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.query.FormDataQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormData;
|
||||||
|
import com.qqchen.deploy.backend.workflow.service.IFormDataService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据API控制器
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/workflow/form-data")
|
||||||
|
@Tag(name = "表单数据管理", description = "表单数据管理相关接口")
|
||||||
|
public class FormDataApiController extends BaseController<FormData, FormDataDTO, Long, FormDataQuery> {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFormDataService formDataService;
|
||||||
|
|
||||||
|
@Operation(summary = "提交表单数据")
|
||||||
|
@PostMapping("/submit")
|
||||||
|
public Response<FormDataDTO> submit(@RequestBody FormDataDTO dto) {
|
||||||
|
FormDataDTO result = formDataService.submit(dto);
|
||||||
|
return Response.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "根据业务标识查询表单数据")
|
||||||
|
@GetMapping("/business/{businessKey}")
|
||||||
|
public Response<FormDataDTO> getByBusinessKey(
|
||||||
|
@Parameter(description = "业务标识", required = true) @PathVariable String businessKey
|
||||||
|
) {
|
||||||
|
FormDataDTO result = formDataService.getByBusinessKey(businessKey);
|
||||||
|
return Response.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void exportData(jakarta.servlet.http.HttpServletResponse response, java.util.List<FormDataDTO> data) {
|
||||||
|
// 暂不支持导出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.api;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.api.Response;
|
||||||
|
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDefinitionDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.query.FormDefinitionQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormDefinition;
|
||||||
|
import com.qqchen.deploy.backend.workflow.service.IFormDefinitionService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义API控制器
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/workflow/form-definition")
|
||||||
|
@Tag(name = "表单定义管理", description = "表单定义管理相关接口")
|
||||||
|
public class FormDefinitionApiController extends BaseController<FormDefinition, FormDefinitionDTO, Long, FormDefinitionQuery> {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFormDefinitionService formDefinitionService;
|
||||||
|
|
||||||
|
@Operation(summary = "发布表单")
|
||||||
|
@PostMapping("/{id}/publish")
|
||||||
|
public Response<FormDefinitionDTO> publish(
|
||||||
|
@Parameter(description = "表单定义ID", required = true) @PathVariable Long id
|
||||||
|
) {
|
||||||
|
FormDefinitionDTO result = formDefinitionService.publish(id);
|
||||||
|
return Response.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "根据key获取最新版本表单")
|
||||||
|
@GetMapping("/latest/{key}")
|
||||||
|
public Response<FormDefinitionDTO> getLatestByKey(
|
||||||
|
@Parameter(description = "表单标识", required = true) @PathVariable String key
|
||||||
|
) {
|
||||||
|
FormDefinitionDTO result = formDefinitionService.getLatestByKey(key);
|
||||||
|
return Response.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void exportData(jakarta.servlet.http.HttpServletResponse response, java.util.List<FormDefinitionDTO> data) {
|
||||||
|
// 暂不支持导出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.converter;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDataDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormData;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据转换器
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Mapper(config = BaseConverter.class)
|
||||||
|
public interface FormDataConverter extends BaseConverter<FormData, FormDataDTO> {
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.converter;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDefinitionDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormDefinition;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义转换器
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Mapper(config = BaseConverter.class)
|
||||||
|
public interface FormDefinitionConverter extends BaseConverter<FormDefinition, FormDefinitionDTO> {
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.form.FormSchema;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormBusinessTypeEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDataStatusEnums;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据DTO
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Schema(description = "表单数据DTO")
|
||||||
|
public class FormDataDTO extends BaseDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义ID
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单定义ID", example = "1")
|
||||||
|
private Long formDefinitionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单标识(冗余存储,避免JOIN)
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单标识", example = "employee_info_form")
|
||||||
|
private String formKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单版本(冗余存储,用于历史追溯)
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单版本", example = "1")
|
||||||
|
private Integer formVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标识(如工作流实例ID、订单号等)
|
||||||
|
*/
|
||||||
|
@Schema(description = "业务标识", example = "workflow_instance_123")
|
||||||
|
private String businessKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务类型(WORKFLOW-工作流、ORDER-订单、STANDALONE-独立表单)
|
||||||
|
*/
|
||||||
|
@Schema(description = "业务类型")
|
||||||
|
private FormBusinessTypeEnums businessType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单填写数据(用户提交的实际数据)
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单填写数据")
|
||||||
|
private Map<String, Object> data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单Schema快照(用于历史追溯,确保数据可还原)
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单Schema快照")
|
||||||
|
private FormSchema schemaSnapshot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交人
|
||||||
|
*/
|
||||||
|
@Schema(description = "提交人", example = "admin")
|
||||||
|
private String submitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交时间
|
||||||
|
*/
|
||||||
|
@Schema(description = "提交时间", example = "2025-10-24T12:00:00")
|
||||||
|
private LocalDateTime submitTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(DRAFT-草稿、SUBMITTED-已提交、COMPLETED-已完成、REJECTED-已拒绝)
|
||||||
|
*/
|
||||||
|
@Schema(description = "状态")
|
||||||
|
private FormDataStatusEnums status;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.form.FormSchema;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormCategoryEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDefinitionStatusEnums;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义DTO
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Schema(description = "表单定义DTO")
|
||||||
|
public class FormDefinitionDTO extends BaseDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单名称
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单名称", example = "员工信息登记表")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单标识(业务唯一)
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单标识", example = "employee_info_form")
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单版本号
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单版本号", example = "1")
|
||||||
|
private Integer formVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单分类
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单分类")
|
||||||
|
private FormCategoryEnums category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单描述
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单描述", example = "用于采集员工基本信息")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单Schema(前端设计器导出的JSON结构)
|
||||||
|
*/
|
||||||
|
@Schema(description = "表单Schema")
|
||||||
|
private FormSchema schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签(用于分类和搜索)
|
||||||
|
*/
|
||||||
|
@Schema(description = "标签列表", example = "[\"员工管理\", \"信息采集\"]")
|
||||||
|
private List<String> tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(DRAFT-草稿、PUBLISHED-已发布、DISABLED-已禁用)
|
||||||
|
*/
|
||||||
|
@Schema(description = "状态")
|
||||||
|
private FormDefinitionStatusEnums status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为模板
|
||||||
|
*/
|
||||||
|
@Schema(description = "是否为模板", example = "false")
|
||||||
|
private Boolean isTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto.form;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单Schema定义
|
||||||
|
* 用于存储前端表单设计器导出的JSON结构
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FormSchema {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单标题
|
||||||
|
*/
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单字段列表
|
||||||
|
*/
|
||||||
|
private List<FormField> fields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单配置
|
||||||
|
*/
|
||||||
|
private Map<String, Object> config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单字段定义
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class FormField {
|
||||||
|
/**
|
||||||
|
* 字段名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段标签
|
||||||
|
*/
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段类型(input、select、textarea、date、number等)
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否必填
|
||||||
|
*/
|
||||||
|
private Boolean required;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认值
|
||||||
|
*/
|
||||||
|
private Object defaultValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段配置(不同类型字段有不同配置)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证规则
|
||||||
|
*/
|
||||||
|
private List<Map<String, Object>> validators;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto.query;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.annotation.QueryField;
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.QueryType;
|
||||||
|
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormBusinessTypeEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDataStatusEnums;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据查询对象
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class FormDataQuery extends BaseQuery {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义ID(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "formDefinitionId", type = QueryType.EQUAL)
|
||||||
|
private Long formDefinitionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单标识(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "formKey", type = QueryType.EQUAL)
|
||||||
|
private String formKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标识(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "businessKey", type = QueryType.EQUAL)
|
||||||
|
private String businessKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务类型(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "businessType", type = QueryType.EQUAL)
|
||||||
|
private FormBusinessTypeEnums businessType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交人(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "submitter", type = QueryType.EQUAL)
|
||||||
|
private String submitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "status", type = QueryType.EQUAL)
|
||||||
|
private FormDataStatusEnums status;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto.query;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.annotation.QueryField;
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.QueryType;
|
||||||
|
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormCategoryEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDefinitionStatusEnums;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义查询对象
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class FormDefinitionQuery extends BaseQuery {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单名称(模糊查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "name", type = QueryType.LIKE)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单标识(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "key", type = QueryType.EQUAL)
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单版本(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "formVersion", type = QueryType.EQUAL)
|
||||||
|
private Integer formVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单分类(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "category", type = QueryType.EQUAL)
|
||||||
|
private FormCategoryEnums category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "status", type = QueryType.EQUAL)
|
||||||
|
private FormDefinitionStatusEnums status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为模板(精确查询)
|
||||||
|
*/
|
||||||
|
@QueryField(field = "isTemplate", type = QueryType.EQUAL)
|
||||||
|
private Boolean isTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.entity;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||||
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.form.FormSchema;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.converter.FormSchemaType;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormBusinessTypeEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDataStatusEnums;
|
||||||
|
import com.vladmihalcea.hibernate.type.json.JsonType;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据实体
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(name = "form_data")
|
||||||
|
@jakarta.persistence.Entity
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@LogicDelete
|
||||||
|
public class FormData extends Entity<Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义ID
|
||||||
|
*/
|
||||||
|
@Column(name = "form_definition_id", nullable = false)
|
||||||
|
private Long formDefinitionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单标识(冗余存储,避免JOIN)
|
||||||
|
*/
|
||||||
|
@Column(name = "form_key", nullable = false)
|
||||||
|
private String formKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单版本(冗余存储,用于历史追溯)
|
||||||
|
*/
|
||||||
|
@Column(name = "form_version", nullable = false)
|
||||||
|
private Integer formVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标识(如工作流实例ID、订单号等)
|
||||||
|
*/
|
||||||
|
@Column(name = "business_key")
|
||||||
|
private String businessKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务类型(WORKFLOW-工作流、ORDER-订单、STANDALONE-独立表单)
|
||||||
|
*/
|
||||||
|
@Column(name = "business_type")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private FormBusinessTypeEnums businessType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单填写数据(用户提交的实际数据)
|
||||||
|
*/
|
||||||
|
@Type(JsonType.class)
|
||||||
|
@Column(name = "data", nullable = false, columnDefinition = "json")
|
||||||
|
private Map<String, Object> data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单Schema快照(用于历史追溯,确保数据可还原)
|
||||||
|
*/
|
||||||
|
@Type(FormSchemaType.class)
|
||||||
|
@Column(name = "schema_snapshot", nullable = false, columnDefinition = "json")
|
||||||
|
private FormSchema schemaSnapshot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交人
|
||||||
|
*/
|
||||||
|
@Column(name = "submitter")
|
||||||
|
private String submitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交时间
|
||||||
|
*/
|
||||||
|
@Column(name = "submit_time")
|
||||||
|
private LocalDateTime submitTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(DRAFT-草稿、SUBMITTED-已提交、COMPLETED-已完成、REJECTED-已拒绝)
|
||||||
|
*/
|
||||||
|
@Column(name = "status", nullable = false)
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private FormDataStatusEnums status;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.entity;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||||
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.form.FormSchema;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.converter.FormSchemaType;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormCategoryEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDefinitionStatusEnums;
|
||||||
|
import com.vladmihalcea.hibernate.type.json.JsonType;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义实体
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(name = "form_definition")
|
||||||
|
@jakarta.persistence.Entity
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@LogicDelete
|
||||||
|
public class FormDefinition extends Entity<Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单名称
|
||||||
|
*/
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单标识(业务唯一)
|
||||||
|
*/
|
||||||
|
@Column(name = "`key`", nullable = false)
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单版本号
|
||||||
|
*/
|
||||||
|
@Column(name = "form_version", nullable = false)
|
||||||
|
private Integer formVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单分类
|
||||||
|
*/
|
||||||
|
@Column(name = "category")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private FormCategoryEnums category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单描述
|
||||||
|
*/
|
||||||
|
@Column(name = "description", columnDefinition = "TEXT")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单Schema(前端设计器导出的JSON结构)
|
||||||
|
*/
|
||||||
|
@Type(FormSchemaType.class)
|
||||||
|
@Column(name = "schema", nullable = false, columnDefinition = "json")
|
||||||
|
private FormSchema schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签(用于分类和搜索)
|
||||||
|
*/
|
||||||
|
@Type(JsonType.class)
|
||||||
|
@Column(name = "tags", columnDefinition = "json")
|
||||||
|
private List<String> tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(DRAFT-草稿、PUBLISHED-已发布、DISABLED-已禁用)
|
||||||
|
*/
|
||||||
|
@Column(name = "status", nullable = false)
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private FormDefinitionStatusEnums status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为模板
|
||||||
|
*/
|
||||||
|
@Column(name = "is_template", nullable = false)
|
||||||
|
private Boolean isTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.entity.converter;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.form.FormSchema;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.usertype.UserType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义 Hibernate 类型,用于处理 FormSchema 的序列化和反序列化
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
public class FormSchemaType implements UserType<FormSchema> {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FormSchemaType.class);
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public FormSchemaType() {
|
||||||
|
this.objectMapper = new ObjectMapper();
|
||||||
|
// 配置 ObjectMapper,忽略未知属性
|
||||||
|
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSqlType() {
|
||||||
|
return Types.VARCHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<FormSchema> returnedClass() {
|
||||||
|
return FormSchema.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(FormSchema x, FormSchema y) {
|
||||||
|
if (x == y) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (x == null || y == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return x.equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode(FormSchema x) {
|
||||||
|
return x == null ? 0 : x.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FormSchema nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner)
|
||||||
|
throws SQLException {
|
||||||
|
String value = rs.getString(position);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(value, FormSchema.class);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
// 记录错误日志,但不抛出异常,返回 null 使得单条记录的错误不影响整体查询
|
||||||
|
log.error("Failed to convert String to FormSchema: " + value, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullSafeSet(PreparedStatement st, FormSchema value, int index, SharedSessionContractImplementor session)
|
||||||
|
throws SQLException {
|
||||||
|
if (value == null) {
|
||||||
|
st.setNull(index, Types.VARCHAR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
st.setString(index, objectMapper.writeValueAsString(value));
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new HibernateException("Failed to convert FormSchema to String: " + value, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FormSchema deepCopy(FormSchema value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(objectMapper.writeValueAsString(value), FormSchema.class);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new HibernateException("Failed to deep copy FormSchema", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMutable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable disassemble(FormSchema value) {
|
||||||
|
try {
|
||||||
|
return value == null ? null : objectMapper.writeValueAsString(value);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new HibernateException("Failed to disassemble FormSchema", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FormSchema assemble(Serializable cached, Object owner) {
|
||||||
|
try {
|
||||||
|
return cached == null ? null : objectMapper.readValue(cached.toString(), FormSchema.class);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new HibernateException("Failed to assemble FormSchema", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FormSchema replace(FormSchema detached, FormSchema managed, Object owner) {
|
||||||
|
return deepCopy(detached);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单业务类型枚举
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum FormBusinessTypeEnums {
|
||||||
|
|
||||||
|
WORKFLOW("WORKFLOW", "工作流"),
|
||||||
|
ORDER("ORDER", "订单"),
|
||||||
|
STANDALONE("STANDALONE", "独立表单");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
FormBusinessTypeEnums(String code, String description) {
|
||||||
|
this.code = code;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单分类枚举
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum FormCategoryEnums {
|
||||||
|
|
||||||
|
APPROVAL("APPROVAL", "审批"),
|
||||||
|
DATA_COLLECTION("DATA_COLLECTION", "数据采集"),
|
||||||
|
SURVEY("SURVEY", "问卷调查"),
|
||||||
|
OTHER("OTHER", "其他");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
FormCategoryEnums(String code, String description) {
|
||||||
|
this.code = code;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据状态枚举
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum FormDataStatusEnums {
|
||||||
|
|
||||||
|
DRAFT("DRAFT", "草稿"),
|
||||||
|
SUBMITTED("SUBMITTED", "已提交"),
|
||||||
|
COMPLETED("COMPLETED", "已完成"),
|
||||||
|
REJECTED("REJECTED", "已拒绝");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
FormDataStatusEnums(String code, String description) {
|
||||||
|
this.code = code;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义状态枚举
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum FormDefinitionStatusEnums {
|
||||||
|
|
||||||
|
DRAFT("DRAFT", "草稿"),
|
||||||
|
PUBLISHED("PUBLISHED", "已发布"),
|
||||||
|
DISABLED("DISABLED", "已禁用");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
FormDefinitionStatusEnums(String code, String description) {
|
||||||
|
this.code = code;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.repository;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormData;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDataStatusEnums;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据Repository接口
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface IFormDataRepository extends IBaseRepository<FormData, Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据业务标识查询
|
||||||
|
*
|
||||||
|
* @param businessKey 业务标识
|
||||||
|
* @return 表单数据
|
||||||
|
*/
|
||||||
|
Optional<FormData> findByBusinessKeyAndDeletedFalse(String businessKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据表单标识分页查询
|
||||||
|
*
|
||||||
|
* @param formKey 表单标识
|
||||||
|
* @param pageable 分页参数
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
Page<FormData> findByFormKeyAndDeletedFalse(String formKey, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据提交人分页查询
|
||||||
|
*
|
||||||
|
* @param submitter 提交人
|
||||||
|
* @param pageable 分页参数
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
Page<FormData> findBySubmitterAndDeletedFalse(String submitter, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态分页查询
|
||||||
|
*
|
||||||
|
* @param status 状态
|
||||||
|
* @param pageable 分页参数
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
Page<FormData> findByStatusAndDeletedFalse(FormDataStatusEnums status, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据表单定义ID查询列表
|
||||||
|
*
|
||||||
|
* @param formDefinitionId 表单定义ID
|
||||||
|
* @return 表单数据列表
|
||||||
|
*/
|
||||||
|
List<FormData> findByFormDefinitionIdAndDeletedFalse(Long formDefinitionId);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.repository;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormDefinition;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDefinitionStatusEnums;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义Repository接口
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface IFormDefinitionRepository extends IBaseRepository<FormDefinition, Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据表单标识和版本查询
|
||||||
|
*
|
||||||
|
* @param key 表单标识
|
||||||
|
* @param formVersion 表单版本
|
||||||
|
* @return 表单定义
|
||||||
|
*/
|
||||||
|
Optional<FormDefinition> findByKeyAndFormVersionAndDeletedFalse(String key, Integer formVersion);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据表单标识查询最新版本
|
||||||
|
*
|
||||||
|
* @param key 表单标识
|
||||||
|
* @return 表单定义
|
||||||
|
*/
|
||||||
|
Optional<FormDefinition> findFirstByKeyAndDeletedFalseOrderByFormVersionDesc(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查表单标识是否存在
|
||||||
|
*
|
||||||
|
* @param key 表单标识
|
||||||
|
* @return 是否存在
|
||||||
|
*/
|
||||||
|
boolean existsByKeyAndDeletedFalse(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态分页查询
|
||||||
|
*
|
||||||
|
* @param status 状态
|
||||||
|
* @param pageable 分页参数
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
Page<FormDefinition> findByStatusAndDeletedFalse(FormDefinitionStatusEnums status, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态查询列表
|
||||||
|
*
|
||||||
|
* @param status 状态
|
||||||
|
* @return 表单定义列表
|
||||||
|
*/
|
||||||
|
List<FormDefinition> findByStatusAndDeletedFalse(FormDefinitionStatusEnums status);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.service;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDataDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.query.FormDataQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据服务接口
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
public interface IFormDataService extends IBaseService<FormData, FormDataDTO, FormDataQuery, Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交表单数据
|
||||||
|
*
|
||||||
|
* @param dto 表单数据DTO
|
||||||
|
* @return 提交后的表单数据
|
||||||
|
*/
|
||||||
|
FormDataDTO submit(FormDataDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据业务标识查询表单数据
|
||||||
|
*
|
||||||
|
* @param businessKey 业务标识
|
||||||
|
* @return 表单数据
|
||||||
|
*/
|
||||||
|
FormDataDTO getByBusinessKey(String businessKey);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.service;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDefinitionDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.query.FormDefinitionQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义服务接口
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
public interface IFormDefinitionService extends IBaseService<FormDefinition, FormDefinitionDTO, FormDefinitionQuery, Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布表单(版本不可变)
|
||||||
|
* 如果当前表单已发布,则创建新版本;否则直接发布
|
||||||
|
*
|
||||||
|
* @param id 表单定义ID
|
||||||
|
* @return 发布后的表单定义
|
||||||
|
*/
|
||||||
|
FormDefinitionDTO publish(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据表单标识获取最新版本
|
||||||
|
*
|
||||||
|
* @param key 表单标识
|
||||||
|
* @return 表单定义
|
||||||
|
*/
|
||||||
|
FormDefinitionDTO getLatestByKey(String key);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.service.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
|
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDataDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.query.FormDataQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormData;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormDefinition;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDataStatusEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.repository.IFormDataRepository;
|
||||||
|
import com.qqchen.deploy.backend.workflow.repository.IFormDefinitionRepository;
|
||||||
|
import com.qqchen.deploy.backend.workflow.service.IFormDataService;
|
||||||
|
import com.qqchen.deploy.backend.workflow.converter.FormDataConverter;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单数据服务实现
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class FormDataServiceImpl extends BaseServiceImpl<FormData, FormDataDTO, FormDataQuery, Long> implements IFormDataService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFormDataRepository formDataRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFormDefinitionRepository formDefinitionRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FormDataConverter formDataConverter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public FormDataDTO submit(FormDataDTO dto) {
|
||||||
|
log.info("提交表单数据: formKey={}, submitter={}", dto.getFormKey(), dto.getSubmitter());
|
||||||
|
|
||||||
|
// 1. 查询表单定义,获取schema快照
|
||||||
|
FormDefinition formDefinition = formDefinitionRepository.findById(dto.getFormDefinitionId())
|
||||||
|
.orElseThrow(() -> new BusinessException(com.qqchen.deploy.backend.framework.enums.ResponseCode.FORM_DEFINITION_NOT_FOUND));
|
||||||
|
|
||||||
|
// 2. 创建表单数据
|
||||||
|
FormData formData = formDataConverter.toEntity(dto);
|
||||||
|
formData.setFormKey(formDefinition.getKey());
|
||||||
|
formData.setFormVersion(formDefinition.getFormVersion());
|
||||||
|
formData.setSchemaSnapshot(formDefinition.getSchema()); // 保存schema快照
|
||||||
|
formData.setSubmitTime(LocalDateTime.now());
|
||||||
|
formData.setStatus(FormDataStatusEnums.SUBMITTED);
|
||||||
|
|
||||||
|
// 3. 保存
|
||||||
|
FormData savedFormData = formDataRepository.save(formData);
|
||||||
|
log.info("表单数据提交成功: id={}, formKey={}", savedFormData.getId(), savedFormData.getFormKey());
|
||||||
|
|
||||||
|
return formDataConverter.toDto(savedFormData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FormDataDTO getByBusinessKey(String businessKey) {
|
||||||
|
log.info("根据业务标识查询表单数据: businessKey={}", businessKey);
|
||||||
|
|
||||||
|
FormData formData = formDataRepository.findByBusinessKeyAndDeletedFalse(businessKey)
|
||||||
|
.orElseThrow(() -> new BusinessException(com.qqchen.deploy.backend.framework.enums.ResponseCode.FORM_DATA_NOT_FOUND));
|
||||||
|
|
||||||
|
return formDataConverter.toDto(formData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.service.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
|
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.FormDefinitionDTO;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.query.FormDefinitionQuery;
|
||||||
|
import com.qqchen.deploy.backend.workflow.entity.FormDefinition;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.FormDefinitionStatusEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.repository.IFormDefinitionRepository;
|
||||||
|
import com.qqchen.deploy.backend.workflow.service.IFormDefinitionService;
|
||||||
|
import com.qqchen.deploy.backend.workflow.converter.FormDefinitionConverter;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单定义服务实现
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @date 2025-10-24
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class FormDefinitionServiceImpl extends BaseServiceImpl<FormDefinition, FormDefinitionDTO, FormDefinitionQuery, Long> implements IFormDefinitionService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFormDefinitionRepository formDefinitionRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FormDefinitionConverter formDefinitionConverter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public FormDefinitionDTO publish(Long id) {
|
||||||
|
log.info("发布表单定义,ID: {}", id);
|
||||||
|
|
||||||
|
// 1. 查询当前表单定义
|
||||||
|
FormDefinition currentForm = formDefinitionRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new BusinessException(com.qqchen.deploy.backend.framework.enums.ResponseCode.FORM_DEFINITION_NOT_FOUND));
|
||||||
|
|
||||||
|
// 2. 检查是否已发布
|
||||||
|
if (FormDefinitionStatusEnums.PUBLISHED.equals(currentForm.getStatus())) {
|
||||||
|
log.info("表单已发布,创建新版本: key={}, currentVersion={}", currentForm.getKey(), currentForm.getFormVersion());
|
||||||
|
|
||||||
|
// 创建新版本
|
||||||
|
FormDefinition newVersion = new FormDefinition();
|
||||||
|
newVersion.setName(currentForm.getName());
|
||||||
|
newVersion.setKey(currentForm.getKey());
|
||||||
|
newVersion.setFormVersion(currentForm.getFormVersion() + 1);
|
||||||
|
newVersion.setCategory(currentForm.getCategory());
|
||||||
|
newVersion.setDescription(currentForm.getDescription());
|
||||||
|
newVersion.setSchema(currentForm.getSchema());
|
||||||
|
newVersion.setTags(currentForm.getTags());
|
||||||
|
newVersion.setStatus(FormDefinitionStatusEnums.PUBLISHED);
|
||||||
|
newVersion.setIsTemplate(currentForm.getIsTemplate());
|
||||||
|
|
||||||
|
FormDefinition savedNewVersion = formDefinitionRepository.save(newVersion);
|
||||||
|
log.info("新版本创建成功: id={}, version={}", savedNewVersion.getId(), savedNewVersion.getFormVersion());
|
||||||
|
|
||||||
|
return formDefinitionConverter.toDto(savedNewVersion);
|
||||||
|
} else {
|
||||||
|
// 3. 首次发布,直接更新状态
|
||||||
|
log.info("首次发布表单: key={}, version={}", currentForm.getKey(), currentForm.getFormVersion());
|
||||||
|
currentForm.setStatus(FormDefinitionStatusEnums.PUBLISHED);
|
||||||
|
if (currentForm.getFormVersion() == null) {
|
||||||
|
currentForm.setFormVersion(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FormDefinition savedForm = formDefinitionRepository.save(currentForm);
|
||||||
|
log.info("表单发布成功: id={}, version={}", savedForm.getId(), savedForm.getFormVersion());
|
||||||
|
|
||||||
|
return formDefinitionConverter.toDto(savedForm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FormDefinitionDTO getLatestByKey(String key) {
|
||||||
|
log.info("根据key获取最新版本表单: key={}", key);
|
||||||
|
|
||||||
|
FormDefinition formDefinition = formDefinitionRepository
|
||||||
|
.findFirstByKeyAndDeletedFalseOrderByFormVersionDesc(key)
|
||||||
|
.orElseThrow(() -> new BusinessException(com.qqchen.deploy.backend.framework.enums.ResponseCode.FORM_DEFINITION_NOT_FOUND));
|
||||||
|
|
||||||
|
return formDefinitionConverter.toDto(formDefinition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -689,3 +689,91 @@ CREATE TABLE sys_notification_channel (
|
|||||||
INDEX idx_deleted (deleted)
|
INDEX idx_deleted (deleted)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='通知渠道配置表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='通知渠道配置表';
|
||||||
|
|
||||||
|
-- =====================================================================================================================
|
||||||
|
-- 表单管理相关表
|
||||||
|
-- =====================================================================================================================
|
||||||
|
|
||||||
|
-- 表单定义表
|
||||||
|
CREATE TABLE form_definition
|
||||||
|
(
|
||||||
|
-- 主键
|
||||||
|
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
|
||||||
|
-- 基础信息
|
||||||
|
name VARCHAR(255) NOT NULL COMMENT '表单名称',
|
||||||
|
`key` VARCHAR(255) NOT NULL COMMENT '表单标识(业务唯一)',
|
||||||
|
form_version INT NOT NULL DEFAULT 1 COMMENT '表单版本号',
|
||||||
|
category VARCHAR(100) NULL COMMENT '表单分类(APPROVAL-审批、DATA_COLLECTION-数据采集、SURVEY-问卷调查、OTHER-其他)',
|
||||||
|
description TEXT NULL COMMENT '表单描述',
|
||||||
|
|
||||||
|
-- 表单配置
|
||||||
|
schema JSON NOT NULL COMMENT '表单Schema(前端设计器导出的JSON结构)',
|
||||||
|
tags JSON NULL COMMENT '标签(用于分类和搜索)',
|
||||||
|
|
||||||
|
-- 表单属性
|
||||||
|
status VARCHAR(50) NOT NULL DEFAULT 'DRAFT' COMMENT '状态(DRAFT-草稿、PUBLISHED-已发布、DISABLED-已禁用)',
|
||||||
|
is_template BIT NOT NULL DEFAULT 0 COMMENT '是否为模板',
|
||||||
|
|
||||||
|
-- 审计字段
|
||||||
|
create_by VARCHAR(255) NULL COMMENT '创建人',
|
||||||
|
create_time DATETIME(6) NULL COMMENT '创建时间',
|
||||||
|
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||||
|
update_by VARCHAR(255) NULL COMMENT '更新人',
|
||||||
|
update_time DATETIME(6) NULL COMMENT '更新时间',
|
||||||
|
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||||
|
|
||||||
|
-- 约束和索引
|
||||||
|
UNIQUE KEY uk_key_version (`key`, form_version),
|
||||||
|
INDEX idx_category (category),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_is_template (is_template),
|
||||||
|
INDEX idx_deleted (deleted)
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci
|
||||||
|
COMMENT = '表单定义表';
|
||||||
|
|
||||||
|
-- 表单数据表
|
||||||
|
CREATE TABLE form_data
|
||||||
|
(
|
||||||
|
-- 主键
|
||||||
|
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
|
||||||
|
-- 关联表单定义
|
||||||
|
form_definition_id BIGINT NOT NULL COMMENT '表单定义ID',
|
||||||
|
form_key VARCHAR(255) NOT NULL COMMENT '表单标识(冗余存储,避免JOIN)',
|
||||||
|
form_version INT NOT NULL COMMENT '表单版本(冗余存储,用于历史追溯)',
|
||||||
|
|
||||||
|
-- 业务关联(松耦合)
|
||||||
|
business_key VARCHAR(255) NULL COMMENT '业务标识(如工作流实例ID、订单号等)',
|
||||||
|
business_type VARCHAR(50) NULL COMMENT '业务类型(WORKFLOW-工作流、ORDER-订单、STANDALONE-独立表单)',
|
||||||
|
|
||||||
|
-- 表单数据
|
||||||
|
data JSON NOT NULL COMMENT '表单填写数据(用户提交的实际数据)',
|
||||||
|
schema_snapshot JSON NOT NULL COMMENT '表单Schema快照(用于历史追溯,确保数据可还原)',
|
||||||
|
|
||||||
|
-- 提交信息
|
||||||
|
submitter VARCHAR(255) NULL COMMENT '提交人',
|
||||||
|
submit_time DATETIME(6) NULL COMMENT '提交时间',
|
||||||
|
|
||||||
|
-- 状态
|
||||||
|
status VARCHAR(50) NOT NULL DEFAULT 'SUBMITTED' COMMENT '状态(DRAFT-草稿、SUBMITTED-已提交、COMPLETED-已完成、REJECTED-已拒绝)',
|
||||||
|
|
||||||
|
-- 审计字段
|
||||||
|
create_by VARCHAR(255) NULL COMMENT '创建人',
|
||||||
|
create_time DATETIME(6) NULL COMMENT '创建时间',
|
||||||
|
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||||
|
update_by VARCHAR(255) NULL COMMENT '更新人',
|
||||||
|
update_time DATETIME(6) NULL COMMENT '更新时间',
|
||||||
|
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||||
|
|
||||||
|
-- 索引
|
||||||
|
INDEX idx_form_definition_id (form_definition_id),
|
||||||
|
INDEX idx_form_key (form_key),
|
||||||
|
INDEX idx_business_key (business_key),
|
||||||
|
INDEX idx_business_type (business_type),
|
||||||
|
INDEX idx_submitter (submitter),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_submit_time (submit_time),
|
||||||
|
INDEX idx_deleted (deleted)
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci
|
||||||
|
COMMENT = '表单数据表';
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user