import type { Dayjs } from 'dayjs'; import type { Ref } from 'vue'; import type { MemberMessageTemplateDto, SaveMemberMessageReachPayload, } from '#/api/member/message-reach'; import type { MemberMessageReachTabKey, MessageReachDetailViewModel, MessageReachEditorForm, } from '#/views/member/message-reach/types'; import { message, Modal } from 'ant-design-vue'; import { deleteMemberMessageReachApi, saveMemberMessageReachApi, } from '#/api/member/message-reach'; import { mapDetailToEditorForm, mapMessageEditorFormToSavePayload, resetMessageEditorForm, toggleTag, } from './helpers'; interface CreateMessageActionsOptions { activeTab: Ref; audienceEstimateCount: Ref; canManage: Ref; detail: Ref; detailDrawerMessageId: Ref; form: MessageReachEditorForm; isDetailDrawerOpen: Ref; isMessageDrawerOpen: Ref; isMessageSubmitting: Ref; messageDrawerMode: Ref<'create' | 'edit'>; loadMessageDetail: ( messageId: string, ) => Promise; loadMessageList: () => Promise; loadStats: () => Promise; } export function createMessageActions(options: CreateMessageActionsOptions) { function setMessageDrawerOpen(value: boolean) { options.isMessageDrawerOpen.value = value; } function setMessageTitle(value: string) { options.form.title = value; } function setMessageContent(value: string) { options.form.content = value; } function setMessageChannel(channel: 'inapp' | 'sms' | 'wechat-mini') { if ( options.form.channels.length === 1 && options.form.channels[0] === channel ) { return; } options.form.channels = [channel]; } function setAudienceType(value: 'all' | 'tag') { options.form.audienceType = value; if (value === 'all') { options.form.audienceTags = []; } } function toggleAudienceTag(value: string) { options.form.audienceTags = toggleTag(options.form.audienceTags, value); } function setScheduleType(value: 'immediate' | 'scheduled') { options.form.scheduleType = value; if (value === 'immediate') { options.form.scheduledAt = null; } } function setScheduledAt(value: Dayjs | null) { options.form.scheduledAt = value; } function switchToTemplateTab() { options.activeTab.value = 'template'; options.isMessageDrawerOpen.value = false; } async function openCreateMessageDrawer() { if (!options.canManage.value) { return; } resetMessageEditorForm(options.form); options.audienceEstimateCount.value = 0; options.messageDrawerMode.value = 'create'; options.isMessageDrawerOpen.value = true; } async function openEditMessageDrawer(messageId: string) { if (!options.canManage.value) { return; } const detail = await options.loadMessageDetail(messageId); if (!detail) { return; } mapDetailToEditorForm(detail, options.form); options.audienceEstimateCount.value = detail.estimatedReachCount; options.messageDrawerMode.value = 'edit'; options.isMessageDrawerOpen.value = true; } async function openDetailDrawer(messageId: string) { options.detailDrawerMessageId.value = messageId; options.isDetailDrawerOpen.value = true; await options.loadMessageDetail(messageId); } async function refreshDetailIfNeeded(messageId: string) { if (!options.isDetailDrawerOpen.value) { return; } if (options.detailDrawerMessageId.value !== messageId) { return; } await options.loadMessageDetail(messageId); } function useTemplateToCreateMessage(template: MemberMessageTemplateDto) { if (!options.canManage.value) { return; } resetMessageEditorForm(options.form); options.form.templateId = template.templateId; options.form.title = template.name; options.form.content = template.content; options.audienceEstimateCount.value = 0; options.messageDrawerMode.value = 'create'; options.isMessageDrawerOpen.value = true; options.activeTab.value = 'list'; } function validateMessagePayload(payload: SaveMemberMessageReachPayload) { if (!payload.title) { message.warning('请输入消息标题'); return false; } if (!payload.content) { message.warning('请输入消息内容'); return false; } if (payload.channels.length === 0) { message.warning('请至少选择一个推送渠道'); return false; } if (payload.audienceType === 'tag' && payload.audienceTags.length === 0) { message.warning('请选择目标标签'); return false; } if (payload.scheduleType === 'scheduled' && !payload.scheduledAt) { message.warning('请选择定时发送时间'); return false; } return true; } async function submitMessage(submitAction: 'draft' | 'send') { if (!options.canManage.value) { return; } const payload = mapMessageEditorFormToSavePayload( options.form, submitAction, ); if (!validateMessagePayload(payload)) { return; } options.isMessageSubmitting.value = true; try { const result = await saveMemberMessageReachApi(payload); message.success( submitAction === 'send' ? '发送任务已提交' : '草稿已保存', ); options.isMessageDrawerOpen.value = false; await Promise.all([options.loadStats(), options.loadMessageList()]); await refreshDetailIfNeeded(result.messageId); } catch (error) { console.error(error); message.error(submitAction === 'send' ? '发送失败' : '保存草稿失败'); } finally { options.isMessageSubmitting.value = false; } } async function removeMessage(messageId: string) { if (!options.canManage.value) { return; } Modal.confirm({ title: '确认删除消息?', content: '删除后无法恢复,且会取消未执行的发送任务。', okText: '删除', okType: 'danger', cancelText: '取消', async onOk() { try { await deleteMemberMessageReachApi({ messageId }); message.success('删除成功'); if (options.detailDrawerMessageId.value === messageId) { options.isDetailDrawerOpen.value = false; options.detailDrawerMessageId.value = ''; options.detail.value = null; } await Promise.all([options.loadStats(), options.loadMessageList()]); } catch (error) { console.error(error); message.error('删除失败'); } }, }); } function setDetailDrawerOpen(value: boolean) { options.isDetailDrawerOpen.value = value; if (!value) { options.detailDrawerMessageId.value = ''; options.detail.value = null; } } return { openCreateMessageDrawer, openDetailDrawer, openEditMessageDrawer, removeMessage, setAudienceType, setDetailDrawerOpen, setMessageContent, setMessageDrawerOpen, setMessageChannel, setMessageTitle, setScheduleType, setScheduledAt, submitMessage, switchToTemplateTab, toggleAudienceTag, useTemplateToCreateMessage, }; }