工作流:通过业务数据操作工作流程(催办、撤销等)

一、抽象模型,需要操作流程的模型继承此模型

定义流程相关的一些信息在模型中;如果直接定义在存储模型中,下面这些字段都是显示的指定为非存储字段。更好的建议:
1、如果有多个业务模型有这类需要,则可以把这些字段抽取到抽象模型中
2、如果仅有一个业务模型需要,则可以放到代理模型中

/**
 * 定义流程相关的一些信息在模型中
 */
@Model.model(DemoBaseAbstractModel.MODEL_MODEL)
@Model(displayName = "抽象模型")
@Model.Advanced(type= ModelTypeEnum.ABSTRACT)
public abstract class DemoBaseAbstractModel extends IdModel {

    public static final String MODEL_MODEL = "hr.simple.DemoBaseAbstractModel";

    // 流程相关
    @Field.Integer
    @Field(displayName = "工作流用户任务ID", summary = "业务数据列表中审核流程使用", invisible = true, store = NullableBoolEnum.FALSE)
    private Long workflowUserTaskId;

    @Field.Integer
    @Field(displayName = "流程实例ID", summary = "业务数据列表中催办使用", invisible = true, store = NullableBoolEnum.FALSE)
    private Long instanceId;

    @Field.String
    @UxForm.FieldWidget(@UxWidget(invisible = "true"))
    @UxDetail.FieldWidget(@UxWidget(invisible = "true"))
    @Field(displayName = "当前流程节点", store = NullableBoolEnum.FALSE)
    private String currentFlowNode;

    @Field.Boolean
    @Field(displayName = "能否催办", invisible = true, defaultValue = "false", store = NullableBoolEnum.FALSE)
    private Boolean canUrge;

    // 审批状态控制申请单是否可以被发起流程、能否编辑等控制
    @Field.Enum
    @Field(displayName = "审批状态", defaultValue = "NC")
    @UxForm.FieldWidget(@UxWidget(invisible = "true"))
    private ApprovalStatusEnum approvalStatus;

}
@Dict(dictionary = ApprovalStatusEnum.dictionary, displayName = "审批状态")
public enum ApprovalStatusEnum implements IEnum<String> {
    NC("NC", "待提交", "待提交"),
    PENDING("PENDING", "已提交", "已提交,待审批"),
    APPROVED("APPROVED", "已批准", "已批准"),
    REJECTED("REJECTED", "已拒绝", "已拒绝");

    public static final String dictionary = "land.enums.LandApprovalStatusEnum";

    private final String value;
    private final String displayName;
    private final String help;

    ApprovalStatusEnum(String value, String displayName, String help) {
        this.value = value;
        this.displayName = displayName;
        this.help = help;
    }

    public String getValue() {
        return value;
    }

    public String getDisplayName() {
        return displayName;
    }

    public String getHelp() {
        return help;
    }
}

二、实现公共逻辑(催办、撤销)

@Slf4j
@Component
@Model.model(DemoBaseAbstractModel.MODEL_MODEL)
public class DemoBaseAbstractModelAction {

    @Autowired
    private WorkflowInstanceService workflowInstanceService;

    @Action(displayName = "催办", summary = "流程催办", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    @Action.Advanced(invisible = "!activeRecord.canUrge")
    public DemoBaseAbstractModel urge(DemoBaseAbstractModel data) {
        if (data.getInstanceId() == null) {
            return data;
        }

        WorkflowInstance instance = new WorkflowInstance().setId(data.getInstanceId()).queryById();
        workflowInstanceService.urge(instance);
        PamirsSession.getMessageHub().success("催办操作成功");
        return data;
    }

    @Action(displayName = "提交审核", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    @Action.Advanced(invisible = "activeRecord.approvalStatus != 'NC'")
    public DemoBaseAbstractModel submit(DemoBaseAbstractModel data) {
        data.setApprovalStatus(ApprovalStatusEnum.PENDING);
        data.updateById();
        PamirsSession.getMessageHub().success("提交审核成功");
        return data;
    }

    @Function(openLevel = FunctionOpenEnum.LOCAL)
    @Function.Advanced(type = FunctionTypeEnum.UPDATE, displayName = "审核通过")
    public DemoBaseAbstractModel applySuccess(DemoBaseAbstractModel data) {
        data.setApprovalStatus(ApprovalStatusEnum.APPROVED);
        data.updateById();

        return data;
    }

    @Action(displayName = "撤销", bindingType = ViewTypeEnum.TABLE)
    public DemoBaseAbstractModel undo(DemoBaseAbstractModel data) {
        if (data.getInstanceId() == null) {
            return data;
        }
        WorkflowInstance instance = new WorkflowInstance().setId(data.getInstanceId()).queryById();
        workflowInstanceService.undoInstance(instance.getId());

        data.setApprovalStatus(ApprovalStatusEnum.NC);
        data.updateById();

        return data;
    }

}

三 、定义业务模型

@Model.model(AssetsProxy.MODEL_MODEL)
@Model(displayName = "资产代理模型")
public class AssetsProxy extends DemoBaseAbstractModel {

    public static final String MODEL_MODEL = "land.mgmt.AssetsProxy";

    @Field(displayName = "使用单位")
    private String useUnit;

    @Field.String
    @Field(displayName = "统一社会信用代码")
    private String creditCode;

    @Field(displayName = "联系电话")
    private String contactNumber;

    @Field.String
    @Field(displayName = "申请单号", invisible = true)
    private String number;

}

四、业务数据逻辑

在业务表格中、通过自定义queryPage查询,将工作流实例ID、用户待办ID,动态的放到业务数据中,以便于实现催办、撤销逻辑。
如需只能自己发起的才能进行操作,这个条件可以在页面设计器上配置,也可以写到Action上,本文催办按钮在Action上定义。也可以在界面设计器设置按钮的隐藏条件(activeRecord.canUrge==true)

@Slf4j
@Component
@Model.model(AssetsProxy.MODEL_MODEL)
public class AssetsProxyAction {

    @Autowired
    private WorkflowUserTaskHandler workflowUserTaskHandler;

    @Function.Advanced(type = FunctionTypeEnum.QUERY, displayName = "查询列表")
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.API})
    public Pagination<AssetsProxy> queryPage(Pagination<AssetsProxy> page, QueryWrapper<AssetsProxy> queryWrapper) {
        page = new AssetsProxy().queryPage(page, queryWrapper);
        workflowUserTaskHandler.computeWorkflowUserTask(page.getContent(), AssetsProxy.MODEL_MODEL);
        return page;
    }

    @Transactional
    @Action.Advanced(name = FunctionConstants.create, managed = true, invisible = ExpConstants.idValueExist)
    @Action(displayName = "保存", summary = "创建", bindingType = ViewTypeEnum.FORM)
    @Function(name = FunctionConstants.create)
    @Function.fun(FunctionConstants.create)
    public AssetsProxy create(AssetsProxy data) {
        data.setApprovalStatus(ApprovalStatusEnum.NC);
        data.construct();
        data.create();

        return data;
    }

    @Transactional
    @Action.Advanced(invisible = ExpConstants.idValueExist)
    @Action(displayName = "保存并发起流程", summary = "保存并发起流程", bindingType = ViewTypeEnum.FORM)
    public AssetsProxy saveAndSubmit(AssetsProxy data) {
        data.setApprovalStatus(ApprovalStatusEnum.PENDING);
        data.construct();
        data.create();

        // 代码触发工作流ID
        WorkflowD workflowD = new WorkflowD().setId(759036552176484888L).queryOne();
        if (workflowD != null) {
            startWorkflow(workflowD, data);
        }

        return data;
    }

    /**
     * 触发⼯作流实例
     */
    private Boolean startWorkflow(WorkflowD workflowD, IdModel modelData) {
        WorkflowDefinition workflowDefinition = new WorkflowDefinition().queryOneByWrapper(
                Pops.<WorkflowDefinition>lambdaQuery()
                        .from(WorkflowDefinition.MODEL_MODEL)
                        .eq(WorkflowDefinition::getWorkflowCode, workflowD.getCode())
                        .eq(WorkflowDefinition::getActive, 1)
        );
        if (null == workflowDefinition) {
            // 流程没有运⾏实例
            return Boolean.FALSE;
        }
        String model = Models.api().getModel(modelData);

        //⼯作流上下⽂
        WorkflowDataContext wdc = new WorkflowDataContext();
        wdc.setDataType(WorkflowVariationTypeEnum.ADD);
        wdc.setModel(model);
        wdc.setWorkflowDefinitionDefinition(workflowDefinition.parseContent());
        wdc.setWorkflowDefinition(workflowDefinition);
        wdc.setWorkflowDefinitionId(workflowDefinition.getId());
        IdModel copyData = KryoUtils.get().copy(modelData);
        // ⼿动触发创建的动作流,将操作⼈设置为当前⽤户,作为流程的发起⼈
        copyData.setCreateUid(PamirsSession.getUserId());
        copyData.setWriteUid(PamirsSession.getUserId());
        String jsonData = JsonUtils.toJSONString(copyData.get_d());
        //触发⼯作流 新增时触发-onCreateManual 更新时触发-onUpdateManual
        String msgId = UUIDUtil.getUUIDNumberString();
        Fun.run(WorkflowModelTriggerFunction.FUN_NAMESPACE, "onCreateManual", wdc, msgId, jsonData);
        return Boolean.TRUE;
    }

}
@Component
public class WorkflowUserTaskHandler<T extends DemoBaseAbstractModel> {

    public void computeWorkflowUserTask(List<T> datas, String model) {
        if (CollectionUtils.isEmpty(datas)) {
            return;
        }

        // 过滤掉【草稿状态】和【审核通过】的数据,减少数据查询量
        List<Long> bizIds = ListUtils.transform(datas, DemoBaseAbstractModel::getId);
        LambdaQueryWrapper<WorkflowUserTask> userTaskWrapper = new LambdaQueryWrapper<>();
        userTaskWrapper.setModel(WorkflowUserTask.MODEL_MODEL);
        userTaskWrapper.select(WorkflowUserTask::getId, WorkflowUserTask::getNodeDataBizId, WorkflowUserTask::getUserId, WorkflowUserTask::getInitiatorUid,
                WorkflowUserTask::getNodeName, WorkflowUserTask::getNodeId, WorkflowUserTask::getInstanceId);
        userTaskWrapper.eq(WorkflowUserTask::getModel, model)
                .eq(WorkflowUserTask::getStatus, WorkflowUserStatusEnum.ACTIVE)
                .in(WorkflowUserTask::getNodeDataBizId, bizIds);

        Pagination<WorkflowUserTask> userTaskPagination = new Pagination<>();
        userTaskPagination.setCurrentPage(1);
        userTaskPagination.setSize(200L);
        userTaskPagination.setSort(new Sort().addOrder(SortDirectionEnum.DESC, WorkflowUserTask::getCreateDate));
        List<WorkflowUserTask> allUserTasks = new WorkflowUserTask().queryListByWrapper(userTaskPagination, userTaskWrapper);
        if (CollectionUtils.isEmpty(allUserTasks)) {
            return;
        }

        // 按NodeDataBizId分组,保留第一个出现的对象
        Map<Long, WorkflowUserTask> workflowUserTaskMap = allUserTasks.stream().filter(user -> user.getNodeDataBizId() != null)
                .collect(Collectors.toMap(WorkflowUserTask::getNodeDataBizId, user -> user, (existing, replacement) -> existing));
        // userTaskWrapper.eq(WorkflowUserTask::getUserId, PamirsSession.getUserId())
        List<WorkflowUserTask> userTasks = allUserTasks.stream().filter(task -> task.getUserId() != null && task.getUserId().equals(PamirsSession.getUserId())).collect(Collectors.toList());
        Map<Long, WorkflowUserTask> userTaskMap = userTasks.stream().collect(Collectors.toMap(WorkflowUserTask::getNodeDataBizId, v -> v, (a, b) -> a));
        Map<Long, String> nodeNameResult = nodeNameResult(allUserTasks);
        datas.forEach(item -> {
            item.setCanUrge(Boolean.FALSE);
            WorkflowUserTask currenctWorkflowUserTask = userTaskMap.get(item.getId());
            if (currenctWorkflowUserTask != null) {
                item.setWorkflowUserTaskId(currenctWorkflowUserTask.getId());
                item.setCurrentFlowNode(currenctWorkflowUserTask.getNodeName());
            }
            WorkflowUserTask workflowUserTask = workflowUserTaskMap.get(item.getId());
            if (workflowUserTask != null) {
                item.setInstanceId(workflowUserTask.getInstanceId());
                item.setCurrentFlowNode(nodeNameResult.get(workflowUserTask.getNodeDataBizId()));
                if (workflowUserTask.getInitiatorUid() != null
                        && workflowUserTask.getInitiatorUid().equals(PamirsSession.getUserId())) {
                    item.setCanUrge(Boolean.TRUE);
                }
            }
            if (ApprovalStatusEnum.APPROVED.equals(item.getApprovalStatus())) {
                item.setCurrentFlowNode("审批通过");
            } else if (ApprovalStatusEnum.REJECTED.equals(item.getApprovalStatus())) {
                item.setCurrentFlowNode("审批拒绝");
            }
        });
    }
    private Map<Long, String> nodeNameResult(List<WorkflowUserTask> allUserTasks) {
        // 分组逻辑:按 department 分组,提取 name 并去重拼接
        Map<Long, String> result = new HashMap<>();
        for (WorkflowUserTask userTask : allUserTasks) {
            Long nodeDataBizId = userTask.getNodeDataBizId();
            String nodeName = userTask.getNodeName();

            // 过滤掉 null 和空字符串的 name
            if (nodeName == null || nodeName.trim().isEmpty()) {
                continue;
            }

            // 初始化分组 Set
            result.putIfAbsent(nodeDataBizId, "");

            // 使用 LinkedHashSet 去重并保留顺序
            Set<String> nodeNamesSet = new LinkedHashSet<>();
            if (!result.get(nodeDataBizId).isEmpty()) {
                Collections.addAll(nodeNamesSet, result.get(nodeDataBizId).split(","));
            }
            nodeNamesSet.add(nodeName);

            // 更新结果
            result.put(nodeDataBizId, String.join(",", nodeNamesSet));
        }

        return result;
    }
}

五、效果图

工作流:通过业务数据操作工作流程(催办、撤销等)

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/dai-ma-shi-jian/21291.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
yexiu的头像yexiu数式员工
上一篇 2025年6月24日 pm7:50
下一篇 2025年7月8日 pm3:21

相关推荐

  • 模型定义在数据库中的映射

    模型定义在数据库中的映射 Oinone中通过定义模型来建立数据表,使用注解的方式来使多张表之间的关联。 数据库字段与模型定义字段映射 package pro.shushi.pamirs.top.api.model; import pro.shushi.pamirs.core.common.enmu.DataStatusEnum; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; import pro.shushi.pamirs.meta.enmu.DateFormatEnum; import pro.shushi.pamirs.meta.enmu.DateTypeEnum; import pro.shushi.pamirs.meta.enmu.MimeTypeEnum; import java.math.BigDecimal; import java.util.Date; @Model.model(PamirsDemo.MODEL_MODEL) @Model(displayName = “PamirsDemo”) public class PamirsDemo extends IdModel { public static final String MODEL_MODEL = “top.PamirsDemo”; @Field.Binary(mime = MimeTypeEnum.html) @Field(displayName = “二进制类型”) private Byte[] byteType; @Field.Integer @Field(displayName = “整数”) private Long longType; @Field.Float @Field(displayName = “浮点数”) private BigDecimal floatType; @Field.Boolean @Field(displayName = “布尔类型”) private Boolean booleanType; @Field.Enum @Field(displayName = “枚举”) private DataStatusEnum enumType; @Field.String @Field(displayName = “字符串”) private String stringType; @Field.Text @Field(displayName = “多行文本”) private String textType; @Field.Html @Field(displayName = “富文本”) private String richText; @Field.Date(type = DateTypeEnum.DATE, format = DateFormatEnum.DATE) @Field(displayName = “日期类型”) private Date dataType; @Field.Date(type = DateTypeEnum.DATETIME, format = DateFormatEnum.DATETIME) @Field(displayName = “日期时间类型”) private Date dataTimeType; @Field.Money @Field(displayName = “金额”) private BigDecimal amount; } 更多字段基础请参考文档字段基础与复合 多对一的关系映射 例:设计一张教师表,一张科目表,教师表对科目表属于多对一的关系,在教师表中使用科目id管理关联关系。 教师表teacher 科目表professional 那么在Oinone的模型定义中,这两张表定义是这样的; 教师模型 package pro.shushi.pamirs.top.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; @Model.model(Teacher.MODEL_MODEL) @Model(displayName = “教师”, summary = “教师”) public class Teacher extends IdModel { public static final String MODEL_MODEL = “top.Teacher”; @Field.String @Field(displayName = “教师名字”) private String teacherName; @Field.Integer @Field(displayName = “科目id”) private Long professionalId; @Field(displayName…

    2024年8月16日
    88200
  • 【前端】项目开发前端知识要点地图

    概述 下面整理了目前现有的所有文章,并提供了基本的学习路径。所有使用*标记的文章属于推荐必读文章。 目录 基础篇 【路由】浏览器地址栏url参数介绍 母版-布局-DSL 渲染基础(v4)* 组件SPI机制(v4)* 组件数据交互基础(v4)* 组件生命周期(v4) 入门篇 自定义视图组件(v4)* 如何通过浏览器开发者工具提高调试效率* 如何提高自定义组件的开发效率* 自定义组件之自动渲染(组件插槽的使用)(v4)* GraphQL请求详解(v4)* 上下文在字段和动作中的应用 如何实现页面间的跳转 如何自定义指定页面的样式 进阶篇 自定义组件之手动渲染基础(v4) 自定义组件之手动渲染弹出层(v4) 自定义组件之手动渲染任意视图(v4) 【前端】IOC容器(v4) 最佳实践篇 【前端】工程结构最佳实践(v4)* 【前端】移动端工程结构最佳实践(v4)* 界面设计器实战篇 基础篇 【界面设计器】模型增删改查基础 【界面设计器】他表字段 【界面设计器】左树右表 【界面设计器】树形表格 【界面设计器】树下拉/级联选择 【界面设计器】自定义字段组件基础 展示篇 【界面设计器】自定义字段组件实战——轮播图 【界面设计器】自定义字段组件实战——表格字段组合展示 【界面设计器】自定义字段组件实战——表格字段内嵌表格 交互篇 【界面设计器】自定义字段组件实战——千分位输入框 其他 前端低无一体使用教程 如何自定义表格字段? 【界面设计器】组件开发常见问题 【前端】低无一体部署常见问题 【前端】生产环境性能调优 API文档 OioProvider详解(v4.3.0)* 前端环境配置(v4)* 默认布局模板(v4) 表格主题配置(v4) 运行时上下文API文档(v4) Class Component(ts)(v4)

    2024年5月25日
    3.6K00
  • 如何选择适合的模型类型?

    介绍 通过Oinone 7天从入门到精通的模型的类型章节我们可以知道模型有抽象模型、存储模型、代理模型、传输模型这四种。但是在在定义模型的时候我们可能不知道该如何选择类型,下面结合业务场景为大家讲解几种模型的典型使用场景。 抽象模型 抽象模型往往是提供公共能力和字段的模型,它本身不会直接用于构建协议和基础设施(如表结构等)。 场景:猫、鸟都继承自动物这个抽象模型 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.annotation.sys.Base; import pro.shushi.pamirs.meta.base.IdModel; import pro.shushi.pamirs.meta.enmu.ModelTypeEnum; @Base @Model.model(AbstractAnimal.MODEL_MODEL) @Model.Advanced(type = ModelTypeEnum.ABSTRACT) @Model(displayName = "动物") public abstract class AbstractAnimal extends IdModel { public static final String MODEL_MODEL = "demo.AbstractAnimal"; @Field.String @Field(displayName = "名称") private String name; @Field.String @Field(displayName = "颜色") private String color; } package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(Cat.MODEL_MODEL) @Model(displayName = "猫") public class Cat extends AbstractAnimal { private static final long serialVersionUID = -5104390780952634397L; public static final String MODEL_MODEL = "demo.Cat"; @Field.Integer @Field(displayName = "尾巴长度") private Integer tailLength; } package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(Bird.MODEL_MODEL) @Model(displayName = "鸟") public class Bird extends AbstractAnimal { private static final long serialVersionUID = -5144390780952634397L; public static final String MODEL_MODEL = "demo.Bird"; @Field.Integer @Field(displayName = "翼展宽度") private Integer wingSpanWidth; } 存储模型 存储模型用于定义数据表结构和数据的增删改查(数据管理器)功能,是直接与连接器进行交互的数据容器。 场景:存储模型对应传统开发模式中的数据表,上面例子中的Cat和Birdd都属于传输模型,由于模型定义的注解@Model.Advanced(type = ModelTypeEnum.STORE)默认值就是存储模型,所以一般不用手动指定 代理模型 代理模型是用于代理存储模型的数据管理器能力,同时又可以扩展出非存储数据信息的交互功能的模型。 场景一:隔离数据权限 场景二:增强列表的搜索项 场景三:导入导出的时候增加其他特殊信息 场景四:重写下拉组件的查询逻辑做数据过滤 传输模型 传输模型不会在数据库生成的表,只是作为数据的传输使用,跟传统开发模式中的DTO有一点相似。 场景一:批量处理数据 场景二:处理一些跟数据表无关的操作,如:清理指定业务的缓存、查看一些系统监控信息,可以根据业务信息建立对应的传输模型,在传输模型上创建action动作 场景三:通过传输模型完成复杂页面数据传输

    2024年4月7日
    1.1K00
  • 如何把平台功能菜单加到项目中?

    概述 在使用Oinone低代码平台进行项目开发的过程中,会存在把平台默认提供的菜单加到自己的项目中。这篇文章介绍实现方式,以角色管理为例。 1. 低代码情况 即项目是通过后端代码初始化菜单的方式。 通常在 XXXMenu.java类通过@UxMenu注解的方式,代码片段如下: 此种情况与添加项目本地的菜单无区别,具体代码: @UxMenu(value = "账号管理", icon = "icon-yonghuguanli") class AccountManage { @UxMenu("用户管理") @UxRoute(value = CustomerCompanyUserProxy.MODEL_MODEL, title = "用户管理") class CompanyUserManage { } @UxMenu("角色管理") @UxRoute(value = AuthRole.MODEL_MODEL, module = AdminModule.MODULE_MODULE, title = "角色管理") class RoleManage { } @UxMenu("操作日志") @UxRoute(value = OperationLog.MODEL_MODEL, module = AdminModule.MODULE_MODULE/***菜单所挂载的模块**/) class OperateLog { } } 2. 无代码情况 在界面设计器中,新建菜单–>选择绑定已有页面,进行发布即可。

    2024年4月19日
    1.4K00
  • 复杂Excel模版定义

    模版示例: Demo Excel样例 代码示例: @Model.model(TestApply.MODEL_MODEL) @Model(displayName = "测试申请") public class TestApply extends IdModel { public static final String MODEL_MODEL = "top.TestApply"; @Field.String @Field(displayName = "发件人") private String addresser; @Field.String @Field(displayName = "委托单位") private String entrustedUnit; @Field.String @Field(displayName = "付款单位") private String payer; @Field.String @Field(displayName = "付款单位地址") private String paymentUnitAdd; } 模版: package pro.shushi.pamirs.top.core.temp; import org.springframework.stereotype.Component; import pro.shushi.pamirs.file.api.builder.SheetDefinitionBuilder; import pro.shushi.pamirs.file.api.builder.WorkbookDefinitionBuilder; import pro.shushi.pamirs.file.api.enmu.ExcelAnalysisTypeEnum; import pro.shushi.pamirs.file.api.enmu.ExcelDirectionEnum; import pro.shushi.pamirs.file.api.enmu.ExcelHorizontalAlignmentEnum; import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition; import pro.shushi.pamirs.file.api.util.ExcelHelper; import pro.shushi.pamirs.file.api.util.ExcelTemplateInit; import pro.shushi.pamirs.top.api.model.TestApply; import java.util.Collections; import java.util.List; @Component public class DemoTemplate implements ExcelTemplateInit { public static final String TEMPLATE_NAME = "DemoTemplate"; @Override public List<ExcelWorkbookDefinition> generator() { WorkbookDefinitionBuilder builder = WorkbookDefinitionBuilder.newInstance(TestApply.MODEL_MODEL, TEMPLATE_NAME) .setDisplayName("测试Demo"); DemoTemplate.createSheet(builder); return Collections.singletonList(builder.build()); } private static void createSheet(WorkbookDefinitionBuilder builder) { SheetDefinitionBuilder sheetBuilder = builder.createSheet().setName("测试Demo"); buildBasicInfo(sheetBuilder); } private static void buildBasicInfo(SheetDefinitionBuilder builder) { //A1:D8:表示表头占的单元格数,范围必须大于实际表头行 BlockDefinitionBuilder mergeRange = builder.createBlock(TestApply.MODEL_MODEL, ExcelAnalysisTypeEnum.FIXED_HEADER, ExcelDirectionEnum.HORIZONTAL, "A1:D8") //预设行 .setPresetNumber(10) //合并哪几个单元格 .createMergeRange("A1:D1") .createMergeRange("A2:D2") .createMergeRange("A3:D3") .createMergeRange("A4:A6") .createMergeRange("B4:B6") .createMergeRange("C4:C6") .createMergeRange("D4:D5"); //createHeader创建行,createCell创建单元格,setField指定解析字段,setIsConfig指定为true标记该行是需要解析的值 mergeRange.createHeader().setStyleBuilder(ExcelHelper.createDefaultStyle()).setIsConfig(Boolean.TRUE) .createCell().setField("addresser").setStyleBuilder(ExcelHelper.createDefaultStyle().setWidth(6000)).and() .createCell().setField("entrustedUnit").and() .createCell().setField("payer").and() .createCell().setField("paymentUnitAdd").and() .and() .createHeader().setStyleBuilder(ExcelHelper.createDefaultStyle(typeface -> typeface.setBold(Boolean.TRUE)).setHorizontalAlignment(ExcelHorizontalAlignmentEnum.CENTER)) .createCell().setValue("Demo").and() .createCell().and() .createCell().and() .createCell().and() .and() //由于该行合并为一个单元格,所以其他可以不设置value .createHeader().setStyleBuilder(ExcelHelper.createDefaultStyle(typeface -> typeface.setBold(Boolean.TRUE)).setHorizontalAlignment(ExcelHorizontalAlignmentEnum.CENTER)) .createCell().setValue("生效金额").and() .createCell().and() .createCell().and() .createCell().and() .and() .createHeader().setStyleBuilder(ExcelHelper.createDefaultStyle(typeface -> typeface.setBold(Boolean.TRUE)).setHorizontalAlignment(ExcelHorizontalAlignmentEnum.RIGHT)) .createCell().setValue("金额单位:元").and() .createCell().and() .createCell().and() .createCell().and() .and() //easyExcel解析不了空行,所以这里写上值。由于上面使用createMergeRange把单元格合并了,并且D列有分割,这里填上每个单元格的值,把合并的单元格填为一样的。 .createHeader().setStyleBuilder(ExcelHelper.createDefaultStyle(typeface -> typeface.setBold(Boolean.TRUE)).setHorizontalAlignment(ExcelHorizontalAlignmentEnum.CENTER)) .createCell().setValue("发件人").and() .createCell().setValue("委托单位").and()…

    2024年11月18日
    1.8K00

Leave a Reply

登录后才能评论