refactor: mp export

This commit is contained in:
xingyu4j
2025-11-07 17:58:24 +08:00
parent 51169116ae
commit 31a8d38174
37 changed files with 54 additions and 59 deletions

View File

@@ -0,0 +1,140 @@
<!--
- Copyright (C) 2018-2019
- All rights reserved, Designed By www.joolun.com
芋道源码
移除多余的 rep 为前缀的变量 message 消息更简单
代码优化补充注释提升阅读性
优化消息的临时缓存策略发送消息时只清理被发送消息的 tab不会强制切回到 text 输入
支持发送视频消息时支持新建视频
-->
<script lang="ts" setup>
import type { Reply } from './types';
import { computed, ref, unref, watch } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { Row, Tabs } from 'ant-design-vue';
import TabImage from './tab-image.vue';
import TabMusic from './tab-music.vue';
import TabNews from './tab-news.vue';
import TabText from './tab-text.vue';
import TabVideo from './tab-video.vue';
import TabVoice from './tab-voice.vue';
import { createEmptyReply, NewsType, ReplyType } from './types';
defineOptions({ name: 'WxReplySelect' });
const props = withDefaults(
defineProps<{
modelValue: Reply;
newsType?: NewsType;
}>(),
{
newsType: () => NewsType.Published,
},
);
const emit = defineEmits<{
(e: 'update:modelValue', v: Reply): void;
}>();
const reply = computed<Reply>({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val),
});
// 作为多个标签保存各自Reply的缓存
const tabCache = new Map<ReplyType, Reply>();
// 采用独立的ref来保存当前tab避免在watch标签变化对reply进行赋值会产生了循环调用
const currentTab = ref<ReplyType>(props.modelValue.type || ReplyType.Text);
watch(
currentTab,
(newTab, oldTab) => {
// 第一次进入oldTab 为 undefined
// 判断 newTab 是因为 Reply 为 Partial
if (oldTab === undefined || newTab === undefined) {
return;
}
tabCache.set(oldTab, unref(reply));
// 从缓存里面取出新tab内容有则覆盖Reply没有则创建空Reply
const temp = tabCache.get(newTab);
if (temp) {
reply.value = temp;
} else {
const newData = createEmptyReply(reply);
newData.type = newTab;
reply.value = newData;
}
},
{
immediate: true,
},
);
/** 清除除了`type`, `accountId`的字段 */
function clear() {
reply.value = createEmptyReply(reply);
}
defineExpose({
clear,
});
</script>
<template>
<Tabs v-model:active-key="currentTab" type="card">
<!-- 类型 1文本 -->
<Tabs.TabPane :key="ReplyType.Text">
<template #tab>
<Row align="middle"><IconifyIcon icon="ep:document" /> 文本</Row>
</template>
<TabText v-model="reply.content" />
</Tabs.TabPane>
<!-- 类型 2图片 -->
<Tabs.TabPane :key="ReplyType.Image">
<template #tab>
<Row align="middle">
<IconifyIcon icon="ep:picture" class="mr-5px" /> 图片
</Row>
</template>
<TabImage v-model="reply" />
</Tabs.TabPane>
<!-- 类型 3语音 -->
<Tabs.TabPane :key="ReplyType.Voice">
<template #tab>
<Row align="middle"><IconifyIcon icon="ep:phone" /> 语音</Row>
</template>
<TabVoice v-model="reply" />
</Tabs.TabPane>
<!-- 类型 4视频 -->
<Tabs.TabPane :key="ReplyType.Video">
<template #tab>
<Row align="middle"><IconifyIcon icon="ep:share" /> 视频</Row>
</template>
<TabVideo v-model="reply" />
</Tabs.TabPane>
<!-- 类型 5图文 -->
<Tabs.TabPane :key="ReplyType.News">
<template #tab>
<Row align="middle"><IconifyIcon icon="ep:reading" /> 图文</Row>
</template>
<TabNews v-model="reply" :news-type="newsType" />
</Tabs.TabPane>
<!-- 类型 6音乐 -->
<Tabs.TabPane :key="ReplyType.Music">
<template #tab>
<Row align="middle"><IconifyIcon icon="ep:service" />音乐</Row>
</template>
<TabMusic v-model="reply" />
</Tabs.TabPane>
</Tabs>
</template>
<style lang="scss" scoped></style>