【工作流】如何自定义工作流的待办任务列表

介绍

有些时候我们需要把一些业务数据同时展示在工作流的待办列表中,这时候我们可以通过覆写oinone的待办列表展示组件

1.添加工作流相关依赖

业务的api工程添加工作流相关依赖

package pro.shushi.pamirs.demo.api;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.core.common.CommonModule;
import pro.shushi.pamirs.file.api.FileModule;
import pro.shushi.pamirs.meta.annotation.Module;
import pro.shushi.pamirs.meta.base.PamirsModule;
import pro.shushi.pamirs.meta.common.constants.ModuleConstants;
import pro.shushi.pamirs.user.api.UserModule;
import pro.shushi.pamirs.workflow.app.api.WorkflowModule;

@Component
@Module(
        name = DemoModule.MODULE_NAME,
        displayName = "oinoneDemo工程",
        version = "1.0.0",
        // 登录后默认访问 priority 值最小的模块
        priority = 1,
        dependencies = {ModuleConstants.MODULE_BASE,
                CommonModule.MODULE_MODULE,
                UserModule.MODULE_MODULE,
                // 此处新增工作流依赖
                WorkflowModule.MODULE_MODULE,
                FileModule.MODULE_MODULE
        }
)
@Module.module(DemoModule.MODULE_MODULE)
@Module.Advanced(selfBuilt = true, application = true)
public class DemoModule implements PamirsModule {

    public static final String MODULE_MODULE = "demo_core";

    public static final String MODULE_NAME = "DemoCore";

    @Override
    public String[] packagePrefix() {
        return new String[]{
                "pro.shushi.pamirs.demo"
        };
    }
}

业务的core工程添加工作流相关依赖

<dependency>
    <groupId>pro.shushi.pamirs.workflow</groupId>
    <artifactId>pamirs-workflow-api</artifactId>
</dependency>
<dependency>
    <groupId>pro.shushi.pamirs.workflow</groupId>
    <artifactId>pamirs-workflow-core</artifactId>
</dependency>

2. 由于平台原有的视图中未返回业务模型的原始数据的字段,所以我们先要将originNodeContext字段加到视图中,该workbench_usertask_active_table.xml文件存放在src/resources目录下

<view model="workbench.WorkBenchWorkflowUserTaskActive" type="gallery" viewName="全部待办" name="全部待办" title="全部待办" layout="workflow_gallery_layout">

    <template slot="search" widget="search" disabledExpand="true" invisibleSearch="true">
        <field allowClear="true" span="4" widget="TabSelect" data="optionSelect" label="false" required="false" defaultValue="ACTIVE_TOTAl"/>
        <field allowClear="true" span="2" widget="TagSelect" data="taskTypeSelect" label="false" required="false" defaultValue="TOTAL"/>
        <field allowClear="true" span="1" name="workflowModule" data="workflowModule" label="false" placeholder="所属应用" searchTrigger="change" domain="systemSource != 'BASE' and systemSource != 'SYSTEM' and state=='installed' and application=='true' " />
        <field allowClear="true" span="1" widget="SearchInput" data="name" label="false" placeholder="使用名称搜索"  required="false"/>
    </template>

    <template slot="actionBar" widget="actionBar"/>

    <template colSpan="FULL" cols="1" defaultPageSize="OPTION_3" disabled="false" gotoListExportDialog="false" gotoListImportDialog="false" invisible="false" readonly="false" required="false" slot="gallery" widget="workflow-gallery">
        <template area="title,content,rowActions" colSpan="FULL" disabled="false" inlineActiveCount="FIVE" invisible="false" minHeight="180" readonly="false" required="false" slot="card" widget="card">
            <template slot="title"  borderVisible="BOTTOM">
                <field data="taskType" invisible="true"/>
                <field data="taskTypeSelect" invisible="true"/>
                <field span="3" data="nodeName" widget="Input" label=""/>
                <field span="3" data="originNodeContext" widget="Input" invisible="true"/>
                <field allowClear="true" span="10" data="name" disabled="false" invisible="false" justifyContent="START" label="" maxLength="128" orientation="TRANSVERSE" patternType="NONE" placeholder="名称" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showCount="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" type="TEXT" widget="Input"/>
                <field allowClear="true" span="2" name="customerTag" data="customerTag" invisible="!activeRecord.customerTag" bgColor="#035DFF"  textColor="#FFFFFF" disabled="false" justifyContent="END" label="" maxLength="128" orientation="TRANSVERSE" patternType="NONE" placeholder="名称" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showCount="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" type="TEXT" widget="TagString" emptyStyle="NULL"/>
                <field allowClear="true" span="2" name="customerTag" data="customerTag" invisible="activeRecord.customerTag" bgColor="#035DFF"  textColor="#FFFFFF" disabled="false" justifyContent="END" label="" maxLength="128" orientation="TRANSVERSE" patternType="NONE" placeholder="名称" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showCount="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" type="TEXT" widget="Input" emptyStyle="NULL"/>

                <field span="3" data="tag" label="" widget="Select" justifyContent="END" emptyStyle="NULL">
                    <options>
                        <option name="TAG_UN_READ" label="未读" backgroundColor='rgba(3,93,255,0.10)' color='#035DFF'/>
                        <option name="TAG_READ" label="已读" backgroundColor='#F1F1F1' color='rgba(0,0,0,0.25)'/>
                        <option name="TAG_PROCESSING" label="进行中" backgroundColor='#46BB36' color='#FFFFFF'/>
                        <option name="TAG_TIME_OUT" label="已超时" backgroundColor='#46BB36' color='#FFFFFF'/>
                        <option name="TAG_PASS" label="已通过" backgroundColor='#46BB36' color='#FFFFFF'/>
                        <option name="TAG_FILLED" label="已填写" backgroundColor='#46BB36' color='#FFFFFF'/>
                        <option name="TAG_REJECT" label="已拒绝" backgroundColor='#E02020' color='#FFFFFF'/>
                        <option name="TAG_TRANSFER" label="已转交" backgroundColor='#F1F1F1' color='rgba(0,0,0,0.25)'/>
                        <option name="TAG_RECALL" label="已撤销" backgroundColor='#F1F1F1' color='rgba(0,0,0,0.25)'/>
                        <option name="TAG_CUI" label="催" backgroundColor='rgba(255,50,50,0.10)' color='#FF3232'/>
                    </options>
                </field>
                <field allowClear="true" span="4" data="createDate" decimal="0" disabled="false" format="YYYY-MM-DD HH:mm" invisible="false" justifyContent="CENTER" label="" orientation="TRANSVERSE" placeholder="任务创建时间" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" widget="DateTimePicker"/>
            </template>
            <template slot="content">

                <field allowClear="true" colSpan="QUARTER" data="workflowModule" disabled="false" invisible="false" justifyContent="START" label="应用" optionLabel="activeRecord.displayName" optionType="关联模型字段" orientation="TRANSVERSE" placeholder="模块" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" widget="Select"/>
                <field allowClear="true" colSpan="QUARTER" data="source" disabled="false" invisible="false" justifyContent="START" label="来源" maxLength="1024" orientation="TRANSVERSE" patternType="NONE" placeholder="来源" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showCount="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" type="TEXT" widget="Input"/>
                <field allowClear="true" colSpan="QUARTER" data="fromDepartment" disabled="false" invisible="false" justifyContent="START" label="来源部门" maxLength="1024" orientation="TRANSVERSE" patternType="NONE" placeholder="来源部门" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showCount="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" type="TEXT" widget="Input"/>
                <field allowClear="true" colSpan="QUARTER" data="status" disabled="false" invisible="false" justifyContent="START" label="当前状态" maxLength="1024" orientation="TRANSVERSE" patternType="NONE" placeholder="状态显示名称" prefixStore="false" prefixType="TEXT" readonly="false" required="false" showCount="false" showPrefix="false" showSuffix="false" suffixStore="false" suffixType="TEXT" type="TEXT" widget="Select"/>
            </template>
            <template slot="rowActions">
                <action bizStyle="DEFAULT" cancelText="取消" closeDialog="true" closeDrawer="true" colSpan="FULL" confirm="确认要执行动作吗?" confirmPosition="BM" confirmType="POPPER" disabled="false" enableConfirm="false" enterText="确定" goBack="false" invisible="!(activeRecord.taskType == 'APPROVE' && activeRecord.status == 'ACTIVE')" label="审批" name="workflow_wait" readonly="false" refreshData="true" required="false" type="PRIMARY" validateForm="true" widget="ViewAction"/>
                <action bizStyle="DEFAULT" cancelText="取消" closeDialog="true" closeDrawer="true" colSpan="FULL" confirm="确认要执行动作吗?" confirmPosition="BM" confirmType="POPPER" disabled="false" enableConfirm="false" enterText="确定" goBack="false" invisible="!(activeRecord.taskType == 'WRITE' && activeRecord.status == 'ACTIVE')" label="填写" name="workflow_write" readonly="false" refreshData="true" required="false" type="PRIMARY" validateForm="true" widget="ViewAction"/>
            </template>
        </template>
        <field data="optionSelect" invisible="true"/>
        <field data="id" invisible="true"/>
    </template>

</view>

3. 在工程启动的生命周期MetaDataEditor的edit方法中手动覆盖工作流模块的待办列表的视图

@Component
public class DemoModuleAppInstall implements MetaDataEditor {

    @Override
    public void edit(AppLifecycleCommand command, Map<String, Meta> metaMap) {
        log.info("开始安装demo_core应用-元数据");
        InitializationUtil util = InitializationUtil.get(metaMap, DemoModule.MODULE_MODULE, DemoModule.MODULE_NAME);
        BizInitLoader.init(util, DemoModule.MODULE_MODULE);

        util.createView(WorkBenchWorkflowUserTaskActive.MODEL_MODEL, "全部待办", "全部待办", "file:workbench_usertask_active_table.xml", ViewTypeEnum.GALLERY, 77, false);
    }
}

4. 前端新增MyWorkflowRuntimeWidget组件,自定义其中的vue组件

MyWorkflowRuntimeWidget.ts文件
import { BaseElementWidget, SPI, ViewType } from '@kunlun/dependencies';
import MyWorkflowRuntime from './MyWorkflowRuntime.vue';
import { WorkflowRuntimeWidget } from '@kunlun/workflow';

@SPI.ClassFactory(
  BaseElementWidget.Token({
    viewType: ViewType.Gallery,
    widget: 'workflow-gallery'
  })
)
export class MyWorkflowRuntimeWidget extends WorkflowRuntimeWidget {
  public initialize(props) {
    super.initialize(props);
    this.setComponent(MyWorkflowRuntime);
    return this;
  }
}
MyWorkflowRuntime.vue文件
<template>
  <div class="default-gallery workflow-runtime-default-gallery">
    <div class="default-gallery-content default-gallery-show-pagination">
      <oio-spin wrapper-class-name="oio-gallery-wrapper oio-scrollbar" :loading="loading">
        <oio-table v-if="dataSource && dataSource.length" resizable :data="dataList">
          <vxe-table-column field="nodeName" title="节点名称"></vxe-table-column>
          <vxe-table-column field="name" title="名称"></vxe-table-column>
          <vxe-table-column title="商品名称">
            <template v-slot:default="{ row }">
              {{ row.nodeData && row.nodeData.name }}
            </template>
          </vxe-table-column>
          <vxe-table-column field="createDate" title="创建日期"></vxe-table-column>
          <vxe-table-column field="tag" title="标签">
            <template v-slot:default="{ row }">
              <div class="gallery-tag" style="justify-content: end" v-if="row.tag">
                <div class="tag" :style="getTagInfo(row.tag)" style="width: unset">
                  <div class="content">
                    {{ getTagInfo(row.tag).label }}
                  </div>
                </div>
              </div>
            </template>
          </vxe-table-column>
          <vxe-table-column field="status" title="状态">
            <template v-slot:default="{ row }">
              <div class="gallery-tag">
                <div class="tag" style="width: unset">
                  <div class="content">
                    {{ statusField && statusField.format(row.status) }}
                  </div>
                </div>
              </div>
            </template>
          </vxe-table-column>
          <vxe-table-column title="操作栏">
            <template v-slot:default="{ row }">
              <oio-button
                type="primary"
                v-for="action in getCardActions(row)"
                @click="executeWorkflowAction(action, row)"
              >
                  {{ action.displayName }}
              </oio-button>
            </template>
          </vxe-table-column>
        </oio-table>

        <a-empty v-else class="empty" :description="translateValueByKey('暂无数据')" />
      </oio-spin>
    </div>
    <div class="default-gallery-pagination">
      <OioPagination
        :currentPage="pagination.current"
        :pageSize="pagination.pageSize"
        :total="pagination.total"
        :showTotal="true"
        :showJumper="paginationStyle != ListPaginationStyle.SIMPLE"
        :showLastPage="paginationStyle != ListPaginationStyle.SIMPLE"
        :onChange="onPaginationChange"
      ></OioPagination>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, computed } from 'vue';
import {
  CommonGutterType,
  ListPaginationStyle,
  OioPagination,
  OioCard,
  OioSpin,
  OioRow,
  OioCol,
  OioButton,
  OioEmpty
} from '@kunlun/vue-ui-antd';
import { OioTable, ActiveRecord, Pagination, ModelFieldType, translateValueByKey } from '@kunlun/dependencies';
import { get as getValue } from 'lodash-es';

export default defineComponent({
  inheritAttrs: false,
  props: {
    dataSource: {
      type: Array as PropType<ActiveRecord[]>
    },
    cols: {
      type: Number
    },
    gutter: {
      type: [Number, String, Array, Object] as PropType<CommonGutterType>
    },
    loading: {
      type: Boolean,
      default: false
    },
    pagination: {
      type: Object as PropType<Pagination>,
      default: () => ({})
    },
    itemWidth: {
      type: Number
    },
    itemMinWidth: {
      type: Number
    },
    itemMaxWidth: {
      type: Number
    },
    showPagination: {
      type: Boolean,
      default: true
    },
    paginationStyle: {
      type: String as PropType<ListPaginationStyle>
    },
    onPaginationChange: {
      type: Function,
      required: true
    },
    getTagInfo: {
      type: Function,
      required: true
    },
    contentFields: {
      type: Array,
      default: () => []
    },
    getCardActions: {
      type: Function,
      required: true
    },
    executeWorkflowAction: {
      type: Function,
      required: true
    }
  },
  components: {
    OioPagination,
    OioCard,
    OioSpin,
    OioRow,
    OioCol,
    OioTable,
    OioButton,
    OioEmpty
  },

  setup(props) {
    const statusField = computed(() => props.contentFields.find((a) => a.value === 'status'));
    const dataList = computed(() => {
      props.dataSource?.forEach((a) => {
        try {
          a.nodeData = JSON.parse(a.originNodeContext);
        } catch (e) {

        }
      });

      return props.dataSource;
    });
    return { statusField, dataList, ListPaginationStyle, ModelFieldType, getValue, translateValueByKey };
  }
});
</script>
<style lang="scss">
.workflow-runtime-default-gallery {
  .empty {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
  }
}
</style>

5.效果查看

【工作流】如何自定义工作流的待办任务列表

上面的vue文件中,我们将商品名称展示在了列表中,可以看到我们在vue的setup方法中将业务数据放到了工作流待办任务的nodeData属性中,我们可以根据自己的业务模型将自己需要的字段展示在页面中。需要注意的是:要展示的字段一定要出现在模型触发工作流的原始视图中。

Oinone社区 作者:nation原创文章,如若转载,请注明出处:https://doc.oinone.top/workflow/6989.html

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

(0)
nationnation
上一篇 2024年5月8日 am2:21
下一篇 2024年5月9日 pm3:56

相关推荐

  • 工作流用户待办过滤站内信

    工作流用户待办过滤站内信 全局过滤 启动工程application.yml中配置: pamirs: workflow: notify: false 个性化过滤 实现pro.shushi.pamirs.workflow.app.api.service.WorkflowMailFilterApi接口 返回true表示需要发送站内信 返回false表示不需要发送站内信 示例: import org.apache.commons.lang3.StringUtils; import pro.shushi.pamirs.message.model.PamirsMessage; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.workflow.app.api.model.WorkflowUserTask; import pro.shushi.pamirs.workflow.app.api.service.WorkflowMailFilterApi; /** * MyWorkflowMailFilterImpl * * @author yakir on 2025/02/24 16:28. */ @Fun(WorkflowMailFilterApi.FUN_NAMESPACE) public class MyWorkflowMailFilterImpl implements WorkflowMailFilterApi { @Override @Function public Boolean filter(WorkflowUserTask workflowUserTask, PamirsUser user, PamirsMessage message) { // 按用户待办过滤 workflowUserTask if (10000L == workflowUserTask.getInitiatorUid()){ return true; } // 按用户过滤 user if (1000L == user.getId()){ return true; } // 按站内信消息过滤 message if (StringUtils.contains(message.getBody(), "你好")) { return true; } return false; } }

    2025年2月24日
    00
  • 【工作流】如何在业务模型的列表中展示工作流的审批按钮

    介绍 当我们需要在业务模型的列表中展示审批的按钮时,我们可以通过自定义的方式完成扩展,这样就可以在业务数据中直接点击该动作按钮跳转到工作流待办详情页处理审批或填写任务 1.先在业务数据模型中新增userTaskList字段存放该条数据的工作流待办数据 @Model.model(DemoItem.MODEL_MODEL) @Model(displayName = "测试商品") public class DemoItem extends IdModel { @Field.one2many @Field(displayName = "工作流任务列表", store = NullableBoolEnum.FALSE, invisible = true) @Field.Relation(store = false) private List<WorkflowUserTask> userTaskList; } 2. 在业务数据的查询方法中查询当前登录用户在工作流任务中的数据 @Function.Advanced(type = FunctionTypeEnum.QUERY, displayName = "查询列表", timeout = 50000) @Function.fun(FunctionConstants.queryPage) @Function(openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API}) public Pagination<DemoItem> queryPage(Pagination<DemoItem> page, QueryWrapper<DemoItem> queryWrapper) { new DemoItem().queryPage(page, queryWrapper); List<Long> bizIds = page.getContent().stream().map(DemoItem::getId).collect(Collectors.toList()); LambdaQueryWrapper<WorkflowUserTask> userTaskWrapper = new LambdaQueryWrapper<>(); userTaskWrapper.setModel(WorkflowUserTask.MODEL_MODEL); userTaskWrapper.select(WorkflowUserTask::getId, WorkflowUserTask::getNodeDataBizId); userTaskWrapper.eq(WorkflowUserTask::getUserId, PamirsSession.getUserId()) .eq(WorkflowUserTask::getModel, DemoItem.MODEL_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> userTasks = new WorkflowUserTask().queryListByWrapper(userTaskPagination, userTaskWrapper); Map<Long, WorkflowUserTask> map = userTasks.stream().collect(Collectors.toMap(WorkflowUserTask::getNodeDataBizId, v -> v, (a, b) -> a)); page.getContent().forEach((item) -> { WorkflowUserTask workflowUserTask = map.get(item.getId()); if (workflowUserTask != null) { item.setUserTaskList(Lists.newArrayList(workflowUserTask)); } }); return page; } 3. 在界面设计器拖一个服务端动作到操作列中 4. 将工作流任务列表字段userTaskList拖到表格列中并隐藏该字段 5. 前端自定义跳转到工作流待办详情页的动作组件 import { ActionType, ActionWidget, ClickResult, executeViewAction, RuntimeViewAction, ServerActionWidget, SPI, ViewActionTarget, ViewType, Widget } from '@kunlun/dependencies'; // name为界面设计器拖出的动作名称 @SPI.ClassFactory(ActionWidget.Token({ actionType: ActionType.Server, model: 'demo.DemoItem', name: 'uiServer0358d42817d64fe7908fe48dfce084d3' })) class WorkflowJumpActionWidget extends ServerActionWidget { @Widget.Reactive() public get invisible(): boolean { if (!this.activeRecords?.[0]?.userTaskList?.[0]?.id) { return true; } return super.invisible; } protected async clickAction(): Promise<ClickResult> { const…

    2024年5月8日
    00
  • 【工作流】如何添加工作流运行时依赖

    前端 package.json中新增依赖 @kunlun/workflow,版本跟@kunlun/dependencies的填一样 src/main.ts内导入依赖 import 'reflect-metadata'; import { VueOioProvider } from '@kunlun/dependencies'; // START 导入代码放在导入@kunlun/dependencies之后 import '@kunlun/workflow/dist/kunlun-workflow.css'; import '@kunlun/workflow'; // END 导入代码放在VueOioProvider()方法执行前 VueOioProvider({ // TODO }); 后端 父pom新增依赖,下面例子中的版本号仅供参考,请根据当前框架版本正确选择版本 <properties> <pamirs.core.version>4.7.8</pamirs.core.version> <pamirs.workflow.designer.version>4.7.8</pamirs.workflow.designer.version> <pamirs.workbench.version>4.7.8</pamirs.workbench.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-core-dependencies</artifactId> <version>${pamirs.core.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <artifactId>pamirs-workflow</artifactId> <version>${pamirs.workflow.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>pro.shushi.pamirs.work.bench</groupId> <artifactId>pamirs-work-bench-core</artifactId> <version>${pamirs.workbench.version}</version> </dependency> <dependency> <groupId>pro.shushi.pamirs.work.bench</groupId> <artifactId>pamirs-work-bench-view</artifactId> <version>${pamirs.workbench.version}</version> </dependency> </dependencies> </dependencyManagement> 2.boot启动工程的pom新增依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-sql-record-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-bridge-tbschedule</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-user-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-user-view</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-auth-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-business-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-business-view</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.workflow</groupId> <artifactId>pamirs-workflow-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.work.bench</groupId> <artifactId>pamirs-work-bench-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.work.bench</groupId> <artifactId>pamirs-work-bench-view</artifactId> </dependency> 3.application.yml配置新增依赖 pamirs: boot: modules: – user – auth – business – sql_record – trigger – workflow 特别注意 工作流模块如果线上部署需要流程设计器能力,可以参考文档流程设计器部署注意事项

    2024年5月30日
    00
  • 工作流动态表单最佳实践

    需求背景 为了提高操作效率并简化流程设计过程,应对伙伴们反映的在流程设计器中,即使填写/审批流程相同,不同模型也需重新配置的问题,我们引入了“动态表单”功能。此功能旨在减少重复配置的需求,通过设置节点名称和绑定视图,便可实现审批流程相同而视图不同,从而使得相同的审批流程可以被高效重复利用。 为确保伙伴们能够更加方便的使用动态表单,我们将典型示例整合至“工作流”中。本节将结合这些示例详细阐述“动态表单”功能的应用方法。 使用主要分为两个步骤:流程设计和动态表单配置。 流程设计 触发节点配置 应用:工作流 选择模型:动态表单任务 触发场景:更新数据时 选择更新字段:触发次数 填写/审批节点配置 动态表单按钮设置为启用状态。 数据来源设置为触发节点。 动态表单函数默认有一条内置函数,选中即可。 数据保存方式、填写人等信息,同从前使用方式。 在动态表单模式下,数据权限的管理将不再由流程设计器控制,而是由用户所填写的视图进行控制。 例如,若希望用户在“一审”阶段不能修改某字段,则应在设计视图时将相关字段设为只读模式。同样,若某些信息不宜在“一审”阶段展示给客户,相应字段应在设计过程中被设置为隐藏状态。 若需在“一审”节点接收“一填”阶段的结果,数据来源设置为“一填[动态表单]”。其他配置项保持不变,按照上述说明进行设置。 若希望“二填”节点的数据由用户填写,并希望内容处于空白状态,可将数据来源设置为“触发”节点。 通过这种配置,“二填”节点的数据将不会受到“一填”和“一审”节点数据的影响。 二审节点的配置同一审,此处省略。 “终审”节点希望接收到“一审”节点的数据,可以将数据来源设置为一审。 动态表单配置 首先创建动态表单任务:工作流->动态表单任务->创建,给流程起个名字。 节点任务配置 流程名:通过下拉菜单选择,数据为动态表单任务中,创建的流程信息。 节点名称:【强制】确保与流程设计中的节点名称完全一致,否则将无法正确匹配到对应节点的视图。 模型:选定用于绑定节点视图的模型。 视图:选择视图前须先确定模型,系统将自动列出所选模型下的通过UI创建的视图供选择。 查看配置效果 在工作流模块->动态表单->动态表单任务,点击“详情”,可以看到该流程所配置的节点信息。 动态表单任务详情页 流程触发 点击“触发”按钮将使触发次数自动递增。在流程设计器中配置触发节点时,我们已设定“触发次数”字段的变化作为流程启动的条件。 触发节点配置筛选条件 通过完成上述操作,我们已成功配置动态表单。现在可以利用触发节点的筛选条件,来确定触发按钮被点击后,所启动的流程。 自定义动态表单函数 如果所提供的示例未能满足您的需求,您可以根据自身的需求,对触发条件和动态表单函数进行相应的定制与调整。 动态表单函数定义规则如下: namespace:强制为 WorkflowFunctionConstant.FUNCTION_NAMESPACE。 fun:强制以 WorkflowFunctionConstant.WORKFLOW_CUSTOM_VIEW_FUNCTION_PREFIX 为前缀。 入参说明: 参数1:节点数据,例如,配合instanceof可以判断当前是填写节点(WriteNode)还是审批节点(ApprovalNode)。 参数2:触发节点的模型数据,如果您的触发节点不确定,可以通过Map接收参数。 参数3:该节点所配置数据来源的数据。 出参说明:视图,如果出参为null,流程终止运行,错误信息提示为“流程节点执行失败,动态表单函数获取视图为空”。 @Slf4j @Component @Fun(WorkflowFunctionConstant.FUNCTION_NAMESPACE) public class DynamicFormCustom { /** * 根据动态表单任务获取视图 * * @param node 节点数据 * @param dynamicFormTask 触发节点数据 * @param dataObj 源数据 */ @Function.fun(WorkflowFunctionConstant.WORKFLOW_CUSTOM_VIEW_FUNCTION_PREFIX + "fetchDynamicFormFunction") @Function.Advanced(displayName = "[内置]获取动态表单函数") @Function(name = "fetchDynamicFormFunction") public View fetchDynamicFormFunction(Node node, DynamicFormTask dynamicFormTask, Map<String, Object> dataObj) { DynamicFormTaskNode dynamicFormTaskNode = fetchDynamicFormTaskNode(node, dynamicFormTask); if (dynamicFormTaskNode == null) { return null; } dynamicFormTaskNode.fieldQuery(DynamicFormTaskNode::getView); return dynamicFormTaskNode.getView(); } private DynamicFormTaskNode fetchDynamicFormTaskNode(Node node, DynamicFormTask dynamicFormTask) { List<DynamicFormTaskNode> dynamicFormTaskNodeList = Models.origin().queryListByWrapper(Pops.<DynamicFormTaskNode>lambdaQuery() .from(DynamicFormTaskNode.MODEL_MODEL) .eq(DynamicFormTaskNode::getNodeName, node.getNodeName()) .eq(DynamicFormTaskNode::getTaskCode, dynamicFormTask.getCode()) ); if (CollectionUtils.isEmpty(dynamicFormTaskNodeList)) { return null; } if (dynamicFormTaskNodeList.size() > 1) { log.error("工作流动态获取表单函数视图匹配多个,{}", JsonUtils.toJSONString(dynamicFormTaskNodeList)); } return dynamicFormTaskNodeList.get(0); } }

    2024年8月22日
    00
  • 【工作流】流程扩展自定义函数示例代码汇总

    目录 1. 流程节点审批人函数2. 审批开始前执行函数3. 待办操作提交后执行函数4. 审批操作数据函数 1. 流程节点审批人函数 包含转交、抄送、加签、填写、通知人自定义函数当平台默认提供的审批人选择无法满足个性化的业务需求时,我们可以通过自定义函数处理审批人的生成逻辑 1.1 编写自定义审批人函数 @Function(openLevel = {FunctionOpenEnum.API}) @Function.Advanced(type = FunctionTypeEnum.QUERY, displayName = "报销单-证明人-审批", category = CUSTOM_DESIGNER) public List<NodePerson> bizZmrApprovePerson(List<NodePerson> nodePersonList, NodeModel nodeModel, WorkflowContext workflowContext) { List<NodePerson> newNodePersonList = new ArrayList<>(); String nodeModelId = nodeModel.getId(); Object nodeData = workflowContext.get(nodeModelId); BuissModel inputBuissModel = JsonUtils.parseObject(JsonUtils.toJSONString(nodeData), BUISSMODEL_TR); BuissModel buissModel = new BuissModel().setId(inputBuissModel.getId()).queryById(); buissModel.fieldQuery(BuissModel::getZmEmployee); BxEmployee zmEmployee = buissModel.getZmEmployee(); if (zmEmployee == null) { log.error("报销单ID:{},名称:{}, 获取证明人为空", buissModel.getId(), buissModel.getName()); return newNodePersonList; } NodePersonUser personUser = new NodePersonUser(); List<NodePersonUser> nodePersonUsers = new ArrayList<>(); NodePerson person = new NodePerson(); person.setId(zmEmployee.getBindingUserId() + ""); person.setType(NodePersonTypeEnum.USER); personUser.setUserId(zmEmployee.getBindingUserId()); nodePersonUsers.add(personUser); person.setNodePersonUsers(nodePersonUsers); newNodePersonList.add(person); return newNodePersonList; } 1.2 流程设计器的审批节点设置自定义函数 2.审批开始前执行函数 使用场景:在流程执行到审批或填写节点任务初始化后,任务尚未开始,需要在初始化任务做一些自定义逻辑处理时,使用该扩展执行时间:执行节点是在审批或填写待办任务初始化之后,审批或填写结果执行之前,执行该扩展 /** * 审批节点初始化完成,执行前置函数 * @param approvalNode * @param context * @param taskInstance */ @Function(name = "approvalCustomStartFun",openLevel = FunctionOpenEnum.API) @Function.Advanced(type= FunctionTypeEnum.QUERY,displayName = "审批执行前置处理",category = FunctionCategoryEnum.CUSTOM_DESIGNER ) public void approvalCustomStartFun(ApprovalNode approvalNode, WorkflowContext context, WorkflowTaskInstance taskInstance) { // TODO: 2024/2/23 可以根据结果自己处理业务逻辑 } 3. 待办操作提交后执行函数 使用场景:在审批或填写的待办任务在操作任务时,需要额外执行一些逻辑,比如当前人提交操作以后需要更新更当前人操作相关的数据库记录,执行时间:执行节点是在保存待办任务之后,异步执行审批或填写结果之前,执行该扩展 /** * 转交操作后置函数,再流程设计器中审批和填写节点中 扩展设置-填写操作提交后执行函数选择 * @param userTask 用户待办记录 * @return 待办记录 */ @Function(name = "transformOrgSelectEndFun",openLevel = FunctionOpenEnum.API) @Function.Advanced(type= FunctionTypeEnum.QUERY,displayName = "转交操作后置函数",category = FunctionCategoryEnum.CUSTOM_DESIGNER ) public WorkflowUserTask transformOrgSelectEndFun(WorkflowUserTask userTask) { //可针对操作类型进行过滤 // 转交操作后 if (!WorkflowUserTaskOperateTypeEnum.APPROVE_TRANGER.equals(userTask.getOperateType())) { return…

    2023年12月4日
    00

Leave a Reply

登录后才能评论