fix: todo 处理

This commit is contained in:
dylanmay
2025-12-05 11:00:48 +08:00
parent 5a6122ab75
commit 5bae28516c
16 changed files with 792 additions and 908 deletions

View File

@@ -1,185 +1,228 @@
<script lang="ts" setup>
import type { Dayjs } from 'dayjs';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MpMessageApi } from '#/api/mp/message';
import { reactive, ref } from 'vue';
import { ref } from 'vue';
import { Page } from '@vben/common-ui';
import { DICT_TYPE, MpMsgType } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import { MpMsgType as MsgType } from '@vben/constants';
import { formatDate2 } from '@vben/utils';
import {
Button,
DatePicker,
Form,
FormItem,
Input,
Modal,
Pagination,
Select,
} from 'ant-design-vue';
import { Image, Modal, Tag } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getMessagePage } from '#/api/mp/message';
import { WxAccountSelect, WxMsg } from '#/views/mp/components';
import {
WxAccountSelect,
WxLocation,
WxMsg,
WxMusic,
WxNews,
WxVideoPlayer,
WxVoicePlayer,
} from '#/views/mp/components';
import MessageTable from './message-table.vue';
import { useGridColumns, useGridFormSchema } from './data';
defineOptions({ name: 'MpMessage' });
const loading = ref(false);
const total = ref(0); // 数据的总页数
const list = ref<any[]>([]); // 当前页的列表数据
const queryParams = reactive<{
accountId: number;
createTime: [Dayjs, Dayjs] | undefined;
openid: string;
pageNo: number;
pageSize: number;
type: string;
}>({
accountId: -1,
createTime: undefined,
openid: '',
pageNo: 1,
pageSize: 10,
type: MpMsgType.Text,
}); // 搜索参数
const queryFormRef = ref(); // 搜索的表单
// 消息对话框
const messageBoxVisible = ref(false);
const messageBoxUserId = ref(0);
/** 侦听 accountId */
function onAccountChanged(id: number) {
queryParams.accountId = id;
queryParams.pageNo = 1;
handleQuery();
}
/** 查询列表 */
function handleQuery() {
queryParams.pageNo = 1;
getList();
}
async function getList() {
try {
loading.value = true;
const data = await getMessagePage(queryParams);
list.value = data.list;
total.value = data.total;
} finally {
loading.value = false;
}
}
/** 重置按钮操作 */
async function resetQuery() {
// 暂存 accountId并在 reset 后恢复
const accountId = queryParams.accountId;
queryFormRef.value?.resetFields();
queryParams.accountId = accountId;
handleQuery();
/** 公众号变化时查询数据 */
function handleAccountChange(accountId: number) {
gridApi.formApi.setValues({ accountId });
gridApi.formApi.submitForm();
}
/** 打开消息发送窗口 */
async function handleSend(userId: number) {
function handleSend(userId: number) {
messageBoxUserId.value = userId;
messageBoxVisible.value = true;
}
/** 分页改变事件 */
function handlePageChange(page: number, pageSize: number) {
queryParams.pageNo = page;
queryParams.pageSize = pageSize;
getList();
}
/** 显示总条数 */
function showTotal(total: number) {
return `${total}`;
}
// TODO @dylan是不是应该都用 Grid 哈1message-table 大部分合并到 index.vue2message-table 的 schema 放到 data.ts 里;
const [Grid, gridApi] = useVbenVxeGrid<MpMessageApi.Message>({
formOptions: {
schema: useGridFormSchema(),
},
gridOptions: {
columns: useGridColumns(),
height: 'auto',
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getMessagePage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
autoLoad: false,
},
rowConfig: {
keyField: 'id',
isHover: true,
},
toolbarConfig: {
refresh: true,
search: true,
},
showOverflow: 'tooltip',
} as VxeTableGridOptions<MpMessageApi.Message>,
});
</script>
<template>
<Page auto-content-height class="flex flex-col">
<!-- 搜索工作栏 -->
<div class="mb-4 rounded-lg bg-background p-4">
<Form
ref="queryFormRef"
:model="queryParams"
layout="inline"
class="search-form"
>
<FormItem label="公众号" name="accountId">
<WxAccountSelect @change="onAccountChanged" />
</FormItem>
<FormItem label="消息类型" name="type">
<Select
v-model:value="queryParams.type"
placeholder="请选择消息类型"
class="!w-[240px]"
>
<Select.Option
v-for="dict in getDictOptions(DICT_TYPE.MP_MESSAGE_TYPE)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Select.Option>
</Select>
</FormItem>
<FormItem label="用户标识" name="openid">
<Input
v-model:value="queryParams.openid"
placeholder="请输入用户标识"
allow-clear
class="!w-[240px]"
/>
</FormItem>
<FormItem label="创建时间" name="createTime">
<DatePicker.RangePicker
v-model:value="queryParams.createTime"
:show-time="true"
class="!w-[240px]"
/>
</FormItem>
<FormItem>
<Button type="primary" @click="handleQuery">
<template #icon>
<IconifyIcon icon="mdi:magnify" />
</template>
搜索
</Button>
<Button class="ml-2" @click="resetQuery">
<template #icon>
<IconifyIcon icon="mdi:refresh" />
</template>
重置
</Button>
</FormItem>
</Form>
</div>
<Page auto-content-height>
<Grid>
<template #form-accountId>
<WxAccountSelect @change="handleAccountChange" />
</template>
<template #createTime="{ row }">
{{ row.createTime ? formatDate2(row.createTime) : '' }}
</template>
<!-- 列表 -->
<div class="flex-1 rounded-lg bg-background p-4">
<MessageTable :list="list" :loading="loading" @send="handleSend" />
<div v-show="total > 0" class="mt-4 flex justify-end">
<Pagination
v-model:current="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
:total="total"
show-size-changer
show-quick-jumper
:show-total="showTotal"
@change="handlePageChange"
<template #sendFrom="{ row }">
<Tag v-if="row.sendFrom === 1" color="success">粉丝</Tag>
<Tag v-else>公众号</Tag>
</template>
<template #content="{ row }">
<div
v-if="
(row.type as string) === (MsgType.Event as string) &&
(row.event as string) === 'subscribe'
"
>
<Tag color="success">关注</Tag>
</div>
<div
v-else-if="
(row.type as string) === (MsgType.Event as string) &&
(row.event as string) === 'unsubscribe'
"
>
<Tag color="error">取消关注</Tag>
</div>
<div
v-else-if="
(row.type as string) === (MsgType.Event as string) &&
(row.event as string) === 'CLICK'
"
>
<Tag>点击菜单</Tag>
【{{ row.eventKey }}】
</div>
<div v-else-if="row.type === MsgType.Event && row.event === 'VIEW'">
<Tag>点击菜单链接</Tag>
【{{ row.eventKey }}】
</div>
<div
v-else-if="
row.type === MsgType.Event && row.event === 'scancode_waitmsg'
"
>
<Tag>扫码结果</Tag>
【{{ row.eventKey }}】
</div>
<div
v-else-if="
row.type === MsgType.Event && row.event === 'scancode_push'
"
>
<Tag>扫码结果</Tag>
【{{ row.eventKey }}】
</div>
<div
v-else-if="row.type === MsgType.Event && row.event === 'pic_sysphoto'"
>
<Tag>系统拍照发图</Tag>
</div>
<div
v-else-if="
row.type === MsgType.Event && row.event === 'pic_photo_or_album'
"
>
<Tag>拍照或者相册</Tag>
</div>
<div
v-else-if="row.type === MsgType.Event && row.event === 'pic_weixin'"
>
<Tag>微信相册</Tag>
</div>
<div
v-else-if="
row.type === MsgType.Event && row.event === 'location_select'
"
>
<Tag>选择地理位置</Tag>
</div>
<div v-else-if="row.type === MsgType.Event">
<Tag color="error">未知事件类型</Tag>
</div>
<div v-else-if="row.type === MsgType.Text">{{ row.content }}</div>
<div v-else-if="row.type === MsgType.Voice">
<WxVoicePlayer
:url="row.mediaUrl || ''"
:content="row.recognition || ''"
/>
</div>
<div v-else-if="row.type === MsgType.Image">
<a :href="row.mediaUrl" target="_blank">
<Image :src="row.mediaUrl" :width="100" :preview="false" />
</a>
</div>
<div
v-else-if="row.type === MsgType.Video || row.type === 'shortvideo'"
>
<WxVideoPlayer :url="row.mediaUrl || ''" class="mt-2" />
</div>
<div v-else-if="row.type === MsgType.Link">
<Tag>链接</Tag>
<a :href="row.url" target="_blank">{{ row.title }}</a>
</div>
<div v-else-if="row.type === MsgType.Location">
<WxLocation
:label="row.label || ''"
:location-y="row.locationY || 0"
:location-x="row.locationX || 0"
/>
</div>
<div v-else-if="row.type === MsgType.Music">
<WxMusic
:title="row.title"
:description="row.description"
:thumb-media-url="row.thumbMediaUrl || ''"
:music-url="row.musicUrl"
:hq-music-url="row.hqMusicUrl"
/>
</div>
<div v-else-if="row.type === MsgType.News">
<WxNews :articles="row.articles" />
</div>
<div v-else>
<Tag color="error">未知消息类型</Tag>
</div>
</template>
<template #actions="{ row }">
<TableAction
:actions="[
{
label: '消息',
type: 'link',
icon: ACTION_ICON.VIEW,
onClick: () => handleSend(row.userId || 0),
},
]"
/>
</div>
</div>
</template>
</Grid>
<!-- 发送消息的弹窗 -->
<Modal
@@ -193,9 +236,3 @@ function showTotal(total: number) {
</Modal>
</Page>
</template>
<style scoped>
.search-form :deep(.ant-form-item) {
margin-bottom: 16px;
}
</style>