package plane_v1 import ( "encoding/json" "fmt" "go.uber.org/zap" ) // ==================== Intake Issue 请求/响应结构 ==================== // IntakeIssueRequest Intake Issue创建请求体 type IntakeIssueRequest struct { Issue IntakeIssue `json:"issue"` Source string `json:"source"` } // IntakeIssue Issue详情 type IntakeIssue struct { Name string `json:"name"` DescriptionHTML string `json:"description_html"` Priority string `json:"priority"` LabelIds []string `json:"label_ids,omitempty"` } // IntakeIssueResponse Intake Issue创建响应 type IntakeIssueResponse struct { Id string `json:"id"` IssueId string `json:"issue"` Status int `json:"status"` Source string `json:"source"` CreatedAt string `json:"created_at"` } // IntakeListResponse Intake列表响应 type IntakeListResponse struct { Results []IntakeListItem `json:"results"` TotalCount int `json:"total_count"` NextCursor string `json:"next_cursor"` } // IntakeListItem Intake列表项 type IntakeListItem struct { Id string `json:"id"` Status int `json:"status"` Source string `json:"source"` CreatedAt string `json:"created_at"` Issue IntakeIssueInfo `json:"issue_detail"` } // IntakeIssueInfo Issue基础信息 type IntakeIssueInfo struct { Id string `json:"id"` Name string `json:"name"` Priority string `json:"priority"` } // ==================== Intake Issue API操作 ==================== // CreateIntakeIssue 创建Intake Issue func CreateIntakeIssue(req IntakeIssueRequest) (*IntakeIssueResponse, error) { url := fmt.Sprintf("/api/v1/workspaces/%s/projects/%s/intake-issues/", planeWorkspaceSlug, planeProjectId, ) resp, err := planeHttpPost(url, req) if err != nil { zap.L().Error("[Plane] CreateIntakeIssue 请求失败", zap.String("err", err.Error())) return nil, fmt.Errorf("提交失败: %w", err) } if !isSuccess(resp.StatusCode) { zap.L().Error("[Plane] CreateIntakeIssue 返回错误", zap.String("status", resp.Status), zap.String("body", string(resp.Body)), ) return nil, fmt.Errorf("提交失败: Plane 返回 %s", resp.Status) } var result IntakeIssueResponse if err := json.Unmarshal(resp.Body, &result); err != nil { zap.L().Error("[Plane] CreateIntakeIssue 响应解析失败", zap.String("err", err.Error())) return nil, fmt.Errorf("响应解析失败: %w", err) } zap.L().Info("[Plane] CreateIntakeIssue 成功", zap.String("id", result.Id)) return &result, nil } // GetIntakeIssueList 查询Intake Issue列表 func GetIntakeIssueList() (*IntakeListResponse, error) { url := fmt.Sprintf("/api/v1/workspaces/%s/projects/%s/intake-issues/?per_page=100&expand=issue_detail", planeWorkspaceSlug, planeProjectId, ) resp, err := planeHttpGet(url) if err != nil { zap.L().Error("[Plane] GetIntakeIssueList 请求失败", zap.String("err", err.Error())) return nil, fmt.Errorf("查询失败: %w", err) } if !isSuccess(resp.StatusCode) { zap.L().Error("[Plane] GetIntakeIssueList 返回错误", zap.String("status", resp.Status)) return nil, fmt.Errorf("查询失败: Plane 返回 %s", resp.Status) } var listResp IntakeListResponse if err := json.Unmarshal(resp.Body, &listResp); err != nil { zap.L().Error("[Plane] GetIntakeIssueList 响应解析失败", zap.String("err", err.Error())) return nil, fmt.Errorf("响应解析失败: %w", err) } zap.L().Debug("[Plane] GetIntakeIssueList", zap.Int("count", len(listResp.Results))) return &listResp, nil } // GetIntakeIssueDetail 获取收件箱工作项详情 func GetIntakeIssueDetail(issueID string) ([]byte, error) { url := fmt.Sprintf("/api/v1/workspaces/%s/projects/%s/intake-issues/%s/", planeWorkspaceSlug, planeProjectId, issueID) resp, err := planeHttpGet(url) if err != nil { zap.L().Error("[Plane] GetIntakeIssueDetail 请求失败", zap.Error(err)) return nil, err } if !isSuccess(resp.StatusCode) { zap.L().Error("[Plane] GetIntakeIssueDetail 返回错误", zap.String("status", resp.Status)) return nil, fmt.Errorf("GetIntakeIssueDetail 失败: %s", resp.Status) } return resp.Body, nil } // UpdateIntakeIssue 更新收件箱工作项 func UpdateIntakeIssue(issueID string, data map[string]interface{}) ([]byte, error) { url := fmt.Sprintf("/api/v1/workspaces/%s/projects/%s/intake-issues/%s/", planeWorkspaceSlug, planeProjectId, issueID) resp, err := planeHttpPatch(url, data) if err != nil { zap.L().Error("[Plane] UpdateIntakeIssue 请求失败", zap.Error(err)) return nil, err } if !isSuccess(resp.StatusCode) { zap.L().Error("[Plane] UpdateIntakeIssue 返回错误", zap.String("status", resp.Status), zap.String("body", string(resp.Body)), ) return nil, fmt.Errorf("UpdateIntakeIssue 失败: %s", resp.Status) } return resp.Body, nil } // AcceptIntakeIssue 接受收件箱工作项 func AcceptIntakeIssue(issueID string) ([]byte, error) { return UpdateIntakeIssue(issueID, map[string]interface{}{"status": 1}) } // RejectIntakeIssue 拒绝收件箱工作项 func RejectIntakeIssue(issueID string) ([]byte, error) { return UpdateIntakeIssue(issueID, map[string]interface{}{"status": -1}) } // DeleteIntakeIssue 删除收件箱工作项 func DeleteIntakeIssue(issueID string) error { url := fmt.Sprintf("/api/v1/workspaces/%s/projects/%s/intake-issues/%s/", planeWorkspaceSlug, planeProjectId, issueID) resp, err := planeHttpDelete(url) if err != nil { zap.L().Error("[Plane] DeleteIntakeIssue 请求失败", zap.Error(err)) return err } if resp.StatusCode != 204 { zap.L().Error("[Plane] DeleteIntakeIssue 返回错误", zap.String("status", resp.Status)) return fmt.Errorf("DeleteIntakeIssue 失败: %s", resp.Status) } return nil }