chore: 合并远程 dev 分支代码
This commit is contained in:
32
apps/web-antd/src/views/mp/components/constants.ts
Normal file
32
apps/web-antd/src/views/mp/components/constants.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
export enum ReplyType {
|
||||
Image = 'image',
|
||||
Music = 'music',
|
||||
News = 'news',
|
||||
Text = 'text',
|
||||
Video = 'video',
|
||||
Voice = 'voice',
|
||||
}
|
||||
|
||||
export enum NewsType {
|
||||
Draft = '2',
|
||||
Published = '1',
|
||||
}
|
||||
|
||||
export enum MaterialType {
|
||||
Image = 'image',
|
||||
News = 'news',
|
||||
Video = 'video',
|
||||
Voice = 'voice',
|
||||
}
|
||||
|
||||
export enum MsgType {
|
||||
Event = 'event',
|
||||
Image = 'image',
|
||||
Link = 'link',
|
||||
Location = 'location',
|
||||
Music = 'music',
|
||||
News = 'news',
|
||||
Text = 'text',
|
||||
Video = 'video',
|
||||
Voice = 'voice',
|
||||
}
|
||||
11
apps/web-antd/src/views/mp/components/index.ts
Normal file
11
apps/web-antd/src/views/mp/components/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export * from './constants';
|
||||
|
||||
export * from './wx-account-select';
|
||||
export * from './wx-location';
|
||||
export * from './wx-material-select';
|
||||
export * from './wx-msg';
|
||||
export * from './wx-music';
|
||||
export * from './wx-news';
|
||||
export * from './wx-reply';
|
||||
export * from './wx-video-play';
|
||||
export * from './wx-voice-play';
|
||||
@@ -3,7 +3,7 @@ import type { SelectValue } from 'ant-design-vue/es/select';
|
||||
|
||||
import type { MpAccountApi } from '#/api/mp/account';
|
||||
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { message, Select } from 'ant-design-vue';
|
||||
@@ -18,7 +18,7 @@ const emit = defineEmits<{
|
||||
|
||||
const { push } = useRouter();
|
||||
|
||||
const account: MpAccountApi.Account = reactive({
|
||||
const account = ref<MpAccountApi.Account>({
|
||||
id: -1,
|
||||
name: '',
|
||||
}); // 当前选中的公众号
|
||||
@@ -36,9 +36,9 @@ async function handleQuery() {
|
||||
// 默认选中第一个,如无数据则不执行
|
||||
const first = accountList.value[0];
|
||||
if (first) {
|
||||
account.id = first.id;
|
||||
account.name = first.name;
|
||||
emit('change', account.id, account.name);
|
||||
account.value.id = first.id;
|
||||
account.value.name = first.name;
|
||||
emit('change', account.value.id, account.value.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ async function handleQuery() {
|
||||
function onChanged(id: SelectValue) {
|
||||
const found = accountList.value.find((v) => v.id === id);
|
||||
if (found) {
|
||||
account.name = found.name;
|
||||
emit('change', account.id, account.name);
|
||||
account.value.name = found.name;
|
||||
emit('change', account.value.id, account.value.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
// TODO @dylan:yudao-ui-admin-vben-v5/apps/web-antd/src/views/mp/components 要不加个 index.ts,统一 export 所有的组件
|
||||
export { default as WxAccountSelect } from './main.vue';
|
||||
export { default as WxAccountSelect } from './account-select.vue';
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { default as WxLocation } from './main.vue';
|
||||
export * from './types';
|
||||
export { default as WxLocation } from './wx-location.vue';
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface WxLocationProps {
|
||||
label: string;
|
||||
locationX: number;
|
||||
locationY: number;
|
||||
qqMapKey?: string;
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { WxLocationProps } from './types';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
@@ -8,17 +10,9 @@ import { Col, Row } from 'ant-design-vue';
|
||||
defineOptions({ name: 'WxLocation' });
|
||||
|
||||
// TODO @dylan:apps/web-antd/src/views/mall/trade/delivery/pickUpStore/modules/form.vue 参考这个,从后端拿 key 哈
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
label: string;
|
||||
locationX: number;
|
||||
locationY: number;
|
||||
qqMapKey?: string;
|
||||
}>(),
|
||||
{
|
||||
qqMapKey: 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', // QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
|
||||
},
|
||||
);
|
||||
const props = withDefaults(defineProps<WxLocationProps>(), {
|
||||
qqMapKey: 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', // QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
|
||||
});
|
||||
|
||||
const mapUrl = computed(() => {
|
||||
return `https://map.qq.com/?type=marker&isopeninfowin=1&markertype=1&pointx=${props.locationY}&pointy=${props.locationX}&name=${props.label}&ref=yudao`;
|
||||
@@ -45,7 +39,7 @@ defineExpose({
|
||||
<img :src="mapImageUrl" alt="地图位置" />
|
||||
</Row>
|
||||
<Row class="mt-2">
|
||||
<IconifyIcon icon="mdi:map-marker" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:map-pin" class="mr-1" />
|
||||
{{ label }}
|
||||
</Row>
|
||||
</Col>
|
||||
@@ -1,3 +1 @@
|
||||
export { default as WxMaterialSelect } from './main.vue';
|
||||
|
||||
export { MaterialType, NewsType } from './types';
|
||||
export { default as WxMaterialSelect } from './wx-material-select.vue';
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
export enum NewsType {
|
||||
Draft = '2',
|
||||
Published = '1',
|
||||
}
|
||||
|
||||
export enum MaterialType {
|
||||
Image = 'image',
|
||||
News = 'news',
|
||||
Video = 'video',
|
||||
Voice = 'voice',
|
||||
}
|
||||
@@ -9,14 +9,12 @@ import { IconifyIcon } from '@vben/icons';
|
||||
import { Button, Pagination, Row, Spin } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import * as MpDraftApi from '#/api/mp/draft';
|
||||
import * as MpFreePublishApi from '#/api/mp/freePublish';
|
||||
import * as MpMaterialApi from '#/api/mp/material';
|
||||
import { WxNews } from '#/views/mp/components/wx-news';
|
||||
import { WxVideoPlayer } from '#/views/mp/components/wx-video-play';
|
||||
import { WxVoicePlayer } from '#/views/mp/components/wx-voice-play';
|
||||
import { getDraftPage } from '#/api/mp/draft';
|
||||
import { getFreePublishPage } from '#/api/mp/freePublish';
|
||||
import { getMaterialPage } from '#/api/mp/material';
|
||||
import { WxNews, WxVideoPlayer, WxVoicePlayer } from '#/views/mp/components';
|
||||
|
||||
import { NewsType } from './types';
|
||||
import { NewsType } from '../constants';
|
||||
|
||||
defineOptions({ name: 'WxMaterialSelect' });
|
||||
|
||||
@@ -142,7 +140,7 @@ const [VoiceGrid, voiceGridApi] = useVbenVxeGrid({
|
||||
return { list: [], total: 0 };
|
||||
}
|
||||
// TODO @dylan:不要带 MpMaterialApi;
|
||||
return await MpMaterialApi.getMaterialPage({
|
||||
return await getMaterialPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
accountId: finalAccountId,
|
||||
@@ -178,7 +176,7 @@ const [VideoGrid, videoGridApi] = useVbenVxeGrid({
|
||||
if (finalAccountId === undefined || finalAccountId === null) {
|
||||
return { list: [], total: 0 };
|
||||
}
|
||||
return await MpMaterialApi.getMaterialPage({
|
||||
return await getMaterialPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
accountId: finalAccountId,
|
||||
@@ -202,7 +200,7 @@ function selectMaterialFun(item: any) {
|
||||
}
|
||||
|
||||
async function getMaterialPageFun() {
|
||||
const data = await MpMaterialApi.getMaterialPage({
|
||||
const data = await getMaterialPage({
|
||||
...queryParams,
|
||||
type: props.type,
|
||||
});
|
||||
@@ -211,7 +209,7 @@ async function getMaterialPageFun() {
|
||||
}
|
||||
|
||||
async function getFreePublishPageFun() {
|
||||
const data = await MpFreePublishApi.getFreePublishPage(queryParams);
|
||||
const data = await getFreePublishPage(queryParams);
|
||||
data.list.forEach((item: any) => {
|
||||
const articles = item.content.newsItem;
|
||||
articles.forEach((article: any) => {
|
||||
@@ -223,7 +221,7 @@ async function getFreePublishPageFun() {
|
||||
}
|
||||
|
||||
async function getDraftPageFun() {
|
||||
const data = await MpDraftApi.getDraftPage(queryParams);
|
||||
const data = await getDraftPage(queryParams);
|
||||
data.list.forEach((draft: any) => {
|
||||
const articles = draft.content.newsItem;
|
||||
articles.forEach((article: any) => {
|
||||
@@ -301,7 +299,7 @@ watch(
|
||||
<Button type="primary" @click="selectMaterialFun(item)">
|
||||
选择
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:check-circle" />
|
||||
<IconifyIcon icon="lucide:circle-check" />
|
||||
</template>
|
||||
</Button>
|
||||
</Row>
|
||||
@@ -328,7 +326,7 @@ watch(
|
||||
<Button type="link" @click="selectMaterialFun(row)">
|
||||
选择
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:plus" />
|
||||
<IconifyIcon icon="lucide:plus" />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
@@ -345,7 +343,7 @@ watch(
|
||||
<Button type="link" @click="selectMaterialFun(row)">
|
||||
选择
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:plus-circle" />
|
||||
<IconifyIcon icon="lucide:circle-plus" />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
@@ -363,7 +361,7 @@ watch(
|
||||
<Button type="primary" @click="selectMaterialFun(item)">
|
||||
选择
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:check-circle" />
|
||||
<IconifyIcon icon="lucide:circle-check" />
|
||||
</template>
|
||||
</Button>
|
||||
</Row>
|
||||
@@ -1,4 +1,4 @@
|
||||
.avue-card {
|
||||
.mp-card {
|
||||
&__item {
|
||||
box-sizing: border-box;
|
||||
height: 200px;
|
||||
@@ -99,18 +99,18 @@
|
||||
}
|
||||
|
||||
/** joolun 额外加的 */
|
||||
.avue-comment__main {
|
||||
.mp-comment__main {
|
||||
flex: unset !important;
|
||||
margin: 0 8px !important;
|
||||
border-radius: 5px !important;
|
||||
}
|
||||
|
||||
.avue-comment__header {
|
||||
.mp-comment__header {
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
}
|
||||
|
||||
.avue-comment__body {
|
||||
.mp-comment__body {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* 来自 https://github.com/nmxiaowei/avue/blob/master/styles/src/element-ui/comment.scss */
|
||||
.avue-comment {
|
||||
.mp-comment {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 30px;
|
||||
@@ -7,7 +7,7 @@
|
||||
&--reverse {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.avue-comment__main {
|
||||
.mp-comment__main {
|
||||
&::before,
|
||||
&::after {
|
||||
right: -8px;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { default as WxMsg } from './main.vue';
|
||||
export * from './types';
|
||||
|
||||
export { MsgType } from './types';
|
||||
export { default as WxMsg } from './wx-msg.vue';
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { Tag } from 'ant-design-vue';
|
||||
|
||||
// TODO @dylan:vue 组件名小写 + 中划线
|
||||
|
||||
defineOptions({ name: 'MsgEvent' });
|
||||
|
||||
defineProps<{
|
||||
@@ -1,12 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import type { User } from '../types';
|
||||
import type { User } from './types';
|
||||
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { formatDateTime } from '@vben/utils';
|
||||
|
||||
import Msg from './Msg.vue';
|
||||
|
||||
// TODO @dylan:vue 组件名小写 + 中划线
|
||||
import Msg from './msg.vue';
|
||||
|
||||
defineOptions({ name: 'MsgList' });
|
||||
|
||||
@@ -15,6 +13,7 @@ const props = defineProps<{
|
||||
list: any[];
|
||||
user: User;
|
||||
}>();
|
||||
|
||||
const SendFrom = {
|
||||
MpBot: 2,
|
||||
User: 1,
|
||||
@@ -26,31 +25,30 @@ function getAvatar(sendFrom: number) {
|
||||
: preferences.app.defaultAvatar;
|
||||
}
|
||||
|
||||
// TODO @dylan:SendFrom 告警;
|
||||
function getNickname(sendFrom: SendFrom) {
|
||||
function getNickname(sendFrom: number) {
|
||||
return sendFrom === SendFrom.User ? props.user.nickname : '公众号';
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="execution" v-for="item in props.list" :key="item.id">
|
||||
<div
|
||||
class="avue-comment"
|
||||
:class="{ 'avue-comment--reverse': item.sendFrom === SendFrom.MpBot }"
|
||||
class="mp-comment"
|
||||
:class="{ 'mp-comment--reverse': item.sendFrom === SendFrom.MpBot }"
|
||||
>
|
||||
<div class="avatar-div">
|
||||
<img :src="getAvatar(item.sendFrom)" class="avue-comment__avatar" />
|
||||
<div class="avue-comment__author">
|
||||
<img :src="getAvatar(item.sendFrom)" class="mp-comment__avatar" />
|
||||
<div class="mp-comment__author">
|
||||
{{ getNickname(item.sendFrom) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="avue-comment__main">
|
||||
<div class="avue-comment__header">
|
||||
<div class="avue-comment__create_time">
|
||||
<div class="mp-comment__main">
|
||||
<div class="mp-comment__header">
|
||||
<div class="mp-comment__create_time">
|
||||
{{ formatDateTime(item.createTime) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="avue-comment__body"
|
||||
class="mp-comment__body"
|
||||
:style="
|
||||
item.sendFrom === SendFrom.MpBot ? 'background: #6BED72;' : ''
|
||||
"
|
||||
@@ -64,10 +62,11 @@ function getNickname(sendFrom: SendFrom) {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 因为 joolun 实现依赖 avue 组件,该页面使用了 comment.scss、card.scc */
|
||||
|
||||
/** TODO @dylan:看看有没适合 tindwind 的哈。 */
|
||||
|
||||
@import url('../comment.scss');
|
||||
@import url('../card.scss');
|
||||
@import url('./comment.scss');
|
||||
@import url('./card.scss');
|
||||
|
||||
.avatar-div {
|
||||
width: 80px;
|
||||
@@ -1,16 +1,16 @@
|
||||
<script lang="ts" setup>
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { WxLocation } from '#/views/mp/components/wx-location';
|
||||
import { WxMusic } from '#/views/mp/components/wx-music';
|
||||
import { WxNews } from '#/views/mp/components/wx-news';
|
||||
import { WxVideoPlayer } from '#/views/mp/components/wx-video-play';
|
||||
import { WxVoicePlayer } from '#/views/mp/components/wx-voice-play';
|
||||
import {
|
||||
WxLocation,
|
||||
WxMusic,
|
||||
WxNews,
|
||||
WxVideoPlayer,
|
||||
WxVoicePlayer,
|
||||
} from '#/views/mp/components';
|
||||
|
||||
import { MsgType } from '../types';
|
||||
import MsgEvent from './MsgEvent.vue';
|
||||
|
||||
// TODO @dylan:vue 组件名小写 + 中划线
|
||||
import { MsgType } from '../constants';
|
||||
import MsgEvent from './msg-event.vue';
|
||||
|
||||
defineOptions({ name: 'Msg' });
|
||||
|
||||
@@ -45,7 +45,7 @@ defineProps<{
|
||||
<div v-else-if="item.type === MsgType.Link" class="flex flex-col gap-2">
|
||||
<a :href="item.url" target="_blank" class="text-success no-underline">
|
||||
<div class="flex items-center text-sm font-medium text-[#52c41a]">
|
||||
<IconifyIcon icon="mdi:link" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:link" class="mr-1" />
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</a>
|
||||
@@ -1,15 +1,3 @@
|
||||
export enum MsgType {
|
||||
Event = 'event',
|
||||
Image = 'image',
|
||||
Link = 'link',
|
||||
Location = 'location',
|
||||
Music = 'music',
|
||||
News = 'news',
|
||||
Text = 'text',
|
||||
Video = 'video',
|
||||
Voice = 'voice',
|
||||
}
|
||||
|
||||
export interface User {
|
||||
accountId: number;
|
||||
avatar: string;
|
||||
|
||||
@@ -9,9 +9,9 @@ import { Button, message, Spin } from 'ant-design-vue';
|
||||
|
||||
import { getMessagePage, sendMessage } from '#/api/mp/message';
|
||||
import { getUser } from '#/api/mp/user';
|
||||
import { WxReplySelect } from '#/views/mp/components/wx-reply';
|
||||
import { WxReply } from '#/views/mp/components';
|
||||
|
||||
import MsgList from './components/MsgList.vue';
|
||||
import MsgList from './msg-list.vue';
|
||||
|
||||
defineOptions({ name: 'WxMsg' });
|
||||
|
||||
@@ -43,7 +43,7 @@ const reply = ref<any>({
|
||||
type: 'text',
|
||||
}); // 微信发送消息
|
||||
|
||||
const replySelectRef = ref<InstanceType<typeof WxReplySelect> | null>(null); // WxReplySelect组件ref,用于消息发送成功后清除内容
|
||||
const replySelectRef = ref<InstanceType<typeof WxReply> | null>(null); // WxReply组件ref,用于消息发送成功后清除内容
|
||||
const msgDivRef = ref<HTMLDivElement | null>(null); // 消息显示窗口ref,用于滚动到底部
|
||||
|
||||
/** 完成加载 */
|
||||
@@ -1 +1 @@
|
||||
export { default as WxMusic } from './main.vue';
|
||||
export { default as WxMusic } from './wx-music.vue';
|
||||
|
||||
7
apps/web-antd/src/views/mp/components/wx-music/types.ts
Normal file
7
apps/web-antd/src/views/mp/components/wx-music/types.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface WxMusicProps {
|
||||
title?: string;
|
||||
description?: string;
|
||||
musicUrl?: string;
|
||||
hqMusicUrl?: string;
|
||||
thumbMediaUrl: string;
|
||||
}
|
||||
@@ -1,23 +1,17 @@
|
||||
<script lang="ts" setup>
|
||||
import type { WxMusicProps } from './types';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
defineOptions({ name: 'WxMusic' });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
description?: string;
|
||||
hqMusicUrl?: string;
|
||||
musicUrl?: string;
|
||||
thumbMediaUrl: string;
|
||||
title?: string;
|
||||
}>(),
|
||||
{
|
||||
title: '',
|
||||
description: '',
|
||||
musicUrl: '',
|
||||
hqMusicUrl: '',
|
||||
},
|
||||
);
|
||||
const props = withDefaults(defineProps<WxMusicProps>(), {
|
||||
title: '',
|
||||
description: '',
|
||||
musicUrl: '',
|
||||
hqMusicUrl: '',
|
||||
thumbMediaUrl: '',
|
||||
});
|
||||
|
||||
const href = computed(() => props.hqMusicUrl || props.musicUrl);
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default as WxNews } from './main.vue';
|
||||
export { default as WxNews } from './wx-news.vue';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export type { NewsType, Reply, ReplyType } from './components/types';
|
||||
export { createEmptyReply } from './components/types';
|
||||
export * from './types';
|
||||
|
||||
export { default as WxReplySelect } from './main.vue';
|
||||
export { default as WxReply } from './wx-reply.vue';
|
||||
|
||||
@@ -10,11 +10,9 @@ import { useAccessStore } from '@vben/stores';
|
||||
|
||||
import { Button, Col, message, Modal, Row, Upload } from 'ant-design-vue';
|
||||
|
||||
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||
import { WxMaterialSelect } from '#/views/mp/components';
|
||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||
|
||||
// TODO @dylan:文件名的大小写
|
||||
|
||||
defineOptions({ name: 'TabImage' });
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -110,7 +108,7 @@ function selectMaterial(item: any) {
|
||||
<Row class="ope-row" justify="center">
|
||||
<Button danger shape="circle" @click="onDelete">
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:delete" />
|
||||
<IconifyIcon icon="lucide:trash-2" />
|
||||
</template>
|
||||
</Button>
|
||||
</Row>
|
||||
@@ -123,7 +121,7 @@ function selectMaterial(item: any) {
|
||||
<Button type="primary" @click="showDialog = true">
|
||||
素材库选择
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:check-circle" />
|
||||
<IconifyIcon icon="lucide:circle-check" />
|
||||
</template>
|
||||
</Button>
|
||||
<Modal
|
||||
@@ -154,7 +152,7 @@ function selectMaterial(item: any) {
|
||||
<Button type="primary">
|
||||
上传图片
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:upload" />
|
||||
<IconifyIcon icon="lucide:upload" />
|
||||
</template>
|
||||
</Button>
|
||||
</Upload>
|
||||
@@ -18,11 +18,9 @@ import {
|
||||
Upload,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||
import { WxMaterialSelect } from '#/views/mp/components';
|
||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||
|
||||
// TODO @dylan:文件名的大小写
|
||||
|
||||
defineOptions({ name: 'TabMusic' });
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -116,7 +114,7 @@ function selectMaterial(item: any) {
|
||||
/>
|
||||
<IconifyIcon
|
||||
v-else
|
||||
icon="mdi:plus"
|
||||
icon="lucide:plus"
|
||||
:size="40"
|
||||
class="text-gray-400"
|
||||
/>
|
||||
@@ -7,12 +7,9 @@ import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Button, Col, Modal, Row } from 'ant-design-vue';
|
||||
|
||||
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||
import { WxNews } from '#/views/mp/components/wx-news';
|
||||
import { WxMaterialSelect, WxNews } from '#/views/mp/components';
|
||||
|
||||
import { NewsType } from './types';
|
||||
|
||||
// TODO @dylan:文件名的大小写
|
||||
import { NewsType } from '../constants';
|
||||
|
||||
defineOptions({ name: 'TabNews' });
|
||||
|
||||
@@ -53,7 +50,7 @@ function onDelete() {
|
||||
<Col class="ope-row">
|
||||
<Button danger shape="circle" @click="onDelete">
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:delete" />
|
||||
<IconifyIcon icon="lucide:trash-2" />
|
||||
</template>
|
||||
</Button>
|
||||
</Col>
|
||||
@@ -70,7 +67,7 @@ function onDelete() {
|
||||
: '选择草稿箱图文'
|
||||
}}
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:check-circle" />
|
||||
<IconifyIcon icon="lucide:circle-check" />
|
||||
</template>
|
||||
</Button>
|
||||
</Col>
|
||||
@@ -3,8 +3,6 @@ import { computed } from 'vue';
|
||||
|
||||
import { Textarea } from 'ant-design-vue';
|
||||
|
||||
// TODO @dylan:文件名的大小写
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: null | string;
|
||||
}>();
|
||||
@@ -18,12 +18,9 @@ import {
|
||||
Upload,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||
import { WxVideoPlayer } from '#/views/mp/components/wx-video-play';
|
||||
import { WxMaterialSelect, WxVideoPlayer } from '#/views/mp/components';
|
||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||
|
||||
// TODO @dylan:文件名的大小写
|
||||
|
||||
defineOptions({ name: 'TabVideo' });
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -143,7 +140,7 @@ function selectMaterial(item: any) {
|
||||
<Button type="primary" @click="showDialog = true">
|
||||
素材库选择
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:check-circle" />
|
||||
<IconifyIcon icon="lucide:circle-check" />
|
||||
</template>
|
||||
</Button>
|
||||
<Modal
|
||||
@@ -174,7 +171,7 @@ function selectMaterial(item: any) {
|
||||
<Button type="primary">
|
||||
新建视频
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:upload" />
|
||||
<IconifyIcon icon="lucide:upload" />
|
||||
</template>
|
||||
</Button>
|
||||
</Upload>
|
||||
@@ -10,12 +10,9 @@ import { useAccessStore } from '@vben/stores';
|
||||
|
||||
import { Button, Col, message, Modal, Row, Upload } from 'ant-design-vue';
|
||||
|
||||
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||
import { WxVoicePlayer } from '#/views/mp/components/wx-voice-play';
|
||||
import { WxMaterialSelect, WxVoicePlayer } from '#/views/mp/components';
|
||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||
|
||||
// TODO @dylan:文件名的大小写
|
||||
|
||||
defineOptions({ name: 'TabVoice' });
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -112,7 +109,7 @@ function selectMaterial(item: Reply) {
|
||||
<Row class="ope-row" justify="center">
|
||||
<Button danger shape="circle" @click="onDelete">
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:delete" />
|
||||
<IconifyIcon icon="lucide:trash-2" />
|
||||
</template>
|
||||
</Button>
|
||||
</Row>
|
||||
@@ -124,7 +121,7 @@ function selectMaterial(item: Reply) {
|
||||
<Button type="primary" @click="showDialog = true">
|
||||
素材库选择
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:check-circle" />
|
||||
<IconifyIcon icon="lucide:circle-check" />
|
||||
</template>
|
||||
</Button>
|
||||
<Modal
|
||||
@@ -155,7 +152,7 @@ function selectMaterial(item: Reply) {
|
||||
<Button type="primary">
|
||||
点击上传
|
||||
<template #icon>
|
||||
<IconifyIcon icon="mdi:upload" />
|
||||
<IconifyIcon icon="lucide:upload" />
|
||||
</template>
|
||||
</Button>
|
||||
</Upload>
|
||||
@@ -1,15 +1,8 @@
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import { unref } from 'vue';
|
||||
import type { ReplyType } from '../constants';
|
||||
|
||||
export enum ReplyType {
|
||||
Image = 'image',
|
||||
Music = 'music',
|
||||
News = 'news',
|
||||
Text = 'text',
|
||||
Video = 'video',
|
||||
Voice = 'voice',
|
||||
}
|
||||
import { unref } from 'vue';
|
||||
|
||||
export interface Reply {
|
||||
accountId: number;
|
||||
@@ -28,13 +21,8 @@ export interface Reply {
|
||||
url?: null | string;
|
||||
}
|
||||
|
||||
export enum NewsType {
|
||||
Draft = '2',
|
||||
Published = '1',
|
||||
}
|
||||
|
||||
/** 利用旧的reply[accountId, type]初始化新的Reply */
|
||||
export const createEmptyReply = (old: Ref<Reply> | Reply): Reply => {
|
||||
export function createEmptyReply(old: Ref<Reply> | Reply): Reply {
|
||||
return {
|
||||
accountId: unref(old).accountId,
|
||||
articles: [],
|
||||
@@ -51,4 +39,4 @@ export const createEmptyReply = (old: Ref<Reply> | Reply): Reply => {
|
||||
type: unref(old).type,
|
||||
url: null,
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
④ 支持发送【视频】消息时,支持新建视频
|
||||
-->
|
||||
<script lang="ts" setup>
|
||||
import type { Reply } from './components/types';
|
||||
import type { Reply } from './types';
|
||||
|
||||
import { computed, ref, unref, watch } from 'vue';
|
||||
|
||||
@@ -16,13 +16,14 @@ import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Row, Tabs } from 'ant-design-vue';
|
||||
|
||||
import TabImage from './components/TabImage.vue';
|
||||
import TabMusic from './components/TabMusic.vue';
|
||||
import TabNews from './components/TabNews.vue';
|
||||
import TabText from './components/TabText.vue';
|
||||
import TabVideo from './components/TabVideo.vue';
|
||||
import TabVoice from './components/TabVoice.vue';
|
||||
import { createEmptyReply, NewsType, ReplyType } from './components/types';
|
||||
import { NewsType, ReplyType } from '../constants';
|
||||
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 } from './types';
|
||||
|
||||
defineOptions({ name: 'WxReplySelect' });
|
||||
|
||||
@@ -88,7 +89,7 @@ defineExpose({
|
||||
<Tabs.TabPane :key="ReplyType.Text">
|
||||
<template #tab>
|
||||
<Row align="middle">
|
||||
<IconifyIcon icon="mdi:text" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:file-text" class="mr-1" />
|
||||
文本
|
||||
</Row>
|
||||
</template>
|
||||
@@ -99,7 +100,7 @@ defineExpose({
|
||||
<Tabs.TabPane :key="ReplyType.Image">
|
||||
<template #tab>
|
||||
<Row align="middle">
|
||||
<IconifyIcon icon="mdi:image" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:image" class="mr-1" />
|
||||
图片
|
||||
</Row>
|
||||
</template>
|
||||
@@ -110,7 +111,7 @@ defineExpose({
|
||||
<Tabs.TabPane :key="ReplyType.Voice">
|
||||
<template #tab>
|
||||
<Row align="middle">
|
||||
<IconifyIcon icon="mdi:microphone" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:mic" class="mr-1" />
|
||||
语音
|
||||
</Row>
|
||||
</template>
|
||||
@@ -121,7 +122,7 @@ defineExpose({
|
||||
<Tabs.TabPane :key="ReplyType.Video">
|
||||
<template #tab>
|
||||
<Row align="middle">
|
||||
<IconifyIcon icon="mdi:video" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:video" class="mr-1" />
|
||||
视频
|
||||
</Row>
|
||||
</template>
|
||||
@@ -132,7 +133,7 @@ defineExpose({
|
||||
<Tabs.TabPane :key="ReplyType.News">
|
||||
<template #tab>
|
||||
<Row align="middle">
|
||||
<IconifyIcon icon="mdi:newspaper" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:newspaper" class="mr-1" />
|
||||
图文
|
||||
</Row>
|
||||
</template>
|
||||
@@ -143,7 +144,7 @@ defineExpose({
|
||||
<Tabs.TabPane :key="ReplyType.Music">
|
||||
<template #tab>
|
||||
<Row align="middle">
|
||||
<IconifyIcon icon="mdi:music" class="mr-1" />
|
||||
<IconifyIcon icon="lucide:music" class="mr-1" />
|
||||
音乐
|
||||
</Row>
|
||||
</template>
|
||||
@@ -1 +1 @@
|
||||
export { default as WxVideoPlayer } from './main.vue';
|
||||
export { default as WxVideoPlayer } from './wx-video-play.vue';
|
||||
|
||||
@@ -26,7 +26,7 @@ function playVideo() {
|
||||
<div class="cursor-pointer" @click="playVideo()">
|
||||
<!-- 提示 -->
|
||||
<div class="flex items-center">
|
||||
<IconifyIcon icon="mdi:play-circle" :size="32" class="mr-2" />
|
||||
<IconifyIcon icon="lucide:circle-play" :size="32" class="mr-2" />
|
||||
<p class="text-sm">点击播放视频</p>
|
||||
</div>
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default as WxVoicePlayer } from './main.vue';
|
||||
export { default as WxVoicePlayer } from './wx-voice-play.vue';
|
||||
|
||||
@@ -68,8 +68,12 @@ function amrStop() {
|
||||
<!-- 微信消息 - 语音播放 -->
|
||||
<div class="wx-voice-div cursor-pointer" @click="playVoice">
|
||||
<div class="flex items-center">
|
||||
<IconifyIcon v-if="playing !== true" icon="mdi:play-circle" :size="32" />
|
||||
<IconifyIcon v-else icon="mdi:pause-circle" :size="32" />
|
||||
<IconifyIcon
|
||||
v-if="playing !== true"
|
||||
icon="lucide:circle-play"
|
||||
:size="32"
|
||||
/>
|
||||
<IconifyIcon v-else icon="lucide:circle-pause" :size="32" />
|
||||
<span v-if="duration" class="amr-duration">{{ duration }} 秒</span>
|
||||
</div>
|
||||
<div v-if="content" class="mt-2">
|
||||
Reference in New Issue
Block a user