| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- package plane_v2
- import (
- "encoding/json"
- "fmt"
- "go.uber.org/zap"
- )
- // ==================== Intake (收件箱) API ====================
- // WebIntakeIssueRequest 创建Intake工作项的请求结构
- type WebIntakeIssueRequest struct {
- Name string `json:"name"`
- DescriptionHTML string `json:"description_html,omitempty"`
- Priority string `json:"priority,omitempty"`
- StateID string `json:"state_id,omitempty"`
- AssigneeIDs []string `json:"assignee_ids,omitempty"`
- LabelIDs []string `json:"label_ids,omitempty"`
- StartDate string `json:"start_date,omitempty"`
- TargetDate *string `json:"target_date"`
- ParentID string `json:"parent_id,omitempty"`
- }
- // WebIntakeIssueResponse Intake创建响应
- type WebIntakeIssueResponse struct {
- Issue struct {
- ID string `json:"id"`
- Name string `json:"name"`
- DescriptionHTML string `json:"description_html"`
- Priority string `json:"priority"`
- } `json:"issue"`
- Status int `json:"status"`
- CreatedAt string `json:"created_at"`
- }
- // ListIntakeIssues 列出收件箱工作项
- // status: 逗号分隔的状态值,如 "-2,-1" (可为空表示不过滤)
- func ListIntakeIssues(slug, projectID, status string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/", slug, projectID)
- if status != "" {
- url += "?status=" + status
- }
- resp, err := planeWebGet(url)
- if err != nil {
- zap.L().Error("[PlaneWeb] ListIntakeIssues 请求失败", zap.Error(err))
- return nil, err
- }
- if !isWebSuccess(resp.StatusCode) {
- zap.L().Error("[PlaneWeb] ListIntakeIssues 返回错误", zap.String("status", resp.Status))
- return nil, fmt.Errorf("ListIntakeIssues 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- // CreateIntakeIssue 创建收件箱工作项
- func CreateIntakeIssue(slug, projectID string, issue WebIntakeIssueRequest) (*WebIntakeIssueResponse, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/", slug, projectID)
- payload := map[string]interface{}{
- "source": "IN_APP",
- "issue": issue,
- }
- resp, err := planeWebPost(url, payload)
- if err != nil {
- zap.L().Error("[PlaneWeb] CreateIntakeIssue 请求失败", zap.Error(err))
- return nil, err
- }
- if !isWebSuccess(resp.StatusCode) {
- zap.L().Error("[PlaneWeb] CreateIntakeIssue 返回错误",
- zap.String("status", resp.Status),
- zap.String("body", string(resp.Body)),
- )
- return nil, fmt.Errorf("CreateIntakeIssue 失败: %s", resp.Status)
- }
- var result WebIntakeIssueResponse
- if err := json.Unmarshal(resp.Body, &result); err != nil {
- zap.L().Error("[PlaneWeb] CreateIntakeIssue 响应解析失败", zap.Error(err))
- return nil, fmt.Errorf("响应解析失败: %w", err)
- }
- zap.L().Info("[PlaneWeb] CreateIntakeIssue 成功", zap.String("issueId", result.Issue.ID))
- return &result, nil
- }
- // CreateIntakeIssueRaw 创建收件箱工作项(原始map方式)
- func CreateIntakeIssueRaw(slug, projectID string, issueData map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/", slug, projectID)
- payload := map[string]interface{}{
- "issue": issueData,
- }
- resp, err := planeWebPost(url, payload)
- if err != nil {
- zap.L().Error("[PlaneWeb] CreateIntakeIssueRaw 请求失败", zap.Error(err))
- return nil, err
- }
- if !isWebSuccess(resp.StatusCode) {
- zap.L().Error("[PlaneWeb] CreateIntakeIssueRaw 返回错误",
- zap.String("status", resp.Status),
- zap.String("body", string(resp.Body)),
- )
- return nil, fmt.Errorf("CreateIntakeIssueRaw 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- // GetIntakeIssue 获取收件箱工作项详情
- func GetIntakeIssue(slug, projectID, issueID string) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/", slug, projectID, issueID)
- resp, err := planeWebGet(url)
- if err != nil {
- zap.L().Error("[PlaneWeb] GetIntakeIssue 请求失败", zap.Error(err))
- return nil, err
- }
- if !isWebSuccess(resp.StatusCode) {
- zap.L().Error("[PlaneWeb] GetIntakeIssue 返回错误", zap.String("status", resp.Status))
- return nil, fmt.Errorf("GetIntakeIssue 失败: %s", resp.Status)
- }
- return resp.Body, nil
- }
- // UpdateIntakeIssue 更新收件箱工作项(修改状态或内容)
- func UpdateIntakeIssue(slug, projectID, issueID string, data map[string]interface{}) ([]byte, error) {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/", slug, projectID, issueID)
- resp, err := planeWebPatch(url, data)
- if err != nil {
- zap.L().Error("[PlaneWeb] UpdateIntakeIssue 请求失败", zap.Error(err))
- return nil, err
- }
- if !isWebSuccess(resp.StatusCode) {
- zap.L().Error("[PlaneWeb] 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(slug, projectID, issueID string) ([]byte, error) {
- return UpdateIntakeIssue(slug, projectID, issueID, map[string]interface{}{
- "status": 1,
- })
- }
- // RejectIntakeIssue 拒绝收件箱工作项
- func RejectIntakeIssue(slug, projectID, issueID string) ([]byte, error) {
- return UpdateIntakeIssue(slug, projectID, issueID, map[string]interface{}{
- "status": -1,
- })
- }
- // SnoozeIntakeIssue 暂缓收件箱工作项
- func SnoozeIntakeIssue(slug, projectID, issueID, snoozedTill string) ([]byte, error) {
- return UpdateIntakeIssue(slug, projectID, issueID, map[string]interface{}{
- "status": 0,
- "snoozed_till": snoozedTill,
- })
- }
- // DuplicateIntakeIssue 标记收件箱工作项为重复
- func DuplicateIntakeIssue(slug, projectID, issueID, duplicateTo string) ([]byte, error) {
- return UpdateIntakeIssue(slug, projectID, issueID, map[string]interface{}{
- "status": 2,
- "duplicate_to": duplicateTo,
- })
- }
- // DeleteIntakeIssue 删除收件箱工作项
- func DeleteIntakeIssue(slug, projectID, issueID string) error {
- url := fmt.Sprintf("/api/workspaces/%s/projects/%s/intake-issues/%s/", slug, projectID, issueID)
- resp, err := planeWebDelete(url)
- if err != nil {
- zap.L().Error("[PlaneWeb] DeleteIntakeIssue 请求失败", zap.Error(err))
- return err
- }
- if resp.StatusCode != 204 {
- zap.L().Error("[PlaneWeb] DeleteIntakeIssue 返回错误", zap.String("status", resp.Status))
- return fmt.Errorf("DeleteIntakeIssue 失败: %s", resp.Status)
- }
- return nil
- }
- // ListCurrentIntakeIssues 列出当前项目的收件箱工作项
- func ListCurrentIntakeIssues(status string) ([]byte, error) {
- return ListIntakeIssues(webWorkspaceSlug, webProjectId, status)
- }
- // CreateCurrentIntakeIssue 在当前项目创建收件箱工作项
- func CreateCurrentIntakeIssue(issue WebIntakeIssueRequest) (*WebIntakeIssueResponse, error) {
- return CreateIntakeIssue(webWorkspaceSlug, webProjectId, issue)
- }
|