report

package
v1.0.63 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package report registers strict declarative shortcuts for DingTalk reports.

Index

Constants

This section is empty.

Variables

View Source
var InboxList = shortcut.Shortcut{
	Service: "report", Command: "+inbox-list", Product: "report",
	Description:   "列出我收到的日志",
	Intent:        "需要按明确时间范围读取别人发给我的日志摘要并取得稳定 reportId 时使用;后端必须提供可验证的终止或严格前进 cursor。",
	Risk:          shortcut.RiskRead,
	Safety:        reportReadSafety(),
	OutputRollout: output.RolloutUnifiedActive,
	Contract: reportContract(
		"+inbox-list", "列出我收到的日志",
		"需要按明确时间范围读取别人发给我的日志摘要并取得稳定 reportId 时使用;后端必须提供可验证的终止或严格前进 cursor。",
		reportCollectionResult("reports", "严格验证的收件箱日志页"), reportPagination(),
		[]contract.ParamDecl{
			{Name: "start", Property: "start"}, {Name: "end", Property: "end"},
			{Name: "cursor", Property: "cursor"}, {Name: "size", Property: "size"},
			{Name: "sender-user-ids", Property: "senderUserIds", InterfaceType: "array"},
		},
		"dws report +inbox-list --start \"2026-03-10T00:00:00+08:00\" --end \"2026-03-10T23:59:59+08:00\" --cursor 0 --size 20",
	),
	Flags: []shortcut.Flag{
		{Name: "start", Type: shortcut.FlagString, Desc: "开始时间 ISO-8601;结束时间必须晚于开始时间,跨度不得超过 180 天", Required: true},
		{Name: "end", Type: shortcut.FlagString, Desc: "结束时间 ISO-8601;结束时间必须晚于开始时间,跨度不得超过 180 天", Required: true},
		{Name: "cursor", Type: shortcut.FlagInt, Default: "0", Desc: "分页游标;--cursor 不能小于 0,续页 cursor 必须严格前进"},
		{Name: "size", Type: shortcut.FlagInt, Default: "20", Desc: "每页条数;--size 必须在 1 到 20 之间"},
		{Name: "sender-user-ids", Type: shortcut.FlagStringSlice, Desc: "发送人 staffId 列表"},
	},
	Constraints: []shortcut.Constraint{
		{Kind: shortcut.ConstraintCustom, Flags: []string{"start", "end"}, Description: "结束时间必须晚于开始时间,跨度不得超过 180 天"},
		{Kind: shortcut.ConstraintCustom, Flags: []string{"cursor"}, Description: "--cursor 不能小于 0,续页 cursor 必须严格前进"},
		{Kind: shortcut.ConstraintCustom, Flags: []string{"size"}, Description: "--size 必须在 1 到 20 之间"},
	},
	Tips: []string{`dws report +inbox-list --start "2026-03-10T00:00:00+08:00" --end "2026-03-10T23:59:59+08:00" --cursor 0 --size 20`},
	Validate: func(rt *shortcut.RuntimeContext) error {
		if err := reportValidatePage(rt.Int("cursor"), rt.Int("size")); err != nil {
			return err
		}
		_, _, err := reportValidateRange("start", rt.Str("start"), "end", rt.Str("end"), reportMaximumInboxDays)
		return err
	},
	Execute: func(rt *shortcut.RuntimeContext) error {
		const operation = "report/get_received_report_list"
		start, end, err := reportValidateRange("start", rt.Str("start"), "end", rt.Str("end"), reportMaximumInboxDays)
		if err != nil {
			return err
		}
		params := map[string]any{
			"startTime": start, "endTime": end,
			"cursor": rt.Int("cursor"), "size": rt.Int("size"),
		}
		if rt.Changed("sender-user-ids") {
			params["senderUserIds"] = rt.StrSlice("sender-user-ids")
		}
		data, err := rt.CallMCPData("report", "get_received_report_list", params)
		if err != nil {
			return err
		}
		reports, page, err := reportProjectEntries(data, operation)
		if err != nil {
			return err
		}
		if err := reportValidateContinuation(page, rt.Int("cursor"), operation); err != nil {
			return err
		}
		return outputReportPage(rt, "reports", reports, page)
	},
}
View Source
var OutboxList = shortcut.Shortcut{
	Service: "report", Command: "+outbox-list", Product: "report",
	Description:   "列出我发出的日志",
	Intent:        "需要按创建或修改时间回顾自己提交的日志并取得稳定 reportId 时使用;每次创建或修改时间窗不得超过 20 天。",
	Risk:          shortcut.RiskRead,
	Safety:        reportReadSafety(),
	OutputRollout: output.RolloutUnifiedActive,
	Contract: reportContract(
		"+outbox-list", "列出我发出的日志",
		"需要按创建或修改时间回顾自己提交的日志并取得稳定 reportId 时使用;每次创建或修改时间窗不得超过 20 天。",
		reportCollectionResult("reports", "严格验证的发件箱日志页"), reportPagination(),
		[]contract.ParamDecl{
			{Name: "cursor", Property: "cursor"}, {Name: "size", Property: "size"},
			{Name: "start", Property: "start"}, {Name: "end", Property: "end"},
			{Name: "modified-start", Property: "modifiedStart"}, {Name: "modified-end", Property: "modifiedEnd"},
			{Name: "template-name", Property: "templateName"},
		},
		"dws report +outbox-list --cursor 0 --size 20",
	),
	Flags: []shortcut.Flag{
		{Name: "cursor", Type: shortcut.FlagInt, Default: "0", Desc: "分页游标;--cursor 不能小于 0,续页 cursor 必须严格前进"},
		{Name: "size", Type: shortcut.FlagInt, Default: "20", Desc: "每页条数;--size 必须在 1 到 20 之间"},
		{Name: "start", Type: shortcut.FlagString, Desc: "创建开始时间 ISO-8601;创建时间范围必须有效且不得超过 20 天"},
		{Name: "end", Type: shortcut.FlagString, Desc: "创建结束时间 ISO-8601;创建时间范围必须有效且不得超过 20 天"},
		{Name: "modified-start", Type: shortcut.FlagString, Desc: "修改开始时间 ISO-8601;修改时间必须成对提供、范围有效且不得超过 20 天"},
		{Name: "modified-end", Type: shortcut.FlagString, Desc: "修改结束时间 ISO-8601;修改时间必须成对提供、范围有效且不得超过 20 天"},
		{Name: "template-name", Type: shortcut.FlagString, Desc: "日志模板名称"},
	},
	Constraints: []shortcut.Constraint{
		{Kind: shortcut.ConstraintCustom, Flags: []string{"cursor"}, Description: "--cursor 不能小于 0,续页 cursor 必须严格前进"},
		{Kind: shortcut.ConstraintCustom, Flags: []string{"size"}, Description: "--size 必须在 1 到 20 之间"},
		{Kind: shortcut.ConstraintCustom, Flags: []string{"start", "end"}, Description: "创建时间范围必须有效且不得超过 20 天"},
		{Kind: shortcut.ConstraintCustom, Flags: []string{"modified-start", "modified-end"}, Description: "修改时间必须成对提供、范围有效且不得超过 20 天"},
	},
	Tips: []string{"dws report +outbox-list --cursor 0 --size 20"},
	Validate: func(rt *shortcut.RuntimeContext) error {
		if err := reportValidatePage(rt.Int("cursor"), rt.Int("size")); err != nil {
			return err
		}
		if rt.Changed("start") && rt.Changed("end") {
			if _, _, err := reportValidateRange("start", rt.Str("start"), "end", rt.Str("end"), reportMaximumOutboxDays); err != nil {
				return err
			}
		}
		if rt.Changed("modified-start") != rt.Changed("modified-end") {
			return apperrors.NewValidation("--modified-start 与 --modified-end 必须同时提供", apperrors.WithReason("incomplete_modified_range"))
		}
		if rt.Changed("modified-start") {
			_, _, err := reportValidateRange("modified-start", rt.Str("modified-start"), "modified-end", rt.Str("modified-end"), reportMaximumOutboxDays)
			return err
		}
		return nil
	},
	Execute: func(rt *shortcut.RuntimeContext) error {
		const operation = "report/get_send_report_list"
		now := time.Now()
		defaultEnd := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())
		startValue := defaultEnd.Add(-reportMaximumOutboxDays * 24 * time.Hour).Format(time.RFC3339)
		endValue := defaultEnd.Format(time.RFC3339)
		if rt.Changed("start") {
			startValue = rt.Str("start")
		}
		if rt.Changed("end") {
			endValue = rt.Str("end")
		}
		start, end, err := reportValidateRange("start", startValue, "end", endValue, reportMaximumOutboxDays)
		if err != nil {
			return err
		}
		params := map[string]any{
			"cursor": rt.Int("cursor"), "size": rt.Int("size"),
			"startTime": start, "endTime": end,
		}
		if rt.Changed("modified-start") {
			modifiedStart, modifiedEnd, rangeErr := reportValidateRange("modified-start", rt.Str("modified-start"), "modified-end", rt.Str("modified-end"), reportMaximumOutboxDays)
			if rangeErr != nil {
				return rangeErr
			}
			params["modifiedStartTime"], params["modifiedEndTime"] = modifiedStart, modifiedEnd
		}
		if name := strings.TrimSpace(rt.Str("template-name")); name != "" {
			params["report_template_name"] = name
		}
		data, err := rt.CallMCPData("report", "get_send_report_list", params)
		if err != nil {
			return err
		}
		reports, page, err := reportProjectEntries(data, operation)
		if err != nil {
			return err
		}
		if err := reportValidateContinuation(page, rt.Int("cursor"), operation); err != nil {
			return err
		}
		return outputReportPage(rt, "reports", reports, page)
	},
}
View Source
var ReportLatest = shortcut.Shortcut{
	Service: "report", Command: "+report-latest", Product: "report",
	Description:   "读取我最近提交的一篇日志详情",
	Intent:        "只想查看明确 20 天内自己提交的最新日志详情时使用;默认最近 20 天,也可成对指定创建时间窗,有界遍历全部候选页后按精确 reportId 读回详情。",
	Risk:          shortcut.RiskRead,
	Safety:        reportReadSafety(),
	OutputRollout: output.RolloutUnifiedActive,
	Contract: reportContract(
		"+report-latest", "读取我最近提交的一篇日志详情",
		"只想查看明确 20 天内自己提交的最新日志详情时使用;默认最近 20 天,也可成对指定创建时间窗,有界遍历全部候选页后按精确 reportId 读回详情。",
		reportLatestResult(), nil,
		[]contract.ParamDecl{
			{Name: "keyword", Property: "report_template_name"},
			{Name: "start", Property: "startTime"}, {Name: "end", Property: "endTime"},
		},
		"dws report +report-latest", `dws report +report-latest --start "2026-03-01T00:00:00+08:00" --end "2026-03-20T00:00:00+08:00"`,
	),
	Flags: []shortcut.Flag{
		{Name: "keyword", Type: shortcut.FlagString, Desc: "按日志模板名称精确过滤"},
		{Name: "start", Type: shortcut.FlagString, Desc: "创建开始时间 ISO-8601;--start 与 --end 必须同时提供,且创建时间范围必须有效并不得超过 20 天"},
		{Name: "end", Type: shortcut.FlagString, Desc: "创建结束时间 ISO-8601;--start 与 --end 必须同时提供,且创建时间范围必须有效并不得超过 20 天"},
	},
	Constraints: []shortcut.Constraint{
		{Kind: shortcut.ConstraintCustom, Flags: []string{"start", "end"}, Description: "--start 与 --end 必须同时提供,且创建时间范围必须有效并不得超过 20 天"},
	},
	Tips: []string{"dws report +report-latest", `dws report +report-latest --start "2026-03-01T00:00:00+08:00" --end "2026-03-20T00:00:00+08:00"`},
	Validate: func(rt *shortcut.RuntimeContext) error {
		if rt.Changed("start") != rt.Changed("end") {
			return apperrors.NewValidation("--start 与 --end 必须同时提供", apperrors.WithReason("incomplete_creation_range"))
		}
		if rt.Changed("start") {
			_, _, err := reportValidateRange("start", rt.Str("start"), "end", rt.Str("end"), reportMaximumOutboxDays)
			return err
		}
		return nil
	},
	Execute: func(rt *shortcut.RuntimeContext) error {
		const listOperation = "report/get_send_report_list"
		originalContext := rt.Command().Context()
		if originalContext == nil {
			originalContext = context.Background()
		}
		boundedContext, cancel := context.WithTimeout(originalContext, reportLatestTimeout)
		rt.Command().SetContext(boundedContext)
		defer func() {
			rt.Command().SetContext(originalContext)
			cancel()
		}()

		now := time.Now()

		end := now
		start := end.Add(-reportMaximumOutboxDays * 24 * time.Hour)
		if rt.Changed("start") {
			startMillis, endMillis, err := reportValidateRange("start", rt.Str("start"), "end", rt.Str("end"), reportMaximumOutboxDays)
			if err != nil {
				return err
			}
			start, end = time.UnixMilli(startMillis), time.UnixMilli(endMillis)
		}
		params := map[string]any{
			"size":      reportLatestPageSize,
			"startTime": start.UnixMilli(), "endTime": end.UnixMilli(),
		}
		if keyword := strings.TrimSpace(rt.Str("keyword")); keyword != "" {
			params["report_template_name"] = keyword
		}
		entries, err := reportCollectLatestCandidates(rt, params, listOperation)
		if err != nil {
			return err
		}
		if len(entries) == 0 {
			return apperrors.NewValidation("所选时间窗内没有可验证的已发送日志", apperrors.WithReason("no_sent_report_fixture"))
		}
		latestID, err := reportLatestEntryID(entries, listOperation)
		if err != nil {
			return err
		}
		const detailOperation = "report/get_report_entry_details"
		detailData, err := rt.CallMCPData("report", "get_report_entry_details", map[string]any{"report_id": latestID})
		if err != nil {
			return err
		}
		detail, err := reportProjectDetail(detailData, detailOperation, latestID)
		if err != nil {
			return err
		}
		return rt.Output(map[string]any{"report": detail})
	},
}
View Source
var TemplateSearch = shortcut.Shortcut{
	Service: "report", Command: "+template-search", Product: "report",
	Description:   "按名称搜索可用日志模板",
	Intent:        "需要从当前用户全部可用日志模板中按名称查找稳定 templateId,或在提交日志前确认模板是否存在时使用。",
	Risk:          shortcut.RiskRead,
	Safety:        reportReadSafety(),
	OutputRollout: output.RolloutUnifiedActive,
	Contract: reportContract(
		"+template-search", "按名称搜索可用日志模板",
		"需要从当前用户全部可用日志模板中按名称查找稳定 templateId,或在提交日志前确认模板是否存在时使用。",
		reportTemplateSearchResult(), nil,
		[]contract.ParamDecl{{Name: "query", Property: "report_template_name"}},
		"dws report +template-search --query 周报",
	),
	Flags:       []shortcut.Flag{{Name: "query", Type: shortcut.FlagString, Desc: "模板名称关键词,不区分大小写;--query 不能为空", Required: true}},
	Constraints: []shortcut.Constraint{{Kind: shortcut.ConstraintCustom, Flags: []string{"query"}, Description: "--query 不能为空"}},
	Tips:        []string{"dws report +template-search --query 周报"},
	Validate: func(rt *shortcut.RuntimeContext) error {
		if strings.TrimSpace(rt.Str("query")) == "" {
			return apperrors.NewValidation("--query 不能为空", apperrors.WithReason("empty_query"))
		}
		return nil
	},
	Execute: func(rt *shortcut.RuntimeContext) error {
		const operation = "report/get_available_report_templates"
		data, err := rt.CallMCPData("report", "get_available_report_templates", map[string]any{})
		if err != nil {
			return err
		}
		templates, err := reportProjectTemplates(data, operation)
		if err != nil {
			return err
		}
		query := strings.ToLower(strings.TrimSpace(rt.Str("query")))
		matches := make([]map[string]any, 0)
		for _, template := range templates {
			if strings.Contains(strings.ToLower(template["name"].(string)), query) {
				matches = append(matches, template)
			}
		}
		payload := map[string]any{"count": len(matches), "templates": matches}
		if !output.UsesUnifiedResult(rt.Command()) {
			return rt.Output(payload)
		}
		meta := &output.Meta{Count: output.NewCount(len(matches))}
		return output.StoreResult(rt.Command().Context(), output.Success(payload, output.WithMeta(meta)))
	},
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL