265 lines
7.2 KiB
TypeScript
265 lines
7.2 KiB
TypeScript
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<MemberMessageReachTabKey>;
|
|
audienceEstimateCount: Ref<number>;
|
|
canManage: Ref<boolean>;
|
|
detail: Ref<MessageReachDetailViewModel | null>;
|
|
detailDrawerMessageId: Ref<string>;
|
|
form: MessageReachEditorForm;
|
|
isDetailDrawerOpen: Ref<boolean>;
|
|
isMessageDrawerOpen: Ref<boolean>;
|
|
isMessageSubmitting: Ref<boolean>;
|
|
messageDrawerMode: Ref<'create' | 'edit'>;
|
|
loadMessageDetail: (
|
|
messageId: string,
|
|
) => Promise<MessageReachDetailViewModel | null>;
|
|
loadMessageList: () => Promise<void>;
|
|
loadStats: () => Promise<void>;
|
|
}
|
|
|
|
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,
|
|
};
|
|
}
|