docs(README): 更新文档为中文并完善API参考
- 将README从英文翻译为中文 - 添加详细的API参考文档,包括所有管理接口和枚举值说明 - 补充安装、快速开始、认证方式等使用指南 refactor(client): 优化客户端代码结构并添加详细注释 - 为所有API方法添加中文注释和使用说明 - 改进Client结构体和Option配置的设计 - 统一错误处理和响应结构的文档说明
This commit is contained in:
@@ -2,7 +2,14 @@ package emailcli
|
||||
|
||||
import "time"
|
||||
|
||||
// PaginationResult is the generic paginated response wrapper.
|
||||
// PaginationResult 是分页接口的统一返回结构。
|
||||
//
|
||||
// {
|
||||
// "list": [...], // 当前页数据
|
||||
// "total": 123, // 总记录数
|
||||
// "page": 1,
|
||||
// "page_size": 20
|
||||
// }
|
||||
type PaginationResult[T any] struct {
|
||||
List []T `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
@@ -10,13 +17,17 @@ type PaginationResult[T any] struct {
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// PaginationQuery 是所有列表接口的分页参数基类,
|
||||
// 业务 Query 结构体可通过嵌入来复用。
|
||||
// - Page: 页码,从 1 开始;省略时后端默认 1
|
||||
// - PageSize: 每页大小,省略时后端默认 20,最大 100
|
||||
type PaginationQuery struct {
|
||||
Page int `json:"page,omitempty"`
|
||||
PageSize int `json:"page_size,omitempty"`
|
||||
}
|
||||
|
||||
// --- GormModel fields ---
|
||||
|
||||
// GormModel 对应后端 gorm.Model。注意后端该部分没有自定义 json tag,
|
||||
// 因此字段使用 PascalCase 序列化(与数据库模型保持一致)。
|
||||
type GormModel struct {
|
||||
ID uint `json:"ID"`
|
||||
CreatedAt time.Time `json:"CreatedAt"`
|
||||
@@ -24,84 +35,104 @@ type GormModel struct {
|
||||
DeletedAt *time.Time `json:"DeletedAt"`
|
||||
}
|
||||
|
||||
// --- Account ---
|
||||
// ============================================================
|
||||
// Account 邮件账号
|
||||
// ============================================================
|
||||
|
||||
// Account 表示一个邮件发送账号。
|
||||
// AppKey 用于发件认证;AppSecret 只在创建或重置时返回一次,
|
||||
// 入库时以 bcrypt 保存,SDK 不会回传。
|
||||
type Account struct {
|
||||
GormModel
|
||||
UserID int `json:"user_id"`
|
||||
Name string `json:"name"`
|
||||
AppKey string `json:"app_key"`
|
||||
Status int8 `json:"status"`
|
||||
AuditMode int8 `json:"audit_mode"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
AllowedChannels string `json:"allowed_channels"`
|
||||
DefaultSignatureID *uint `json:"default_signature_id"`
|
||||
Remark string `json:"remark"`
|
||||
UserID int `json:"user_id"` // 关联主平台用户 ID
|
||||
Name string `json:"name"` // 账号名称
|
||||
AppKey string `json:"app_key"` // 发件公钥
|
||||
Status int8 `json:"status"` // 账号状态: 0=禁用 1=启用
|
||||
AuditMode int8 `json:"audit_mode"` // 审核模式: 0=免审核 1=自动 2=人工
|
||||
RateLimit int `json:"rate_limit"` // 频率限制(封/分钟),0 表示不限
|
||||
DefaultChannelID *uint `json:"default_channel_id"` // 默认发件通道 ID
|
||||
AllowedChannels string `json:"allowed_channels"` // 允许的通道 ID 列表 JSON 字符串,如 "[1,2]";空串=不限
|
||||
DefaultSignatureID *uint `json:"default_signature_id"` // 默认签名 ID
|
||||
Remark string `json:"remark"` // 备注
|
||||
}
|
||||
|
||||
// CreateAccountReq 是创建账号的请求体。
|
||||
type CreateAccountReq struct {
|
||||
UserID int `json:"user_id"`
|
||||
Name string `json:"name"`
|
||||
AuditMode *int8 `json:"audit_mode,omitempty"`
|
||||
RateLimit *int `json:"rate_limit,omitempty"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
UserID int `json:"user_id"` // 必填,关联用户 ID
|
||||
Name string `json:"name"` // 必填,账号名称,≤100
|
||||
AuditMode *int8 `json:"audit_mode,omitempty"` // 可选,默认 0 免审核
|
||||
RateLimit *int `json:"rate_limit,omitempty"` // 可选,0=不限
|
||||
DefaultChannelID *uint `json:"default_channel_id,omitempty"` // 可选,默认发件通道 ID
|
||||
AllowedChannels string `json:"allowed_channels,omitempty"` // 可选,允许通道 ID 列表的 JSON 字符串
|
||||
Remark string `json:"remark,omitempty"` // 可选,备注
|
||||
}
|
||||
|
||||
// CreateAccountResp 是创建账号后的返回,AppSecret 仅此一次明文展示。
|
||||
type CreateAccountResp struct {
|
||||
ID uint `json:"id"`
|
||||
AppKey string `json:"app_key"`
|
||||
AppSecret string `json:"app_secret"`
|
||||
AppSecret string `json:"app_secret"` // 明文密钥,务必妥善保存
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// UpdateAccountReq 所有字段均为可选;只对传入字段做局部更新。
|
||||
type UpdateAccountReq struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
AuditMode *int8 `json:"audit_mode,omitempty"`
|
||||
RateLimit *int `json:"rate_limit,omitempty"`
|
||||
AllowedChannels *string `json:"allowed_channels,omitempty"`
|
||||
DefaultSignatureID *uint `json:"default_signature_id,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"` // 0=禁用 1=启用
|
||||
AuditMode *int8 `json:"audit_mode,omitempty"` // 0=免审核 1=自动 2=人工
|
||||
RateLimit *int `json:"rate_limit,omitempty"` // 封/分钟,0=不限
|
||||
DefaultChannelID *uint `json:"default_channel_id,omitempty"` // 默认发件通道 ID
|
||||
AllowedChannels *string `json:"allowed_channels,omitempty"` // 允许通道 ID 列表 JSON
|
||||
DefaultSignatureID *uint `json:"default_signature_id,omitempty"` // 默认签名 ID
|
||||
Remark *string `json:"remark,omitempty"`
|
||||
}
|
||||
|
||||
// AccountListQuery 是账号列表过滤参数。
|
||||
type AccountListQuery struct {
|
||||
PaginationQuery
|
||||
UserID *int `json:"user_id,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"`
|
||||
UserID *int `json:"user_id,omitempty"` // 按用户过滤
|
||||
Status *int8 `json:"status,omitempty"` // 0=禁用 1=启用
|
||||
Keyword string `json:"keyword,omitempty"` // 模糊匹配 name / remark
|
||||
}
|
||||
|
||||
// ResetSecretResp 是重置密钥后的返回。
|
||||
type ResetSecretResp struct {
|
||||
AppSecret string `json:"app_secret"`
|
||||
AppSecret string `json:"app_secret"` // 新生成的明文密钥
|
||||
}
|
||||
|
||||
// --- Signature ---
|
||||
// ============================================================
|
||||
// Signature 签名
|
||||
// ============================================================
|
||||
|
||||
// Signature 表示一个邮件签名。
|
||||
// EnglishName 会作为 From 地址的 local 部分组装发件人(签名@域名)。
|
||||
type Signature struct {
|
||||
GormModel
|
||||
UserID int `json:"user_id"`
|
||||
AccountID *uint `json:"account_id"`
|
||||
Title string `json:"title"`
|
||||
EnglishName string `json:"english_name"`
|
||||
Content string `json:"content"`
|
||||
Applicant string `json:"applicant"`
|
||||
ApplicantInfo string `json:"applicant_info"`
|
||||
Status int8 `json:"status"`
|
||||
AccountID *uint `json:"account_id"` // 为空表示用户全局签名
|
||||
Title string `json:"title"` // 中文抬头
|
||||
EnglishName string `json:"english_name"` // 英文标识(用于拼 From 地址)
|
||||
Content string `json:"content"` // HTML 签名正文
|
||||
Applicant string `json:"applicant"` // 申请人
|
||||
ApplicantInfo string `json:"applicant_info"` // 申请说明
|
||||
Status int8 `json:"status"` // 0=待审核 1=已通过 2=已驳回
|
||||
RejectReason string `json:"reject_reason"`
|
||||
Auditor string `json:"auditor"`
|
||||
AuditedAt *time.Time `json:"audited_at"`
|
||||
}
|
||||
|
||||
// CreateSignatureReq 是创建签名的请求体。新建签名默认 Status=0(待审核)。
|
||||
type CreateSignatureReq struct {
|
||||
UserID int `json:"user_id"`
|
||||
AccountID *uint `json:"account_id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
EnglishName string `json:"english_name"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Applicant string `json:"applicant,omitempty"`
|
||||
ApplicantInfo string `json:"applicant_info,omitempty"`
|
||||
UserID int `json:"user_id"` // 必填
|
||||
AccountID *uint `json:"account_id,omitempty"` // 可选,绑定账号
|
||||
Title string `json:"title"` // 必填,中文抬头
|
||||
EnglishName string `json:"english_name"` // 必填,英文标识
|
||||
Content string `json:"content,omitempty"` // HTML 签名内容
|
||||
Applicant string `json:"applicant,omitempty"` // 申请人
|
||||
ApplicantInfo string `json:"applicant_info,omitempty"` // 申请说明
|
||||
}
|
||||
|
||||
// UpdateSignatureReq 局部更新签名字段。
|
||||
type UpdateSignatureReq struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
EnglishName *string `json:"english_name,omitempty"`
|
||||
@@ -110,64 +141,79 @@ type UpdateSignatureReq struct {
|
||||
ApplicantInfo *string `json:"applicant_info,omitempty"`
|
||||
}
|
||||
|
||||
// AuditSignatureReq 是审核签名的请求体。
|
||||
type AuditSignatureReq struct {
|
||||
Status int8 `json:"status"`
|
||||
RejectReason string `json:"reject_reason,omitempty"`
|
||||
Status int8 `json:"status"` // 1=通过 2=驳回
|
||||
RejectReason string `json:"reject_reason,omitempty"` // 驳回时填写
|
||||
}
|
||||
|
||||
// SignatureListQuery 是签名列表过滤参数。
|
||||
type SignatureListQuery struct {
|
||||
PaginationQuery
|
||||
AccountID *uint `json:"account_id,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"` // 0=待审核 1=已通过 2=已驳回
|
||||
UserID *int `json:"user_id,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"` // 模糊匹配 title / english_name
|
||||
}
|
||||
|
||||
// --- Mail ---
|
||||
// ============================================================
|
||||
// Mail 发送邮件
|
||||
// ============================================================
|
||||
|
||||
// SendMailReq 是 POST /api/v1/mail/send 的请求体。
|
||||
//
|
||||
// Channel 为空时,后端按以下顺序自动选择:
|
||||
// 1. Account.DefaultChannelID 对应的已启用通道;
|
||||
// 2. Account.AllowedChannels 列表中的首个已启用通道。
|
||||
type SendMailReq struct {
|
||||
To []string `json:"to"`
|
||||
Cc []string `json:"cc,omitempty"`
|
||||
Bcc []string `json:"bcc,omitempty"`
|
||||
Subject string `json:"subject"`
|
||||
Body string `json:"body"`
|
||||
ContentType string `json:"content_type,omitempty"`
|
||||
Channel string `json:"channel"`
|
||||
SignatureID *uint `json:"signature_id,omitempty"`
|
||||
SignatureTitle string `json:"signature_title,omitempty"`
|
||||
Attachments []AttachmentItem `json:"attachments,omitempty"`
|
||||
To []string `json:"to"` // 必填,收件人列表(至少 1 个)
|
||||
Cc []string `json:"cc,omitempty"` // 抄送
|
||||
Bcc []string `json:"bcc,omitempty"` // 密送
|
||||
Subject string `json:"subject"` // 必填,主题
|
||||
Body string `json:"body"` // 必填,正文
|
||||
ContentType string `json:"content_type,omitempty"` // text/plain 或 text/html,默认 text/html
|
||||
Channel string `json:"channel,omitempty"` // 通道 code;留空走默认/允许通道
|
||||
SignatureID *uint `json:"signature_id,omitempty"` // 指定签名 ID(优先级低于 title)
|
||||
SignatureTitle string `json:"signature_title,omitempty"` // 按 title + user_id 查找已审核签名
|
||||
Attachments []AttachmentItem `json:"attachments,omitempty"` // 附件
|
||||
}
|
||||
|
||||
// AttachmentItem 附件项,Content 为 base64 编码字符串。
|
||||
type AttachmentItem struct {
|
||||
Filename string `json:"filename"`
|
||||
Content string `json:"content"`
|
||||
Filename string `json:"filename"` // 文件名(含扩展名)
|
||||
Content string `json:"content"` // base64 编码的文件内容
|
||||
}
|
||||
|
||||
// SendMailResp 是发送邮件的返回结果。
|
||||
type SendMailResp struct {
|
||||
MailLogID uint `json:"mail_log_id"`
|
||||
Status string `json:"status"`
|
||||
MailLogID uint `json:"mail_log_id"` // 创建的邮件日志 ID
|
||||
Status string `json:"status"` // queued / pending_audit / rejected
|
||||
}
|
||||
|
||||
// --- Mail Log ---
|
||||
// ============================================================
|
||||
// MailLog 邮件日志
|
||||
// ============================================================
|
||||
|
||||
// MailLog 邮件日志记录。
|
||||
// Status 枚举:0=待审核 1=排队中 2=发送中 3=成功 4=失败 5=放弃 6=驳回
|
||||
type MailLog struct {
|
||||
GormModel
|
||||
UserID int `json:"user_id"`
|
||||
AccountID uint `json:"account_id"`
|
||||
QuotaID *uint `json:"quota_id"`
|
||||
ChannelID *uint `json:"channel_id"`
|
||||
SenderAccountID *uint `json:"sender_account_id"`
|
||||
QuotaID *uint `json:"quota_id"` // 扣减的配额记录 ID
|
||||
ChannelID *uint `json:"channel_id"` // 使用的发件通道 ID
|
||||
SenderAccountID *uint `json:"sender_account_id"` // 实际使用的发信账号 ID
|
||||
SignatureID *uint `json:"signature_id"`
|
||||
MessageID string `json:"message_id"`
|
||||
FromAddress string `json:"from_address"`
|
||||
ToAddresses string `json:"to_addresses"`
|
||||
CcAddresses string `json:"cc_addresses"`
|
||||
BccAddresses string `json:"bcc_addresses"`
|
||||
MessageID string `json:"message_id"` // SMTP 返回的 Message-ID
|
||||
FromAddress string `json:"from_address"` // 实际 From 地址
|
||||
ToAddresses string `json:"to_addresses"` // JSON 字符串数组
|
||||
CcAddresses string `json:"cc_addresses"` // JSON 字符串数组
|
||||
BccAddresses string `json:"bcc_addresses"` // JSON 字符串数组
|
||||
Subject string `json:"subject"`
|
||||
ContentType string `json:"content_type"`
|
||||
HasAttachment bool `json:"has_attachment"`
|
||||
SourceIP string `json:"source_ip"`
|
||||
SourceType string `json:"source_type"`
|
||||
SourceIP string `json:"source_ip"` // 请求来源 IP
|
||||
SourceType string `json:"source_type"` // http / smtp
|
||||
Status int8 `json:"status"`
|
||||
RetryCount int `json:"retry_count"`
|
||||
MaxRetry int `json:"max_retry"`
|
||||
@@ -175,51 +221,61 @@ type MailLog struct {
|
||||
SentAt *time.Time `json:"sent_at"`
|
||||
}
|
||||
|
||||
// MailLogListQuery 是邮件日志列表过滤参数。
|
||||
type MailLogListQuery struct {
|
||||
PaginationQuery
|
||||
UserID *int `json:"user_id,omitempty"`
|
||||
AccountID *uint `json:"account_id,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
StartDate string `json:"start_date,omitempty"`
|
||||
EndDate string `json:"end_date,omitempty"`
|
||||
To string `json:"to,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"` // 见 MailLog.Status 枚举
|
||||
StartDate string `json:"start_date,omitempty"` // 格式 YYYY-MM-DD
|
||||
EndDate string `json:"end_date,omitempty"` // 格式 YYYY-MM-DD
|
||||
To string `json:"to,omitempty"` // 精确匹配收件人
|
||||
Keyword string `json:"keyword,omitempty"` // 模糊匹配主题/收件人
|
||||
}
|
||||
|
||||
// MailLogDetail 邮件日志详情,包含完整正文。
|
||||
type MailLogDetail struct {
|
||||
Log MailLog `json:"log"`
|
||||
Body string `json:"body"`
|
||||
Body string `json:"body"` // 邮件正文
|
||||
}
|
||||
|
||||
// MailStatItem 按状态分组的邮件计数,用于概览统计。
|
||||
type MailStatItem struct {
|
||||
Status int8 `json:"status"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
// --- Quota ---
|
||||
// ============================================================
|
||||
// Quota 配额
|
||||
// ============================================================
|
||||
|
||||
// MailQuota 配额记录。
|
||||
// - QuotaType=1 总量:Total 为生命周期内的总配额
|
||||
// - QuotaType=2 周期:每个 CycleUnit 周期重置 Used
|
||||
type MailQuota struct {
|
||||
GormModel
|
||||
UserID int `json:"user_id"`
|
||||
AccountID uint `json:"account_id"`
|
||||
QuotaType int8 `json:"quota_type"`
|
||||
QuotaType int8 `json:"quota_type"` // 1=总量 2=周期
|
||||
Total int `json:"total"`
|
||||
Used int `json:"used"`
|
||||
ExpireAt *time.Time `json:"expire_at"`
|
||||
CycleUnit string `json:"cycle_unit"`
|
||||
CycleResetAt *time.Time `json:"cycle_reset_at"`
|
||||
Status int8 `json:"status"`
|
||||
ExpireAt *time.Time `json:"expire_at"` // 到期时间,仅总量配额有意义
|
||||
CycleUnit string `json:"cycle_unit"` // day/week/month/year
|
||||
CycleResetAt *time.Time `json:"cycle_reset_at"` // 周期起始时间
|
||||
Status int8 `json:"status"` // 0=禁用 1=启用
|
||||
}
|
||||
|
||||
// CreateQuotaReq 创建配额。
|
||||
type CreateQuotaReq struct {
|
||||
AccountID uint `json:"account_id"`
|
||||
QuotaType int8 `json:"quota_type"`
|
||||
Total int `json:"total"`
|
||||
ExpireAt string `json:"expire_at,omitempty"`
|
||||
CycleUnit string `json:"cycle_unit,omitempty"`
|
||||
CycleResetAt string `json:"cycle_reset_at,omitempty"`
|
||||
AccountID uint `json:"account_id"` // 必填
|
||||
QuotaType int8 `json:"quota_type"` // 必填,1=总量 2=周期
|
||||
Total int `json:"total"` // 必填,配额上限
|
||||
ExpireAt string `json:"expire_at,omitempty"` // YYYY-MM-DD HH:mm:ss
|
||||
CycleUnit string `json:"cycle_unit,omitempty"` // day/week/month/year
|
||||
CycleResetAt string `json:"cycle_reset_at,omitempty"` // 周期起点
|
||||
}
|
||||
|
||||
// UpdateQuotaReq 局部更新配额。
|
||||
type UpdateQuotaReq struct {
|
||||
Total *int `json:"total,omitempty"`
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
@@ -228,6 +284,7 @@ type UpdateQuotaReq struct {
|
||||
CycleResetAt *string `json:"cycle_reset_at,omitempty"`
|
||||
}
|
||||
|
||||
// QuotaListQuery 配额列表过滤参数。
|
||||
type QuotaListQuery struct {
|
||||
PaginationQuery
|
||||
AccountID *uint `json:"account_id,omitempty"`
|
||||
@@ -235,32 +292,38 @@ type QuotaListQuery struct {
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// QuotaSummary 指定账号的配额汇总信息。
|
||||
type QuotaSummary struct {
|
||||
AccountID uint `json:"account_id"`
|
||||
TotalQuota int `json:"total_quota"`
|
||||
TotalUsed int `json:"total_used"`
|
||||
TotalRemaining int `json:"total_remaining"`
|
||||
Details []MailQuota `json:"details"`
|
||||
TotalQuota int `json:"total_quota"` // 所有配额累加总量
|
||||
TotalUsed int `json:"total_used"` // 已用
|
||||
TotalRemaining int `json:"total_remaining"` // 剩余
|
||||
Details []MailQuota `json:"details"` // 每条配额明细
|
||||
}
|
||||
|
||||
// --- Channel ---
|
||||
// ============================================================
|
||||
// Channel 通道
|
||||
// ============================================================
|
||||
|
||||
// Channel 发件通道,一个通道下可挂多个 SenderAccount,由 Strategy 决定分发逻辑。
|
||||
type Channel struct {
|
||||
GormModel
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Code string `json:"code"` // 唯一标识,发件请求中 channel 字段填这个
|
||||
Description string `json:"description"`
|
||||
Strategy string `json:"strategy"`
|
||||
Status int8 `json:"status"`
|
||||
Strategy string `json:"strategy"` // round_robin / weight / least_used
|
||||
Status int8 `json:"status"` // 0=禁用 1=启用
|
||||
}
|
||||
|
||||
// CreateChannelReq 创建通道。
|
||||
type CreateChannelReq struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"` // 必填
|
||||
Code string `json:"code"` // 必填,唯一
|
||||
Description string `json:"description,omitempty"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
Strategy string `json:"strategy,omitempty"` // 默认 round_robin
|
||||
}
|
||||
|
||||
// UpdateChannelReq 局部更新通道。
|
||||
type UpdateChannelReq struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
@@ -268,14 +331,18 @@ type UpdateChannelReq struct {
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// ChannelListQuery 通道列表过滤参数。
|
||||
type ChannelListQuery struct {
|
||||
PaginationQuery
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"` // 模糊匹配 name / code
|
||||
}
|
||||
|
||||
// --- Sender Account ---
|
||||
// ============================================================
|
||||
// SenderAccount 发信账号(SMTP)
|
||||
// ============================================================
|
||||
|
||||
// SenderAccount 挂在某个 Channel 下的 SMTP 发信账号。
|
||||
type SenderAccount struct {
|
||||
GormModel
|
||||
ChannelID uint `json:"channel_id"`
|
||||
@@ -286,27 +353,29 @@ type SenderAccount struct {
|
||||
SmtpSSL bool `json:"smtp_ssl"`
|
||||
FromName string `json:"from_name"`
|
||||
FromAddress string `json:"from_address"`
|
||||
DailyLimit int `json:"daily_limit"`
|
||||
DailySent int `json:"daily_sent"`
|
||||
Weight int `json:"weight"`
|
||||
Status int8 `json:"status"`
|
||||
DailyLimit int `json:"daily_limit"` // 每日发送上限,0=不限
|
||||
DailySent int `json:"daily_sent"` // 当日已发送数
|
||||
Weight int `json:"weight"` // Strategy=weight 时使用
|
||||
Status int8 `json:"status"` // 0=禁用 1=启用
|
||||
LastCheckAt *time.Time `json:"last_check_at"`
|
||||
LastCheckResult string `json:"last_check_result"`
|
||||
}
|
||||
|
||||
// CreateSenderReq 创建发信账号。Password 只存密文,不会回显。
|
||||
type CreateSenderReq struct {
|
||||
Name string `json:"name"`
|
||||
SmtpHost string `json:"smtp_host"`
|
||||
SmtpPort int `json:"smtp_port"`
|
||||
SmtpUser string `json:"smtp_user"`
|
||||
SmtpPassword string `json:"smtp_password"`
|
||||
Name string `json:"name"` // 必填
|
||||
SmtpHost string `json:"smtp_host"` // 必填
|
||||
SmtpPort int `json:"smtp_port"` // 必填
|
||||
SmtpUser string `json:"smtp_user"` // 必填
|
||||
SmtpPassword string `json:"smtp_password"` // 必填
|
||||
SmtpSSL *bool `json:"smtp_ssl,omitempty"`
|
||||
FromName string `json:"from_name,omitempty"`
|
||||
FromAddress string `json:"from_address"`
|
||||
FromAddress string `json:"from_address"` // 必填
|
||||
DailyLimit *int `json:"daily_limit,omitempty"`
|
||||
Weight *int `json:"weight,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateSenderReq 局部更新发信账号。
|
||||
type UpdateSenderReq struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
SmtpHost *string `json:"smtp_host,omitempty"`
|
||||
@@ -321,91 +390,108 @@ type UpdateSenderReq struct {
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// SenderListQuery 发信账号列表过滤参数。
|
||||
type SenderListQuery struct {
|
||||
PaginationQuery
|
||||
Status *int8 `json:"status,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"`
|
||||
}
|
||||
|
||||
// --- Audit ---
|
||||
// ============================================================
|
||||
// Audit 审核
|
||||
// ============================================================
|
||||
|
||||
// MailAudit 邮件审核记录。
|
||||
type MailAudit struct {
|
||||
GormModel
|
||||
MailLogID uint `json:"mail_log_id"`
|
||||
UserID int `json:"user_id"`
|
||||
AccountID uint `json:"account_id"`
|
||||
AuditType int8 `json:"audit_type"`
|
||||
Action int8 `json:"action"`
|
||||
AuditType int8 `json:"audit_type"` // 1=自动 2=人工
|
||||
Action int8 `json:"action"` // 1=通过 2=驳回
|
||||
RejectReason string `json:"reject_reason"`
|
||||
HitRules string `json:"hit_rules"`
|
||||
HitRules string `json:"hit_rules"` // 命中规则列表 JSON
|
||||
Auditor string `json:"auditor"`
|
||||
AuditedAt time.Time `json:"audited_at"`
|
||||
}
|
||||
|
||||
// AuditPendingQuery 待审核列表过滤参数。
|
||||
type AuditPendingQuery struct {
|
||||
PaginationQuery
|
||||
UserID *int `json:"user_id,omitempty"`
|
||||
AccountID *uint `json:"account_id,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"`
|
||||
Keyword string `json:"keyword,omitempty"` // 模糊匹配主题/收件人
|
||||
}
|
||||
|
||||
// AuditLogQuery 审核记录列表过滤参数。
|
||||
type AuditLogQuery struct {
|
||||
PaginationQuery
|
||||
AuditType *int8 `json:"audit_type,omitempty"`
|
||||
Action *int8 `json:"action,omitempty"`
|
||||
AuditType *int8 `json:"audit_type,omitempty"` // 1=自动 2=人工
|
||||
Action *int8 `json:"action,omitempty"` // 1=通过 2=驳回
|
||||
UserID *int `json:"user_id,omitempty"`
|
||||
StartDate string `json:"start_date,omitempty"`
|
||||
EndDate string `json:"end_date,omitempty"`
|
||||
StartDate string `json:"start_date,omitempty"` // YYYY-MM-DD
|
||||
EndDate string `json:"end_date,omitempty"` // YYYY-MM-DD
|
||||
}
|
||||
|
||||
// AuditRejectReq 驳回审核请求体。
|
||||
type AuditRejectReq struct {
|
||||
RejectReason string `json:"reject_reason"`
|
||||
RejectReason string `json:"reject_reason"` // 建议填写驳回原因
|
||||
}
|
||||
|
||||
// BatchAuditApproveReq 批量通过请求体。
|
||||
type BatchAuditApproveReq struct {
|
||||
MailLogIDs []uint `json:"mail_log_ids"`
|
||||
}
|
||||
|
||||
// BatchAuditRejectReq 批量驳回请求体。
|
||||
type BatchAuditRejectReq struct {
|
||||
MailLogIDs []uint `json:"mail_log_ids"`
|
||||
RejectReason string `json:"reject_reason"`
|
||||
}
|
||||
|
||||
// AuditStats 审核概览统计(用于仪表盘)。
|
||||
type AuditStats struct {
|
||||
PendingCount int64 `json:"pending_count"`
|
||||
TodayDetails []AuditDetailCount `json:"today_details"`
|
||||
PendingCount int64 `json:"pending_count"` // 待审核数量
|
||||
TodayDetails []AuditDetailCount `json:"today_details"` // 今日按 type/action 分组
|
||||
}
|
||||
|
||||
// AuditDetailCount 按 AuditType+Action 分组的计数。
|
||||
type AuditDetailCount struct {
|
||||
AuditType int8 `json:"audit_type"`
|
||||
Action int8 `json:"action"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
// --- Audit Rule ---
|
||||
// ============================================================
|
||||
// AuditRule 审核规则
|
||||
// ============================================================
|
||||
|
||||
// AuditRule 审核规则。自动审核会按 Priority 从高到低依次评估,
|
||||
// 命中即返回 Action。
|
||||
type AuditRule struct {
|
||||
GormModel
|
||||
Name string `json:"name"`
|
||||
RuleType string `json:"rule_type"`
|
||||
Target string `json:"target"`
|
||||
Condition string `json:"condition"`
|
||||
Action int8 `json:"action"`
|
||||
Priority int `json:"priority"`
|
||||
Status int8 `json:"status"`
|
||||
RuleType string `json:"rule_type"` // keyword/regex/domain
|
||||
Target string `json:"target"` // subject/body/to/from
|
||||
Condition string `json:"condition"` // 关键词或正则
|
||||
Action int8 `json:"action"` // 1=自动通过 2=自动驳回 3=转人工
|
||||
Priority int `json:"priority"` // 数字越大优先级越高
|
||||
Status int8 `json:"status"` // 0=禁用 1=启用
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// CreateAuditRuleReq 创建规则。
|
||||
type CreateAuditRuleReq struct {
|
||||
Name string `json:"name"`
|
||||
RuleType string `json:"rule_type"`
|
||||
Target string `json:"target"`
|
||||
Condition string `json:"condition"`
|
||||
Action int8 `json:"action"`
|
||||
Name string `json:"name"` // 必填
|
||||
RuleType string `json:"rule_type"` // 必填,keyword/regex/domain
|
||||
Target string `json:"target"` // 必填,subject/body/to/from
|
||||
Condition string `json:"condition"` // 必填
|
||||
Action int8 `json:"action"` // 必填,1/2/3
|
||||
Priority *int `json:"priority,omitempty"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateAuditRuleReq 局部更新规则。
|
||||
type UpdateAuditRuleReq struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
RuleType *string `json:"rule_type,omitempty"`
|
||||
@@ -417,6 +503,7 @@ type UpdateAuditRuleReq struct {
|
||||
Remark *string `json:"remark,omitempty"`
|
||||
}
|
||||
|
||||
// TestAuditRuleReq 在不发送邮件的前提下测试规则命中情况。
|
||||
type TestAuditRuleReq struct {
|
||||
Subject string `json:"subject,omitempty"`
|
||||
Body string `json:"body,omitempty"`
|
||||
@@ -425,24 +512,32 @@ type TestAuditRuleReq struct {
|
||||
AccountID uint `json:"account_id,omitempty"`
|
||||
}
|
||||
|
||||
// TestAuditRuleResp 规则测试结果。
|
||||
type TestAuditRuleResp struct {
|
||||
Action string `json:"action"`
|
||||
HitRules []HitRuleEntry `json:"hit_rules"`
|
||||
Action string `json:"action"` // approve/reject/to_manual/none
|
||||
HitRules []HitRuleEntry `json:"hit_rules"` // 命中的规则列表
|
||||
}
|
||||
|
||||
// HitRuleEntry 命中规则信息。
|
||||
type HitRuleEntry struct {
|
||||
RuleID uint `json:"rule_id"`
|
||||
RuleName string `json:"rule_name"`
|
||||
RuleType string `json:"rule_type"`
|
||||
}
|
||||
|
||||
// --- Queue ---
|
||||
// ============================================================
|
||||
// Queue 发送队列
|
||||
// ============================================================
|
||||
|
||||
// QueueStatusData 队列状态快照。
|
||||
// - Queues: key = 通道 code, value = 该通道排队长度
|
||||
// - DelayQueue: 延迟重试队列长度
|
||||
type QueueStatusData struct {
|
||||
Queues map[string]int `json:"queues"`
|
||||
DelayQueue int `json:"delay_queue"`
|
||||
}
|
||||
|
||||
// QueuePendingQuery 队列待发送邮件过滤参数。
|
||||
type QueuePendingQuery struct {
|
||||
PaginationQuery
|
||||
ChannelID *uint `json:"channel_id,omitempty"`
|
||||
@@ -450,20 +545,25 @@ type QueuePendingQuery struct {
|
||||
AccountID *uint `json:"account_id,omitempty"`
|
||||
}
|
||||
|
||||
// --- Check ---
|
||||
// ============================================================
|
||||
// Check 健康检查
|
||||
// ============================================================
|
||||
|
||||
// CheckLog 发信账号健康检查记录。
|
||||
// 通过向 verification 地址发测试邮件并等待 webhook 回调验证收信可用性。
|
||||
type CheckLog struct {
|
||||
ID uint `json:"id"`
|
||||
SenderAccountID uint `json:"sender_account_id"`
|
||||
VerificationCode string `json:"verification_code"`
|
||||
SentAt time.Time `json:"sent_at"`
|
||||
Received bool `json:"received"`
|
||||
Received bool `json:"received"` // 是否收到回执
|
||||
ReceivedAt *time.Time `json:"received_at"`
|
||||
LatencyMs int `json:"latency_ms"`
|
||||
LatencyMs int `json:"latency_ms"` // 端到端延迟,毫秒
|
||||
ErrorMessage string `json:"error_message"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// CheckLogQuery 健康检查日志过滤参数。
|
||||
type CheckLogQuery struct {
|
||||
PaginationQuery
|
||||
SenderAccountID *uint `json:"sender_account_id,omitempty"`
|
||||
@@ -471,6 +571,7 @@ type CheckLogQuery struct {
|
||||
EndDate string `json:"end_date,omitempty"`
|
||||
}
|
||||
|
||||
// SenderHealth 发信账号健康汇总。
|
||||
type SenderHealth struct {
|
||||
SenderAccountID uint `json:"sender_account_id"`
|
||||
Name string `json:"name"`
|
||||
@@ -481,8 +582,9 @@ type SenderHealth struct {
|
||||
SuccessChecks int64 `json:"success_checks"`
|
||||
}
|
||||
|
||||
// TriggerCheckResp 手动触发健康检查的返回。
|
||||
type TriggerCheckResp struct {
|
||||
Result string `json:"result"`
|
||||
Result string `json:"result"` // ok / failed
|
||||
Error string `json:"error,omitempty"`
|
||||
CheckLog *CheckLog `json:"check_log,omitempty"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user