Files
TakeoutSaaS.TenantUI/apps/web-antd/src/views/member/message-reach/components/MessageReachTableCard.vue

222 lines
5.7 KiB
Vue

<script setup lang="ts">
import type { TableColumnType } from 'ant-design-vue';
import type {
MemberMessageReachChannel,
MemberMessageReachListItemDto,
MemberMessageReachStatus,
} from '#/api/member/message-reach';
import type { MessageReachPager } from '#/views/member/message-reach/types';
import { Button, Pagination, Table, Tag } from 'ant-design-vue';
import {
formatInteger,
formatPercent,
MESSAGE_CHANNEL_COLOR_MAP,
MESSAGE_CHANNEL_TEXT_MAP,
MESSAGE_STATUS_COLOR_MAP,
MESSAGE_STATUS_TEXT_MAP,
resolveMessageTime,
} from '../composables/message-reach-page/helpers';
defineProps<{
canManage: boolean;
loading: boolean;
pager: MessageReachPager;
}>();
const emit = defineEmits<{
(event: 'delete', messageId: string): void;
(event: 'detail', messageId: string): void;
(event: 'edit', messageId: string): void;
(event: 'pageChange', page: number, pageSize: number): void;
}>();
const columns: TableColumnType<MemberMessageReachListItemDto>[] = [
{
title: '消息标题',
dataIndex: 'title',
key: 'title',
width: 280,
},
{
title: '推送渠道',
dataIndex: 'channels',
key: 'channels',
width: 180,
},
{
title: '目标人群',
dataIndex: 'audienceText',
key: 'audienceText',
width: 170,
},
{
title: '触达人数',
dataIndex: 'estimatedReachCount',
key: 'estimatedReachCount',
width: 120,
},
{
title: '发送时间',
key: 'sendTime',
width: 180,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 120,
},
{
title: '操作',
key: 'action',
fixed: 'right',
width: 180,
},
];
function showMetricRow(record: Record<string, any>) {
return (
Number(record.openRate || 0) > 0 || Number(record.conversionRate || 0) > 0
);
}
function resolveChannelColor(channel: unknown) {
return (
MESSAGE_CHANNEL_COLOR_MAP[channel as MemberMessageReachChannel] || 'default'
);
}
function resolveChannelText(channel: unknown) {
return (
MESSAGE_CHANNEL_TEXT_MAP[channel as MemberMessageReachChannel] || '未知渠道'
);
}
function resolveStatusColor(status: unknown) {
return MESSAGE_STATUS_COLOR_MAP[status as MemberMessageReachStatus];
}
function resolveStatusText(status: unknown) {
return MESSAGE_STATUS_TEXT_MAP[status as MemberMessageReachStatus];
}
function canEdit(status: unknown) {
const currentStatus = status as MemberMessageReachStatus;
return currentStatus === 'draft' || currentStatus === 'failed';
}
function canDelete(status: unknown) {
const currentStatus = status as MemberMessageReachStatus;
return (
currentStatus === 'draft' ||
currentStatus === 'failed' ||
currentStatus === 'pending'
);
}
</script>
<template>
<div class="mmr-table-wrap">
<Table
:columns="columns"
:data-source="pager.items"
:loading="loading"
:pagination="false"
row-key="messageId"
:scroll="{ x: 1080 }"
class="mmr-table"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'title'">
<div class="mmr-message-title">{{ record.title }}</div>
<div v-if="showMetricRow(record)" class="mmr-message-metric">
打开率 {{ formatPercent(record.openRate) }} | 转化率
{{ formatPercent(record.conversionRate) }}
</div>
</template>
<template v-else-if="column.key === 'channels'">
<div class="mmr-channel-list">
<Tag
v-for="item in record.channels"
:key="`${record.messageId}-${item}`"
:color="resolveChannelColor(item)"
>
{{ resolveChannelText(item) }}
</Tag>
</div>
</template>
<template v-else-if="column.key === 'estimatedReachCount'">
<span>
{{
record.estimatedReachCount > 0
? formatInteger(record.estimatedReachCount)
: '—'
}}
</span>
</template>
<template v-else-if="column.key === 'sendTime'">
<span class="mmr-time-text">
{{ resolveMessageTime(record.sentAt, record.scheduledAt) }}
</span>
</template>
<template v-else-if="column.key === 'status'">
<Tag :color="resolveStatusColor(record.status)">
{{ resolveStatusText(record.status) }}
</Tag>
</template>
<template v-else-if="column.key === 'action'">
<div class="mmr-table-actions">
<Button
type="link"
size="small"
class="mmr-action-link"
@click="emit('detail', record.messageId)"
>
详情
</Button>
<Button
v-if="canManage && canEdit(record.status)"
type="link"
size="small"
class="mmr-action-link"
@click="emit('edit', record.messageId)"
>
编辑
</Button>
<Button
v-if="canManage && canDelete(record.status)"
type="link"
size="small"
danger
class="mmr-action-link"
@click="emit('delete', record.messageId)"
>
删除
</Button>
</div>
</template>
</template>
</Table>
<div class="mmr-pagination">
<Pagination
:current="pager.page"
:page-size="pager.pageSize"
:total="pager.totalCount"
show-size-changer
:show-total="(value) => `${value}`"
:page-size-options="['10', '20', '50']"
@change="(page, pageSize) => emit('pageChange', page, pageSize)"
/>
</div>
</div>
</template>