bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
292 lines
9.5 KiB
Go
292 lines
9.5 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package okr
|
|
|
|
// RespAlignment 对齐关系
|
|
type RespAlignment struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
UpdateTime string `json:"update_time"`
|
|
FromOwner RespOwner `json:"from_owner"`
|
|
ToOwner RespOwner `json:"to_owner"`
|
|
FromEntityType string `json:"from_entity_type"`
|
|
FromEntityID string `json:"from_entity_id"`
|
|
ToEntityType string `json:"to_entity_type"`
|
|
ToEntityID string `json:"to_entity_id"`
|
|
}
|
|
|
|
// RespCategory 分类
|
|
type RespCategory struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
UpdateTime string `json:"update_time"`
|
|
CategoryType string `json:"category_type"`
|
|
Enabled *bool `json:"enabled,omitempty"`
|
|
Color *string `json:"color,omitempty"`
|
|
Name CategoryName `json:"name"`
|
|
}
|
|
|
|
// RespCycle 周期
|
|
type RespCycle struct {
|
|
ID string `json:"id"`
|
|
StartTime string `json:"start_time"`
|
|
EndTime string `json:"end_time"`
|
|
CycleStatus *string `json:"cycle_status,omitempty"`
|
|
}
|
|
|
|
// RespIndicator 指标
|
|
type RespIndicator struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
UpdateTime string `json:"update_time"`
|
|
Owner RespOwner `json:"owner"`
|
|
EntityType *string `json:"entity_type,omitempty"`
|
|
EntityID *string `json:"entity_id,omitempty"`
|
|
IndicatorStatus *string `json:"indicator_status,omitempty"`
|
|
StatusCalculateType *string `json:"status_calculate_type,omitempty"`
|
|
StartValue *float64 `json:"start_value,omitempty"`
|
|
TargetValue *float64 `json:"target_value,omitempty"`
|
|
CurrentValue *float64 `json:"current_value,omitempty"`
|
|
CurrentValueCalculateType *string `json:"current_value_calculate_type,omitempty"`
|
|
Unit *RespIndicatorUnit `json:"unit,omitempty"`
|
|
}
|
|
|
|
// RespIndicatorUnit 指标单位
|
|
type RespIndicatorUnit struct {
|
|
UnitType *string `json:"unit_type,omitempty"`
|
|
UnitValue *string `json:"unit_value,omitempty"`
|
|
}
|
|
|
|
// RespKeyResult 关键结果
|
|
type RespKeyResult struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
UpdateTime string `json:"update_time"`
|
|
Owner RespOwner `json:"owner"`
|
|
ObjectiveID string `json:"objective_id"`
|
|
Position *int32 `json:"position,omitempty"`
|
|
Content *string `json:"content,omitempty"`
|
|
Score *float64 `json:"score,omitempty"`
|
|
Weight *float64 `json:"weight,omitempty"`
|
|
Deadline *string `json:"deadline,omitempty"`
|
|
}
|
|
|
|
// RespObjective 目标
|
|
type RespObjective struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
UpdateTime string `json:"update_time"`
|
|
Owner RespOwner `json:"owner"`
|
|
CycleID string `json:"cycle_id"`
|
|
Position *int32 `json:"position,omitempty"`
|
|
Content *string `json:"content,omitempty"`
|
|
Score *float64 `json:"score,omitempty"`
|
|
Notes *string `json:"notes,omitempty"`
|
|
Weight *float64 `json:"weight,omitempty"`
|
|
Deadline *string `json:"deadline,omitempty"`
|
|
CategoryID *string `json:"category_id,omitempty"`
|
|
KeyResults []RespKeyResult `json:"key_results,omitempty"`
|
|
}
|
|
|
|
// RespOwner OKR 所有者
|
|
type RespOwner struct {
|
|
OwnerType string `json:"owner_type"`
|
|
UserID *string `json:"user_id,omitempty"`
|
|
}
|
|
|
|
// ProgressStatus 进展状态
|
|
type ProgressStatus int32
|
|
|
|
const (
|
|
ProgressStatusNormal ProgressStatus = 0 // 正常
|
|
ProgressStatusOverdue ProgressStatus = 1 // 逾期
|
|
ProgressStatusDone ProgressStatus = 2 // 已完成
|
|
)
|
|
|
|
// ParseProgressStatus parses a progress status string into ProgressStatus.
|
|
// Accepts "normal", "overdue", "done" or their numeric values "0", "1", "2".
|
|
func ParseProgressStatus(s string) (ProgressStatus, bool) {
|
|
switch s {
|
|
case "normal", "0":
|
|
return ProgressStatusNormal, true
|
|
case "overdue", "1":
|
|
return ProgressStatusOverdue, true
|
|
case "done", "2":
|
|
return ProgressStatusDone, true
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|
|
|
|
// String returns a human-readable name for ProgressStatus.
|
|
func (s ProgressStatus) String() string {
|
|
switch s {
|
|
case ProgressStatusNormal:
|
|
return "normal"
|
|
case ProgressStatusOverdue:
|
|
return "overdue"
|
|
case ProgressStatusDone:
|
|
return "done"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// RespProgressRate 进度率(面向用户的响应格式,Status 为可读字符串)
|
|
type RespProgressRate struct {
|
|
Percent *float64 `json:"percent,omitempty"`
|
|
Status *string `json:"status,omitempty"`
|
|
}
|
|
|
|
// RespProgress 进展记录
|
|
type RespProgress struct {
|
|
ID string `json:"progress_id"`
|
|
ModifyTime string `json:"modify_time"`
|
|
CreateTime *string `json:"create_time,omitempty"`
|
|
Content *string `json:"content,omitempty"`
|
|
ProgressRate *RespProgressRate `json:"progress_rate,omitempty"`
|
|
}
|
|
|
|
// ========== Simple-style response types (semi-plain text format) ==========
|
|
|
|
// RespKeyResultSimple is KeyResult response with SemiPlainContent instead of ContentBlock JSON string.
|
|
type RespKeyResultSimple struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
UpdateTime string `json:"update_time"`
|
|
Owner RespOwner `json:"owner"`
|
|
ObjectiveID string `json:"objective_id"`
|
|
Position *int32 `json:"position,omitempty"`
|
|
Content *SemiPlainContent `json:"content,omitempty"`
|
|
Score *float64 `json:"score,omitempty"`
|
|
Weight *float64 `json:"weight,omitempty"`
|
|
Deadline *string `json:"deadline,omitempty"`
|
|
}
|
|
|
|
// RespObjectiveSimple is Objective response with SemiPlainContent instead of ContentBlock JSON string.
|
|
type RespObjectiveSimple struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
UpdateTime string `json:"update_time"`
|
|
Owner RespOwner `json:"owner"`
|
|
CycleID string `json:"cycle_id"`
|
|
Position *int32 `json:"position,omitempty"`
|
|
Content *SemiPlainContent `json:"content,omitempty"`
|
|
Score *float64 `json:"score,omitempty"`
|
|
Notes *SemiPlainContent `json:"notes,omitempty"`
|
|
Weight *float64 `json:"weight,omitempty"`
|
|
Deadline *string `json:"deadline,omitempty"`
|
|
CategoryID *string `json:"category_id,omitempty"`
|
|
KeyResults []RespKeyResultSimple `json:"key_results,omitempty"`
|
|
}
|
|
|
|
// RespProgressSimple is Progress response with SemiPlainContent instead of ContentBlock JSON string.
|
|
type RespProgressSimple struct {
|
|
ID string `json:"progress_id"`
|
|
ModifyTime string `json:"modify_time"`
|
|
CreateTime *string `json:"create_time,omitempty"`
|
|
Content *SemiPlainContent `json:"content,omitempty"`
|
|
ProgressRate *RespProgressRate `json:"progress_rate,omitempty"`
|
|
}
|
|
|
|
// ToSimple converts KeyResult to RespKeyResultSimple.
|
|
func (k *KeyResult) ToSimple() *RespKeyResultSimple {
|
|
if k == nil {
|
|
return nil
|
|
}
|
|
result := &RespKeyResultSimple{
|
|
ID: k.ID,
|
|
CreateTime: formatTimestamp(k.CreateTime),
|
|
UpdateTime: formatTimestamp(k.UpdateTime),
|
|
Owner: *k.Owner.ToResp(),
|
|
ObjectiveID: k.ObjectiveID,
|
|
Position: k.Position,
|
|
Score: k.Score,
|
|
Weight: k.Weight,
|
|
}
|
|
if k.Deadline != nil {
|
|
d := formatTimestamp(*k.Deadline)
|
|
result.Deadline = &d
|
|
}
|
|
result.Content = k.Content.ToSemiPlain()
|
|
return result
|
|
}
|
|
|
|
// ToSimple converts Objective to RespObjectiveSimple.
|
|
func (o *Objective) ToSimple() *RespObjectiveSimple {
|
|
if o == nil {
|
|
return nil
|
|
}
|
|
result := &RespObjectiveSimple{
|
|
ID: o.ID,
|
|
CreateTime: formatTimestamp(o.CreateTime),
|
|
UpdateTime: formatTimestamp(o.UpdateTime),
|
|
Owner: *o.Owner.ToResp(),
|
|
CycleID: o.CycleID,
|
|
Position: o.Position,
|
|
Score: o.Score,
|
|
Weight: o.Weight,
|
|
CategoryID: o.CategoryID,
|
|
}
|
|
if o.Deadline != nil {
|
|
d := formatTimestamp(*o.Deadline)
|
|
result.Deadline = &d
|
|
}
|
|
result.Content = o.Content.ToSemiPlain()
|
|
result.Notes = o.Notes.ToSemiPlain()
|
|
return result
|
|
}
|
|
|
|
// ToSimple converts ProgressV1 to RespProgressSimple.
|
|
func (p *ProgressV1) ToSimple() *RespProgressSimple {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
resp := &RespProgressSimple{
|
|
ID: p.ID,
|
|
ModifyTime: formatTimestamp(p.ModifyTime),
|
|
}
|
|
if p.ProgressRate != nil {
|
|
resp.ProgressRate = &RespProgressRate{
|
|
Percent: p.ProgressRate.Percent,
|
|
}
|
|
if p.ProgressRate.Status != nil {
|
|
s := ProgressStatus(*p.ProgressRate.Status).String()
|
|
if s != "" {
|
|
resp.ProgressRate.Status = &s
|
|
}
|
|
}
|
|
}
|
|
if p.Content != nil {
|
|
resp.Content = p.Content.ToV2().ToSemiPlain()
|
|
}
|
|
return resp
|
|
}
|
|
|
|
// ToSimple converts Progress to RespProgressSimple.
|
|
func (p *Progress) ToSimple() *RespProgressSimple {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
createTime := formatTimestamp(p.CreateTime)
|
|
resp := &RespProgressSimple{
|
|
ID: p.ID,
|
|
ModifyTime: formatTimestamp(p.UpdateTime),
|
|
CreateTime: &createTime,
|
|
}
|
|
if p.ProgressRate != nil {
|
|
resp.ProgressRate = &RespProgressRate{
|
|
Percent: p.ProgressRate.ProgressPercent,
|
|
}
|
|
if p.ProgressRate.ProgressStatus != nil {
|
|
s := ProgressStatus(*p.ProgressRate.ProgressStatus).String()
|
|
if s != "" {
|
|
resp.ProgressRate.Status = &s
|
|
}
|
|
}
|
|
}
|
|
resp.Content = p.Content.ToSemiPlain()
|
|
return resp
|
|
}
|