Skip to content

工作列表

引擎提供了配套的工作查询功能,支持用户以多种方式筛选个人工作。同时支持跳转工作详情,查看或办理工作。

概览

用户可以根据工作创建时间、工作状态、办理状态、流程、标题等条件筛选工作,查询结果包含创建人、创建时间、工作、流程等信息。

work list

自定义扩展

可以看到,默认的查询条件与结果仅包含引擎相关内容(流程、工作等),不包含业务相关数据。而在实际使用中,往往期望根据某些业务字段搜索工作,例如工单、客户、流水号等。为此引擎提供了工作查询扩展支持。

原理与限制

要想使用业务字段查询工作,必须将其与工作信息关联。但业务表并不唯一,无法简单关联。

引擎利用了 PostgreSQL 的表继承功能——把需要作为查询条件或结果的业务字段抽取至统一的基础表,然后使用基础表与工作信息关联,这样就解决了有多个业务表需要与工作信息关联的问题。

由于要关联查询,基础表必须包含 bizId 信息,通常为主键 id

提示

关于 bizId 的更多信息,请查看创建工作说明。

后端实现

与普通查询功能类似,后端实现同样需要实体定义、逻辑实现、服务注册几个步骤。但需要继承引擎提供的一些基础类。下面结合示例分别介绍。

实体 Entity

业务基础表对应的实体类,需继承 WorkBizEntityBase。

java
@TableName(value = "wf_work_biz_base")
public class WorkBizBase extends WorkBizEntityBase {
    private String orderNumber;
    private String customerCode;
    // 省略 get/set 方法
}

入参 DTO

查询入参类,需继承 WorkSearchDto。由于入参类型无法预知,也就不能使用控制器的模型绑定功能,需要开发人员实现参数绑定与验证。

java
public class BizSearchDto extends WorkSearchDto {
    private String orderNumber;
    private String customerCode;
    // 省略 get/set 方法

    @Override
    public void inflate(Map<String, String> requestParams) {
        // 填充参数
        this.orderNumber = requestParams.getOrDefault("orderNumber", null);
        this.customerCode = requestParams.getOrDefault("customerCode", null);
    }

    @Override
    public void validate() {
        // 模型验证,按需实现
    }

出参 VO

查询结果类,需继承 WorkSearchVo。

java
public class BizSearchVo extends WorkSearchVo {
    private String orderNumber;
    private String customerCode;
    // 省略 get/set 方法
}

服务 Service

查询服务类,需继承泛型类 AbstractUserWorkSearcher。类型参数分别为上面定义的 Entity、DTO、VO 类。

开发人员需要重写 customQuery 方法,指定业务相关的查询条件与结果字段即可,查询主体已在基类实现。

java
@Service
@Primary
public class SimUserWorkSearcher extends AbstractUserWorkSearcher<WorkBizBase, BizSearchDto, BizSearchVo> {
    @Override
    protected void customQuery(MPJLambdaWrapper<?> condition, BizSearchDto dto) {
        condition.select("b.order_number", BizSearchVo::getOrderNumber)
                .select("b.customer_code", BizSearchVo::getCustomerCode)
                .eq(StringUtils.isNotEmpty(dto.getOrderNumber()), "b.customer_code", dto.getOrderNumber())
                .eq(StringUtils.isNotEmpty(dto.getCustomerCode()), "b.customer_code", dto.getCustomerCode());
    }
}

注意

由于 ORM 框架限制,业务字段只能通过字符串方式指定,且必须使用表别名 b

注意

为了使自定义服务生效,除了声明为 Service 外,还需要声明为 Primary。

至此就完成了后端扩展,可以通过请求 /api/wf/works/mine 进行测试验证。

提示

此时 swagger 无法直接使用,需要 postman 等其它工具发送自定义参数。

.NET 差异

  1. 服务实现

由于 ORM 框架限制,业务条件与结果需要分别指定。

csharp
public class TestUserWorkSearcher : AbstractUserWorkSearcher<TestWorkBizEntity, TestWorkBizDto, TestWorkBizVo>
{
    protected override Expression<Func<TestWorkBizEntity, bool>> GetQueryCondition(TestWorkBizDto dto)
    {
        return new OptionalExpressionBuilder<Func<TestWorkBizEntity, bool>>()
            .WhereIfNotNullOrEmpty(dto.CustomerCode, t => t.CustomerCode == dto.CustomerCode)
            .Build();
    }

    protected override Expression<Func<TestWorkBizEntity, TestWorkBizVo>> GetQuerySelector()
    {
        return t => new TestWorkBizVo
        {
            CustomerCode = t.CustomerCode,
            ProductCode = t.ProductCode
        };
    }
}
  1. 服务注册

虽然在服务类上直接声明 [Service] 也可以达到目的——在 .NET 中获取指定服务时,如果存在多个匹配则取最后一次注册的服务,而开发人员声明的服务总是晚于基础框架注册的默认服务。

不过为了避免开发人员后续声明多个服务时出现顺序问题,强烈建议手动注册工作查询服务,不使用声明式注册。框架使用 TryAdd 方法注册默认查询服务,因此开发人员应在调用框架的注册服务方法前注册自定义查询服务。

csharp
// Startup.cs
public override void ConfigureServices(IServiceCollection services)
{
    // 注册查询服务
    services.AddScoped<IUserWorkSearcher, TestUserWorkSearcher>();
    // 调用框架注册服务方法
    base.ConfigureServices(services);
    // 省略其它内容
}

前端实现

引擎提供了前端组件,供重写查询页面时使用。组件路径为 @frame/pages/work/list/components/WorkSearchList.vue

属性

名称类型说明取值
before-query-fnfunction(query)查询前调用,供写入查询参数默认为null
reset-data-fnfunction重置查询时调用,供清空查询条件默认为null

插槽

名称类别说明
custom-condition查询条件在默认查询条件之前(日期条件之后)
custom-condition-back查询条件在默认查询条件之后
custom-table-column查询结果在“操作列”之前,内容为 el-table-column。

示例

下面给出一个简单示例。

html
<template>
  <work-search-list :before-query-fn="onQuery" :reset-data-fn="onReset">
    <!-- 自定义筛选条件 -->
    <template #custom-condition>
      <el-form-item label="客户代码:">
        <el-input
          v-model="query.customerCode"
          placeholder="请输入"
          clearable
        ></el-input>
      </el-form-item>
    </template>
    <!-- 自定义列 -->
    <template #custom-table-column>
      <el-table-column
        prop="customerCode"
        align="left"
        label="客户代码"
      ></el-table-column>
    </template>
  </work-search-list>
</template>
javascript
import WorkSearchList from "@frame/pages/work/list/components/WorkSearchList.vue";
export default {
  name: "work-list",
  components: {
    WorkSearchList,
  },
  data() {
    return {
      query: this.initData(),
    };
  },
  methods: {
    initData() {
      return {
        customerCode: "",
      };
    },
    onQuery(data) {
      Object.assign(data, this.query);
    },
    onReset() {
      this.query = this.initData();
    },
  },
};

系统菜单

实现新查询页面后,需要将“我的工作”菜单修改为新页面路径。同时,工作台“更多”按钮链接也需要修改。