工时拦截
要求
适用环境
- 私有部署
ONES 版本
v6.3.0+
依赖包版本
{
"dependencies": {
"@ones-op/fetch": "0.46.12+",
"@ones-open/node-host": "0.4.2+",
"@ones/cli-plugin": "1.29.0+",
"@ones/cli-plugin-template": "1.10.8+",
"@ones-op/sdk": "0.46.7+"
}
}
特别地,还需要在插件 backend 也安装 @ones-open/node-host
cd backend/
npm install @ones-open/node-host@0.4.3+
能力概述
本文档提供工时拦截能力,客户可通过这个功能对工时的操作进行拦截,该能力为组织级别能力。在部分场景下,会出现同一数据多次收到多次拦截,所以使用该能力需保持行为的幂等性,保持行为的幂等性意味着即使同一拦截请求被多次触发,其效果应该如同只被触发一次一样,不会导致重复的数据处理或异常情况
工时验证器与插件
插件体系内,如何使用工时验证器呢?
在插件的 plugin.yaml 中添加工时验证器配置如下:
extension:
- manhourValidator: # 使用工时验证器功能扩展
provider: manhour # 字节数必须是8,后续不允许修改,谨慎定义。命名方式使用字母和数字组成的,不要使用其他特殊字符。
funcs:
- name: validate # 使用该能力必须注册,命名不能改
url: validate # 与插件内func名称一致
工时验证器与插件生命周期
工时验证器功能与插件生命周期操作存在绑定关系,如下表所示:
| 生命周期操作 | 私有部署 | SaaS |
|---|---|---|
| 安装 | 组织级别:注册 | 实例级别:注册 组织级别:注册 |
| 卸载 | 组织级别:注销 | 实例级别:注销 组织级别:注销 |
工时验证器实现
后端实现
- 创建文件
backend/src/manhour-validator.ts:
import { FetchAsAdmin } from '@ones-op/fetch'
import { Logger } from '@ones-op/node-logger'
import type { PluginRequest, PluginResponse } from '@ones-op/node-types'
export async function validate(body: any): Promise<PluginResponse> {
Logger.info('body', body)
const haveError = true
if (haveError) {
return {
statusCode: 200,
body: {
error: {
reason: "这是一个错误提示", // 错误提示
level: "error" //错误级别
},
},
}
}
return {
statusCode: 200
}
}
请求体说明
插件注册相关能力,并实现对应方法后,会收到以下信息:
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| teamUUID | string | 团队uuid | |
| userUUID | string | 请求用户uuid | |
| req | ManhourRequest | 请求的工时相关信息 |
ManhourRequest 结构
type ManhourRequest struct {
Type string `json:"type"` // 预估、登记、剩余工时分类
Action string `json:"action"` // add、update、delete
Mode string `json:"mode"`
Options manhourModel.Options `json:"options"`
ManhourInfo []*ManhourInfo `json:"manhour_info"` // 工时的详细信息填充
}
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| type | string | 工时分类 | 登记 "recorded" 预估 "estimated" 剩余 "remaining" 以前端页面当前操作传入的工时为准 |
| action | string | 工时操作行为 | add、update、delete 这个信息有部分场景在add和update上不够准确,因为目前的业务架构不足以完全区分,插件尽量不要依赖该字段来区分是添加还是更新操作 |
| mode | string | 工时模式 | 简单模式 "simple" 汇总模式 "detailed" |
| options | Options | 操作场景 | 任务导入 "import_task" 其他场景该字段为空 |
| manhour_info | []*ManhourInfo | 数组类型,详情字段见下面表格 |
ManhourInfo 结构
type ManhourInfo struct {
task *Task // 任务的具体信息
assess_manhour *AssessManhour // 预估工时的具体信息
remaining_manhour *RemainingHour // 剩余工时的具体信息
record_manhour *RecordManhour // 登记工时的具体信息
}
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| task | *Task | 任务的具体信息 | 详见 Task 结构说明 |
| assess_manhour | *AssessManhour | 预估工时的具体信息 | 详见 AssessManhour 结构说明 |
| remaining_manhour | *RemainingHour | 剩余工时的具体信息 | 详见 RemainingHour 结构说明 |
| record_manhour | *RecordManhour | 登记工时的具体信息 | 详见 RecordManhour 结构说明 |
Task 结构
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| UUID | string | 任务UUID | |
| TeamUUID | string | 团队UUID | |
| Owner | string | 任务所有者 | |
| Assign | string | 任务负责人 | |
| ProjectUUID | string | 项目UUID | |
| IssueTypeUUID | string | 工作项类型UUID | |
| ParentUUID | string | 父任务UUID | |
| SubIssueTypeUUID | string | 子工作项类型UUID | |
| IsCreateTask | bool | 是否新建任务 |
AssessManhour 结构
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| UUID | string | 预估工时UUID | |
| From | int64 | 开始时间 | |
| To | int64 | 结束时间 | |
| HoursFormat | string | 工时格式 | |
| IncludeNonWorkingDay | int64 | 是否包含非工作日 | |
| Hours | float64 | 工时数 | |
| Owner | string | 工时所有者 | |
| StartTime | float64 | 开始时间 | 汇总模式-修改预估工时会填 |
RemainingHour 结构
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| UUID | string | 剩余工时UUID | |
| Hours | float64 | 剩余工时数 | |
| Owner | string | 工时所有者 |
RecordManhour 结构
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| UUID | string | 登记工时UUID | |
| StartTime | float64 | 开始时间 | |
| Description | string | 工时描述 | |
| Hours | float64 | 工时数 | |
| Owner | string | 工时所有者 |
Options 结构
type Options struct {
// 用 scene 来判断是否需要权限校验
Scene string `json:"scene"`
}
最佳实践
- 保持行为的幂等性:即使同一拦截请求被多次触发,其效果应该如同只被触发一次一样,不会导致重复的数据处理或异常情况。
- 错误处理:当方法的 error 不等于空的时候,前端工时的操作行为就会失败,错误需要在真正需要中断的时候返回。
- 错误码结构:
//服务内部异常可以直接返回错误。
error: {
reason: "这是一个错误提示", // 错误提示
level: "error" //错误级别
}