七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s

This commit is contained in:
2026-07-25 17:06:58 +08:00
parent ad9f613dd6
commit 73f5125d3d
249 changed files with 17137 additions and 877 deletions

View File

@@ -0,0 +1,100 @@
package wecom
import (
"context"
stdErrors "errors"
"github.com/bytedance/sonic"
"github.com/hibiken/asynq"
approvalapp "github.com/break/junhong_cmp_fiber/internal/application/approval"
"github.com/break/junhong_cmp_fiber/internal/infrastructure/messaging/outbox"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
)
// ApprovalSubmissionConsumer 消费通用审批提交 Outbox并保证结果未知时不盲目重提。
type ApprovalSubmissionConsumer struct {
repository *ApprovalContextRepository
client *ApprovalSubmissionClient
attachments approvalAttachmentPort
}
// NewApprovalSubmissionConsumer 创建企业微信审批提交消费者。
func NewApprovalSubmissionConsumer(repository *ApprovalContextRepository, client *ApprovalSubmissionClient, attachments approvalAttachmentPort) *ApprovalSubmissionConsumer {
return &ApprovalSubmissionConsumer{repository: repository, client: client, attachments: attachments}
}
// Consume 校验通用事件并提交一次企业微信审批申请。
func (c *ApprovalSubmissionConsumer) Consume(ctx context.Context, envelope outbox.DeliveryEnvelope) error {
if c == nil || c.repository == nil || c.client == nil {
return errors.New(errors.CodeServiceUnavailable, "企业微信审批提交消费者未配置")
}
if envelope.PayloadVersion != constants.ApprovalSubmissionPayloadVersionV1 {
return stdErrors.Join(asynq.SkipRetry, errors.New(errors.CodeInvalidParam, "不支持的审批提交事件版本"))
}
var event approvalapp.SubmissionRequestedEvent
if err := sonic.Unmarshal(envelope.Payload, &event); err != nil {
return stdErrors.Join(asynq.SkipRetry, errors.New(errors.CodeInvalidParam, "审批提交事件载荷无效"))
}
if event.InstanceID == 0 || event.Provider != constants.IntegrationProviderWeCom {
return stdErrors.Join(asynq.SkipRetry, errors.New(errors.CodeInvalidParam, "审批提交事件渠道或实例无效"))
}
record, claimed, err := c.repository.ClaimSubmission(ctx, event.InstanceID)
if err != nil {
return err
}
if !claimed {
return nil
}
form, err := buildApprovalForm(
ctx, record.Context.ApplicationID, event.InstanceID,
record.Context.ControlMapping, record.Context.TemplateSnapshot, record.Instance.RequestSnapshot, c.attachments,
)
if err != nil {
var attachmentErr *attachmentPreparationError
if stdErrors.As(err, &attachmentErr) {
if releaseErr := c.repository.ReleaseForRetry(ctx, event.InstanceID, "审批附件准备失败,等待重试"); releaseErr != nil {
return releaseErr
}
return err
}
if markErr := c.repository.MarkFailed(ctx, event.InstanceID, err.Error()); markErr != nil {
return markErr
}
return nil
}
result, submitErr := c.client.Submit(ctx, ApprovalSubmitRequest{
InstanceID: event.InstanceID, ApplicationID: record.Context.ApplicationID,
TemplateID: record.Context.TemplateID, CreatorUserID: record.Context.CreatorUserID,
CorrelationID: event.CorrelationID, Contents: form.Contents,
})
switch result.Outcome {
case submissionOutcomeSuccess:
if err := c.repository.MarkSubmitted(ctx, event.InstanceID, result.SPNo); err != nil {
return err
}
case submissionOutcomeUnknown:
if err := c.repository.MarkUnknown(ctx, event.InstanceID, result.Message); err != nil {
return err
}
case submissionOutcomeFailed:
if result.SafeToRetry {
if err := c.repository.ReleaseForRetry(ctx, event.InstanceID, result.Message); err != nil {
return err
}
if submitErr != nil {
return submitErr
}
return errors.New(errors.CodeServiceUnavailable, result.Message)
}
if err := c.repository.MarkFailed(ctx, event.InstanceID, result.Message); err != nil {
return err
}
default:
return errors.New(errors.CodeInternalError, "企业微信审批提交结果无效")
}
return submitErr
}
var _ outbox.EventConsumer = (*ApprovalSubmissionConsumer)(nil)