import { axiosInstance } from '@/api/rbac' import { assertBusinessOk, omsUrl, unwrapData } from '@/api/oms/common' /** 与桌面版 emailAuto.py 一致:阿里企业邮等 */ export type BatchEmailServerType = 'qiye' | 'qiye_ssl' | 'aliyun' | 'aliyun_ssl' | 'mxhichina' /** 与后端 BatchEmailSmtpHelper.SecretMask 一致,用于线上已保存密码占位 */ export const SMTP_SECRET_MASK = '******' export function isSmtpSecretMask(value?: string | null): boolean { return String(value ?? '').trim() === SMTP_SECRET_MASK } export interface BatchEmailTemplate { name: string subject: string content: string } export interface BatchEmailAccount { smtpUsername: string smtpPassword: string serverType: BatchEmailServerType fromName?: string } export interface BatchEmailSendOneBody { smtpUsername: string smtpPassword: string serverType?: BatchEmailServerType to: string subject: string body: string bodyType?: 'plain' | 'html' fromName?: string } function pickStr(row: Record, ...keys: string[]) { for (const key of keys) { const val = row[key] if (val != null && String(val).trim() !== '') return String(val).trim() } return '' } function normalizeTemplate(raw: unknown): BatchEmailTemplate | null { if (raw == null || typeof raw !== 'object') return null const row = raw as Record const name = pickStr(row, 'name', 'Name') if (!name) return null return { name, subject: pickStr(row, 'subject', 'Subject') || name, content: pickStr(row, 'content', 'Content'), } } function normalizeAccount(raw: unknown): BatchEmailAccount | null { if (raw == null || typeof raw !== 'object') return null const row = raw as Record const smtpUsername = pickStr(row, 'smtpUsername', 'SmtpUsername') if (!smtpUsername) return null const serverType = (pickStr(row, 'serverType', 'ServerType') || 'qiye') as BatchEmailServerType return { smtpUsername, smtpPassword: pickStr(row, 'smtpPassword', 'SmtpPassword'), serverType, fromName: pickStr(row, 'fromName', 'FromName') || undefined, } } export interface BatchEmailSendRecord { id: number toEmail: string subject: string content: string sendTime: string sender: string } function normalizeRecord(raw: unknown): BatchEmailSendRecord | null { if (raw == null || typeof raw !== 'object') return null const row = raw as Record const id = Number(row.id ?? row.Id) if (!Number.isFinite(id)) return null return { id, toEmail: pickStr(row, 'toEmail', 'ToEmail'), subject: pickStr(row, 'subject', 'Subject'), content: pickStr(row, 'content', 'Content'), sendTime: pickStr(row, 'sendTime', 'SendTime'), sender: pickStr(row, 'sender', 'Sender'), } } function unwrapPageResult(resBody: unknown): { items: unknown[]; total: number } { assertBusinessOk(resBody) const root = (resBody as Record) ?? {} const inner = (root.data ?? root.Data ?? root) as Record const items = inner.items ?? inner.Items ?? inner.list ?? inner.List ?? [] const total = Number(inner.total ?? inner.Total ?? inner.totalCount ?? inner.TotalCount ?? 0) return { items: Array.isArray(items) ? items : [], total: Number.isFinite(total) ? total : 0, } } function unwrapList(resBody: unknown): unknown[] { assertBusinessOk(resBody) const root = (resBody as Record) ?? {} const inner = root.data ?? root.Data ?? root if (Array.isArray(inner)) return inner return unwrapPageResult(resBody).items } /** GET /system/batch-email/account */ export async function getBatchEmailAccount(): Promise { const res = await axiosInstance.get(omsUrl('/system/batch-email/account')) const raw = unwrapData | null>(res.data) return raw ? normalizeAccount(raw) : null } /** GET /system/batch-email/templates/list */ export async function listBatchEmailTemplates(): Promise { const res = await axiosInstance.get(omsUrl('/system/batch-email/templates/list')) return unwrapList(res.data) .map(normalizeTemplate) .filter((item): item is BatchEmailTemplate => item != null) } /** POST /system/batch-email/templates/save */ export async function saveBatchEmailTemplate(body: { name: string subject: string content: string }) { const res = await axiosInstance.post(omsUrl('/system/batch-email/templates/save'), body) assertBusinessOk(res.data) } /** POST /system/batch-email/templates/delete */ export async function deleteBatchEmailTemplate(body: { name: string }) { const res = await axiosInstance.post(omsUrl('/system/batch-email/templates/delete'), body) assertBusinessOk(res.data) } /** POST /system/batch-email/account/save */ export async function saveBatchEmailAccount(body: BatchEmailAccount) { const res = await axiosInstance.post(omsUrl('/system/batch-email/account/save'), body) assertBusinessOk(res.data) } /** POST /system/batch-email/test-connection — 验证 SMTP 账号 */ export async function testBatchEmailConnection(body: { smtpUsername: string smtpPassword: string serverType?: BatchEmailServerType fromName?: string }) { const res = await axiosInstance.post(omsUrl('/system/batch-email/test-connection'), body) assertBusinessOk(res.data) } /** POST /system/batch-email/send-one — 发送单封(批量时由前端循环调用,便于逐条写日志) */ export async function sendBatchEmailOne(body: BatchEmailSendOneBody) { const res = await axiosInstance.post(omsUrl('/system/batch-email/send-one'), body) assertBusinessOk(res.data) } /** GET /system/batch-email/records/list */ export async function listBatchEmailRecords(params?: { page?: number; pageSize?: number }) { const res = await axiosInstance.get(omsUrl('/system/batch-email/records/list'), { params }) const page = unwrapPageResult(res.data) return { items: page.items .map(normalizeRecord) .filter((item): item is BatchEmailSendRecord => item != null), total: page.total, } }