Skip to content

工作组件

引擎提供了工作组件,所有工作办理都使用该组件。它不仅简化了部分开发工作,同时也为用户提供了一致的操作体验。

概览

如下图所示,组件包含标题区、表单区、办理意见区、流转记录区。

create

标题区

这里显示了流程标题、当前节点、版本号、快捷导航和操作按钮。

点击快捷导航可以快速滚动到对应位置,增加了操作便利性,尤其是在表单内容较长时。

表单区

表单区是用户操作的主要区域,组件负责加载展示开发人员实现的业务表单。工作组件提供了与业务组件的交互机制。

办理意见

工作组件提供了办理意见输入框,并在退回工作等操作时进行必填较验。业务提交时应主动获取办理意见。

提示

开发人员可以根据需要隐藏办理意见区,具体请查看 config 方法。

流转记录

这里显示了每个节点的办理记录,还包含一些工作相关的系统信息,如转发记录、操作备注等。

deal rec

提示

为了减轻对用户注意力的干扰,流转记录默认开启“简洁模式”,不显示系统消息、操作备注。需要时用户可以点击退出简洁模式,查看更多信息。

提示

开发人员可以设置默认不开启简洁模式,在 env 配置文件添加 VUE_APP_WORK_ENTRY_FOCUS_MODE = false 即可。

流程图

点击快捷导航的“流程图”,可以打开流程图面板,展示完整流程走向。在办理工作状态下,会以不同颜色标记已经过节点和当前节点。

graph

刷新策略

工作组件的刷新策略经过了特别地设计——用户在打开的多个标签页之间切换时,工作组件不会刷新,防止用户未保存的内容丢失;从其它链接导航至工作页面时,工作组件会刷新,以显示最新内容。

交互支持

工作组件要加载展示业务组件,业务组件需要控制按钮、响应操作,两者不可避免需要交互操作。工作组件提供了 prop方法支持。

prop

工作组件加载业务组件时,可以传入特定参数,业务组件可根据需要声明相应的prop。

名称类型说明
task-idString任务编号
work-idString工作编号
node-codeString节点编码
versionNumber流程版本号
readonlyBoolean是否只读模式
modeString访问模式。取值:create/view/read

注意

业务组件声明的 prop 名称必须与上表中的名称一致(camelCase)。

方法

工作组件提供的方法暴露在 entry 对象中,业务组件可以通过 $parent 访问,也可以通过 inject 注入(推荐)。

entry.reload

  • 说明:刷新页面
  • 参数:无
  • 返回:无

entry.getData

  • 说明:获取部分工作数据
  • 参数:无
  • 返回:
    • {Object}
      • {String} taskId 任务编号
      • {String} title 工作标题
      • {String} dealMsg 办理意见
      • {String} rejectTo 用户指定的退回节点。未指定时为空。

entry.config

  • 说明:配置工作组件
  • 参数:
    • {Object} 配置对象
      • {Boolean} enableComment 是否显示办理意见,默认为 true
      • {Array} buttons 按钮配置
        • {String} name 按钮标识
        • {String} text 按钮文字
        • {String} type 按钮颜色
        • {String} icon 按钮图标。自定义按钮默认为 el-icon-menu。
        • {Boolean} show 是否显示。自定义按钮默认为 true。
        • {Boolean} top 是否显示为顶层按钮,自定义按钮默认在“更多”菜单中显示。
        • {Function([resolve, reject])} handler 点击事件处理方法,是否有参数传入取决于下述 promise 配置。
        • {Boolean} promise 处理方法是否返回 Promise 对象,默认 false 。 如果返回 Promise 则工作组件可以根据它确定是否处理结束,然后执行后续逻辑;否则会传入resolve、reject参数给处理方法,由开发人员手动调用。
        • {Boolean} commentRequired 办理意见是否必填。退回默认为 true, 其它默认为 false。
  • 返回:无

entry.error

  • 说明:进入错误模式。隐藏其它内容,仅显示错误消息。
  • 参数:
    • {String} msg 错误消息
  • 返回:无

entry.navigateTo

  • 说明:滚动或切换到指定视图。
  • 参数:
    • {String} view 视图名称。可选值:form(流程表单)、comment(办理意见)、record(流转记录)、graph(流程图)
  • 返回:无

entry.toggleAllBtnsState

  • 说明:禁用或恢复所有按钮。
  • 参数:
    • {String} state 状态。可选值:false(禁用)、true(恢复)
  • 返回:无

提示

点击标题区任意操作按钮发起网络请求时,工作组件会禁用所有按钮,防止用户重复操作。 此时开发人员无需调用 toggleAllBtnsState 方法。

操作按钮

内置按钮

组件内置了一些常用操作按钮,并附带部分通用逻辑。开发人员可以根据需要使用,具体如下表所示。

按钮标识说明默认显示附带逻辑
提交submit主按钮,用于提交推进工作完成后跳转查看模式
保存save用于保存草稿🔲完成后跳转办理模式
退回reject用于退回流程🔲确认提示,完成后跳转查看模式
删除del删除工作与任务🔲确认提示,删除工作与任务。
支持自定义
刷新refresh刷新页面,“更多”菜单中刷新

自定义按钮

组件还支持配置自定义按钮,以应对更多业务需求。只需要在业务组件中调用 entry.config 方法即可,示例如下。

javascript
export default {
  inject: ["entry"],
  // 其它内容省略
  methods: {
    submitForm(resolve, reject) {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return;
        }

        // 获取并设置办理消息
        this.form.dealMsg = this.entry.getData().dealMsg;
        api.add(this.form).then(resolve).catch(reject);
      });
    },
    resetForm(resolve, reject) {
      this.form = this.initForm();
      resolve();
    },
    saveForm(resolve, reject) {
      // 获取并设置办理消息
      this.form.dealMsg = this.entry.getData().dealMsg;
      api.save(this.form).then(resolve).catch(reject);
    },
  },
  mounted() {
    this.entry.config({
      buttons: [
        {
          name: "submit",
          handler: this.submitForm,
        },
        {
          name: "save",
          show: true,
          handler: this.saveForm,
        },
        {
          name: "reset",
          top: true,
          text: "重置",
          handler: this.resetForm,
        },
      ],
    });
  },
};

在上例中启用了内置的“保存”按钮,并添加了一个“重置”按钮,最终效果如下图所示。

btn

注意

除刷新按钮外,其它按钮仅能在办理工作时显示,查看工作(例如查看已办、抄送)时不显示。

事件处理器

工作组件仅支持按钮的点击事件处理。用户点击按钮时,通常会触发异步请求,为了确保在请求结束时进行附加逻辑,工作组件需要知道请求何时结束。这里采用了常用的 Promise 方式,具体分为参数模式与返回模式。

提示

为内置按钮或自定义按钮编写事件处理方法时,无需考虑按钮 loading 状态控制。工作组件会在按钮点击时开启 loading, 处理完成时关闭。

参数模式

在上面的示例代码中,处理方法接收两个参数:resolve 和 reject。熟悉 Promise 的开发人员马上就能领会——在异步业务逻辑成功时调用 resolve,其它情况调用 reject。

javascript
doBiz(resolve, reject) {
  api.doBiz()
    .then((res) => {
      if(res.code == 0) {
        resolve(res.data);
      }else {
        reject(res);
      }
    })
    .catch((err) => {
      reject(err);
    })
}

为了简化业务组件代码,工作组件内部支持检查res.code,为 0 时才继续后续逻辑。因此上例可以作如下修改。

javascript
doBiz(resolve, reject) {
  api.doBiz()
    .then((res) => {
      resolve(res);
    })
    .catch((err) => {
      reject(err);
    })
}

此时匿名函数也可以去掉,最终代码如下。

javascript
doBiz(resolve, reject) {
  api.doBiz().then(resolve).catch(reject);
}

注意

由于 resolve 方法只接收一个参数,上面的写法实际上会忽略 Axios 传入的其它参数。如果关注其它参数,则仍需要使用匿名函数的形式。

返回模式(不推荐

工作组件还支持返回 Promise 对象的事件处理器,这样可以进一步简化事件处理器。使用此模式需要在配置按钮时开启promise参数,示例如下。

javascript
export default {
  inject: ["entry"],
  // 其它内容省略
  methods: {
    submitForm() {
      return this.$refs.form
        .validate()
        .then(() => {
          // 获取并设置办理消息
          this.form.dealMsg = this.entry.getData().dealMsg;
          return api.add(this.form);
        })
    },
    resetForm() {
      this.form = this.initForm();
      return Promise.resolve();
    },
    saveForm() {
      // 获取并设置办理消息
      this.form.dealMsg = this.entry.getData().dealMsg;
      return api.save(this.form);
    },
  },
  mounted() {
    this.entry.config({
      buttons: [
        {
          name: "submit",
          handler: this.submitForm,
          promise: true,
        },
        {
          name: "save",
          show: true,
          handler: this.saveForm,
          promise: true,
        },
        {
          name: "reset",
          top: true,
          text: "重置",
          handler: this.resetForm,
          promise: true,
        },
      ],
    });
  },
}

提示

上例中通过 promise 参数开启了返回模式,处理方法取消了 resolve、reject 参数,添加了 return 声明。

Axios 请求本身会返回 Promise,因此可以直接将其作为返回值,如 Line 11、21 所示。 否则需要手动创建 Promise 对象,如 Line 16 所示。

注意

表单验证需要修改为 Promise 模式(Line 6),且不能调用 catch 方法,否则会引起后续逻辑的意外执行。

业务开发

全局注册 重要

业务组件的加载和切换基于 Vue 的动态组件实现,因此业务组件必须注册为全局组件。

javascript
// main.js
import Vue from 'vue'
Vue.component('wf-leave-start', () => import('@/pages/foo-biz/Start.vue'))

注意

节点配置中的“页面视图”即为此处声明的组件名。

工作标题

标题对于流程工作有重要作用,它会出现在待办事项、消息提醒、办理界面等地方,方便用户快速了解当前工作内容。同时,工作标题也往往与业务紧密相关,这样才能精确体现出实际工作内容。

因此在发起流程时,工作标题需要由业务侧生成并传递给引擎。在回显表单时,标题由工作组件传递给业务组件。

提示

建议业务表不再包含标题字段。如果业务表包含标题,则需要考虑与工作标题同步。

办理意见

由于工作组件内置了办理意见输入功能,业务表单在提交时必须主动获取用户输入的办理意见,并传递给引擎。 请调用 entry.getData 方法获取。

注意

工作组件仅在退回工作时要求必须填写办理意见(未隐藏办理意见区时),其它情况由开发人员自行控制。

发起流程

发起流程(含草稿)成功后,必须传递workId给工作组件。这样工作组件才可以顺利切换到查看模式或待办模式。

javascript
submitForm(resolve, reject) {
  this.$refs.form.validate((valid) => {
    if (!valid) {
      return;
    }

    // 获取并设置办理消息
    this.form.dealMsg = this.entry.getData().dealMsg;
    api.add(this.form).then((res) => {
      // res.data 必须为包含 workId 的对象,或者 workId 本身。
    }).catch(reject);
  });
},

加载表单

除发起流程外,其它情况下业务表单都需要回显用户已填写的数据。加载表单数据时需要使用 taskId 参数, 它由工作组件通过 prop 传入。如果要回显标题,则需要从工作数据中获取。

javascript
export default {
  inject: ["entry"],
  props: {
    version: Number,
    taskId: String,
  },
  data() {
    return {
      loading: false,
      form: this.initForm(),
    };
  },
  methods: {
    loadForm() {
      this.loading = true;
      api
        .info(this.taskId)
        .then((res) => {
          if (res && res.code == 0) {
            res.body.title = this.entry.getData().title;// 设置为工作标题
            this.form = res.body;
          }
        })
        .catch(() => {
          this.$message.error("获取表单数据失败");
        })
        .finally(() => {
          this.loading = false;
        });
    },
  },
  mounted() {
    if (this.taskId) {
      this.loadForm();
    }
  },

提示

上例中声明了 taskId prop,用来接收任务编号,后台使用它来获取表单数据。 同时还声明了 version prop,这样可以根据版本号实现不同版本的业务逻辑。

后台流程为:接收 taskId -> 调用流程引擎(getBizInfo) -> 引擎校验权限 -> 返回业务 id -> 业务侧根据 id 返回表单数据。

办理工作

办理工作(例如通过、退回)时需要从工作组件获取“任务编号(taskId)”与“办理意见(dealMsg)”。

javascript
submitForm(resolve, reject) {
  const { taskId, dealMsg } = this.entry.getData();
  Object.assign(this.form, { taskId, dealMsg });
  api.judge(this.form).then(resolve).catch(reject);
}

提示

后台流程为:接收 taskId -> 调用流程引擎(getBizInfo) -> 引擎校验权限 -> 返回业务 id -> 业务侧根据 id 执行逻辑 -> 调用引擎推进工作。

此时对后台返回值没有要求。

查看工作

当用户查看已办工作或抄送工作时,业务表单须为不可编辑状态,此时业务组件进入只读模式。 工作组件通过 readonly prop 指示业务组件是否应该进入只读模式。因此在实际开发中,业务组件必须声明并响应 readonly prop。

js
export default {
  inject: ["entry"],
  props: {
    readonly: Boolean,
    version: Number,
    taskId: String,
  },
  // 其它内容省略
}
html
<template>
  <el-form
    ref="form"
    :model="form"
    :disabled="readonly"
  >
    <!-- 其它内容省略 -->
  </el-form>
</template>

在实际开发中,出于视觉效果或自定义组件原因,可能无法做到在同一个组件中直接切换编辑模式与只读模式。这时需要分别开发编辑视图与只读视图,然后将它们放在一个包裹组件中。下面是一个可能的例子。

html
<template>
  <div>
    <child-readonly v-if="readonly" v-bind="$attrs" />
    <child-normal v-else v-bind="$attrs" />
  </div>
</template>
<script>
  // 子组件引入省略
  export default {
    inheritAttrs: false
    props: {
      readonly: Boolean,
    }
  }
</script>

提示

例子中通过 readonly prop 切换子组件显示。同时通过 inheritAttrs 和 $attrs,将工作组件传递的 prop 转交给子组件。

子组件开发不受任何影响,仍然通过声明 props 与 inject 与工作组件交互。

外部调用

本人工作

工作组件支持从外部传入参数,显示指定工作的信息。只需跳转至如下路由即可。

访问路由

/work/entry/view/{by}/{data}?nodeCode={node}

路由参数

参数说明取值
by查询方式work:按工作编号查询
data查询数据-
node节点编码可选。不传则默认为用户最新任务的节点。

提示

此时用户可以查看或办理自己参与的工作任务,无法查看未参与的工作。

他人工作 .NET 3.2.1+ Java 1.8.0+

默认情况下,工作组件在加载工作时,会校验当前用户是否是该工作的参与人(包括办理、抄送)。 如果不是,则会拒绝返回工作信息,保证数据安全。

但在一些特定业务场景下,需要根据业务数据之间的联系查看工作。比如上级查看下级工作,从父工单查看子工单等。 这时就不适合根据操作人判断权限,因此工作组件提供了查看他人工作的 read 模式。

需要使用 read 模式展示工作信息时,跳转至如下路由即可。

访问路由

/work/entry/read/{by}/{data}

路由参数

参数说明取值
by查询方式work:按工作编号查询; biz:按业务编号查询
data查询数据-

下面给出一个示例。

javascript
this.$router.push(`/work/entry/read/biz/${bizId}`);

提示

read 模式仅能查看工作,不支持办理。

查看工作时会展示最新任务节点对应的表单,因此要查看已结束的工作必须在结束节点配置页面视图。

注意

为避免数据安全问题,业务侧应验证相关数据访问权限。