feat: mp
This commit is contained in:
@@ -7,7 +7,7 @@ import { DICT_TYPE } from '@vben/constants';
|
||||
|
||||
import { WxAccountSelect } from '#/views/mp/modules/wx-account-select';
|
||||
|
||||
import { MsgType } from './modules/types';
|
||||
import { MsgType } from './components/types';
|
||||
|
||||
/** 获取表格列配置 */
|
||||
export function useGridColumns(msgType: MsgType): VxeGridPropTypes.Columns {
|
||||
|
||||
@@ -18,10 +18,10 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import * as MpAutoReplyApi from '#/api/mp/autoReply';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import ReplyContentCell from './components/ReplyTable.vue';
|
||||
import { MsgType } from './components/types';
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
import ReplyContentCell from './modules/ReplyTable.vue';
|
||||
import { MsgType } from './modules/types';
|
||||
|
||||
defineOptions({ name: 'MpAutoReply' });
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import * as MpAutoReplyApi from '#/api/mp/autoReply';
|
||||
import { createAutoReply, updateAutoReply } from '#/api/mp/autoReply';
|
||||
import { $t } from '#/locales';
|
||||
import { ReplyType } from '#/views/mp/modules/wx-reply/types';
|
||||
|
||||
import ReplyForm from './ReplyForm.vue';
|
||||
import { MsgType } from './types';
|
||||
import ReplyForm from '../components/ReplyForm.vue';
|
||||
import { MsgType } from '../components/types';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
@@ -52,10 +52,10 @@ const [Modal, modalApi] = useVbenModal({
|
||||
modalApi.lock();
|
||||
try {
|
||||
if (replyForm.value.id === undefined) {
|
||||
await MpAutoReplyApi.createAutoReply(submitForm);
|
||||
await createAutoReply(submitForm);
|
||||
message.success('新增成功');
|
||||
} else {
|
||||
await MpAutoReplyApi.updateAutoReply(submitForm);
|
||||
await updateAutoReply(submitForm);
|
||||
message.success('修改成功');
|
||||
}
|
||||
await modalApi.close();
|
||||
|
||||
@@ -97,7 +97,7 @@ function onUploadError(err: Error) {
|
||||
/>
|
||||
<IconifyIcon
|
||||
v-else
|
||||
icon="ep:plus"
|
||||
icon="lucide:plus"
|
||||
class="avatar-uploader-icon"
|
||||
:class="isFirst ? 'avatar' : 'avatar1'"
|
||||
/>
|
||||
@@ -11,15 +11,9 @@ const props = defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="draft-content">
|
||||
<div class="p-2.5">
|
||||
<div v-if="props.row.content && props.row.content.newsItem">
|
||||
<WxNews :articles="props.row.content.newsItem" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.draft-content {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -109,7 +109,7 @@ function plusNews() {
|
||||
size="small"
|
||||
@click="() => moveDownNews(index)"
|
||||
>
|
||||
<IconifyIcon icon="ep:arrow-down-bold" />
|
||||
<IconifyIcon icon="lucide:arrow-down" />
|
||||
</Button>
|
||||
<Button
|
||||
v-if="isCreating"
|
||||
@@ -119,7 +119,7 @@ function plusNews() {
|
||||
size="small"
|
||||
@click="() => removeNews(index)"
|
||||
>
|
||||
<IconifyIcon icon="ep:delete" />
|
||||
<IconifyIcon icon="lucide:trash-2" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -143,7 +143,7 @@ function plusNews() {
|
||||
size="small"
|
||||
@click="() => moveDownNews(index)"
|
||||
>
|
||||
<IconifyIcon icon="ep:arrow-down-bold" />
|
||||
<IconifyIcon icon="lucide:arrow-down" />
|
||||
</Button>
|
||||
<Button
|
||||
v-if="index > 0"
|
||||
@@ -152,7 +152,7 @@ function plusNews() {
|
||||
size="small"
|
||||
@click="() => moveUpNews(index)"
|
||||
>
|
||||
<IconifyIcon icon="ep:arrow-up-bold" />
|
||||
<IconifyIcon icon="lucide:arrow-up" />
|
||||
</Button>
|
||||
<Button
|
||||
v-if="isCreating"
|
||||
@@ -162,7 +162,7 @@ function plusNews() {
|
||||
shape="circle"
|
||||
@click="() => removeNews(index)"
|
||||
>
|
||||
<IconifyIcon icon="ep:delete" />
|
||||
<IconifyIcon icon="lucide:trash-2" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,7 +174,7 @@ function plusNews() {
|
||||
@click="plusNews"
|
||||
v-if="newsList.length < 8 && isCreating"
|
||||
>
|
||||
<IconifyIcon icon="ep:plus" />
|
||||
<IconifyIcon icon="lucide:plus" />
|
||||
</Button>
|
||||
</Row>
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Article } from './modules/types';
|
||||
import type { Article } from './components/types';
|
||||
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
|
||||
@@ -12,10 +12,10 @@ import { message } from 'ant-design-vue';
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import * as MpDraftApi from '#/api/mp/draft';
|
||||
import * as MpFreePublishApi from '#/api/mp/freePublish';
|
||||
import { createEmptyNewsItem } from '#/views/mp/draft/modules/types';
|
||||
import { createEmptyNewsItem } from '#/views/mp/draft/components/types';
|
||||
|
||||
import DraftTableCell from './components/draft-table.vue';
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import DraftTableCell from './modules/draft-table.vue';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
defineOptions({ name: 'MpDraft' });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { NewsItem } from './types';
|
||||
import type { NewsItem } from '../components/types';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
@@ -7,9 +7,9 @@ import { confirm, useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message, Spin } from 'ant-design-vue';
|
||||
|
||||
import * as MpDraftApi from '#/api/mp/draft';
|
||||
import { createDraft, updateDraft } from '#/api/mp/draft';
|
||||
|
||||
import NewsForm from './news-form.vue';
|
||||
import NewsForm from '../components/news-form.vue';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
@@ -37,10 +37,10 @@ const [Modal, modalApi] = useVbenModal({
|
||||
modalApi.lock();
|
||||
try {
|
||||
if (formData.value.isCreating) {
|
||||
await MpDraftApi.createDraft(formData.value.accountId, newsList.value);
|
||||
await createDraft(formData.value.accountId, newsList.value);
|
||||
message.success('新增成功');
|
||||
} else if (formData.value.mediaId) {
|
||||
await MpDraftApi.updateDraft(
|
||||
await updateDraft(
|
||||
formData.value.accountId,
|
||||
formData.value.mediaId,
|
||||
newsList.value,
|
||||
|
||||
@@ -134,7 +134,8 @@ function onChildDragEnd({ newIndex }: { newIndex: number }) {
|
||||
class="menu-item"
|
||||
:class="{ active: props.activeIndex === `${x}` }"
|
||||
>
|
||||
<IconifyIcon icon="ep:fold" color="black" />{{ parent.name }}
|
||||
<IconifyIcon icon="lucide:panel-right-open" color="black" />
|
||||
{{ parent.name }}
|
||||
</div>
|
||||
<!-- 以下为二级菜单-->
|
||||
<div class="submenu" v-if="props.parentIndex === x && parent.children">
|
||||
@@ -164,7 +165,7 @@ function onChildDragEnd({ newIndex }: { newIndex: number }) {
|
||||
v-if="!parent.children || parent.children.length < 5"
|
||||
@click="addSubMenu(x, parent)"
|
||||
>
|
||||
<IconifyIcon icon="ep:plus" class="plus" />
|
||||
<IconifyIcon icon="lucide:plus" class="plus" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -177,7 +178,7 @@ function onChildDragEnd({ newIndex }: { newIndex: number }) {
|
||||
v-if="menuList.length < 3"
|
||||
@click="addMenu"
|
||||
>
|
||||
<IconifyIcon icon="ep:plus" class="plus" />
|
||||
<IconifyIcon icon="lucide:plus" class="plus" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { handleTree } from '@vben/utils';
|
||||
|
||||
import { Button, Form, message } from 'ant-design-vue';
|
||||
|
||||
import * as MpMenuApi from '#/api/mp/menu';
|
||||
import { deleteMenu, getMenuList, saveMenu } from '#/api/mp/menu';
|
||||
import { MenuEditor, MenuPreviewer } from '#/views/mp/menu/components';
|
||||
import { Level, MENU_NOT_SELECTED } from '#/views/mp/menu/data';
|
||||
import { WxAccountSelect } from '#/views/mp/modules/wx-account-select';
|
||||
@@ -60,7 +60,7 @@ function onAccountChanged(id: number, name: string) {
|
||||
async function getList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const data = await MpMenuApi.getMenuList(accountId.value);
|
||||
const data = await getMenuList(accountId.value);
|
||||
const menuData = menuListToFrontend(data);
|
||||
menuList.value = handleTree(menuData, 'id') as Menu[];
|
||||
} finally {
|
||||
@@ -178,7 +178,7 @@ async function onSave() {
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await MpMenuApi.saveMenu(accountId.value, menuListToBackend());
|
||||
await saveMenu(accountId.value, menuListToBackend());
|
||||
getList();
|
||||
message.success('发布成功');
|
||||
} finally {
|
||||
@@ -198,7 +198,7 @@ async function onClear() {
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await MpMenuApi.deleteMenu(accountId.value);
|
||||
await deleteMenu(accountId.value);
|
||||
handleQuery();
|
||||
message.success('清空成功');
|
||||
} finally {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
【微信消息 - 定位】TODO @Dhb52 目前未启用
|
||||
-->
|
||||
<script lang="ts" setup>
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Col, Row } from 'ant-design-vue';
|
||||
|
||||
defineOptions({ name: 'WxLocation' });
|
||||
@@ -53,7 +55,7 @@ defineExpose({
|
||||
/>
|
||||
</Row>
|
||||
<Row>
|
||||
<Icon icon="ep:location" />
|
||||
<IconifyIcon icon="lucide:map-pin" />
|
||||
{{ label }}
|
||||
</Row>
|
||||
</Col>
|
||||
|
||||
@@ -6,9 +6,9 @@ import { formatTime } from '@vben/utils';
|
||||
|
||||
import { Button, Pagination, Row, Spin, Table } from 'ant-design-vue';
|
||||
|
||||
import * as MpDraftApi from '#/api/mp/draft';
|
||||
import * as MpFreePublishApi from '#/api/mp/freePublish';
|
||||
import * as MpMaterialApi from '#/api/mp/material';
|
||||
import { getDraftPage } from '#/api/mp/draft';
|
||||
import { getFreePublishPage } from '#/api/mp/freePublish';
|
||||
import { getMaterialPage } from '#/api/mp/material';
|
||||
import { WxNews } from '#/views/mp/modules/wx-news';
|
||||
import { WxVideoPlayer } from '#/views/mp/modules/wx-video-play';
|
||||
import { WxVoicePlayer } from '#/views/mp/modules/wx-voice-play';
|
||||
@@ -69,7 +69,7 @@ async function getPage() {
|
||||
|
||||
/** 获取素材分页 */
|
||||
async function getMaterialPageFun() {
|
||||
const data = await MpMaterialApi.getMaterialPage({
|
||||
const data = await getMaterialPage({
|
||||
...queryParams,
|
||||
type: props.type,
|
||||
});
|
||||
@@ -79,7 +79,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) => {
|
||||
@@ -92,7 +92,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) => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { WxLocation } from '#/views/mp/modules/wx-location';
|
||||
import { WxMusic } from '#/views/mp/modules/wx-music';
|
||||
import { WxNews } from '#/views/mp/modules/wx-news';
|
||||
@@ -47,7 +49,7 @@ const item = ref<any>(props.item);
|
||||
<div
|
||||
class="mb-3 text-base text-[rgba(0,0,0,0.85)] hover:text-[#1890ff]"
|
||||
>
|
||||
<Icon icon="ep:link" />{{ item.title }}
|
||||
<IconifyIcon icon="lucide:link" />{{ item.title }}
|
||||
</div>
|
||||
</a>
|
||||
<div
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export { createEmptyReply, NewsType, type Reply, ReplyType } from './types';
|
||||
|
||||
export * from './types';
|
||||
export { default as WxReplySelect } from './wx-reply.vue';
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Tag } from 'ant-design-vue';
|
||||
// 因为微信语音是 amr 格式,所以需要用到 amr 解码器:https://www.npmjs.com/package/benz-amr-recorder
|
||||
import BenzAMRRecorder from 'benz-amr-recorder';
|
||||
@@ -35,7 +37,7 @@ const playing = ref(false);
|
||||
const duration = ref();
|
||||
|
||||
/** 处理点击,播放或暂停 */
|
||||
const playVoice = () => {
|
||||
function playVoice() {
|
||||
// 情况一:未初始化,则创建 BenzAMRRecorder
|
||||
if (amr.value === undefined) {
|
||||
amrInit();
|
||||
@@ -47,10 +49,10 @@ const playVoice = () => {
|
||||
} else {
|
||||
amrPlay();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 音频初始化 */
|
||||
const amrInit = () => {
|
||||
function amrInit() {
|
||||
amr.value = new BenzAMRRecorder();
|
||||
// 设置播放
|
||||
amr.value.initWithUrl(props.url).then(() => {
|
||||
@@ -61,26 +63,26 @@ const amrInit = () => {
|
||||
amr.value.onEnded(() => {
|
||||
playing.value = false;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/** 音频播放 */
|
||||
const amrPlay = () => {
|
||||
function amrPlay() {
|
||||
playing.value = true;
|
||||
amr.value.play();
|
||||
};
|
||||
}
|
||||
|
||||
/** 音频暂停 */
|
||||
const amrStop = () => {
|
||||
function amrStop() {
|
||||
playing.value = false;
|
||||
amr.value.stop();
|
||||
};
|
||||
}
|
||||
// TODO 芋艿:下面样式有点问题
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="wx-voice-div" @click="playVoice">
|
||||
<Icon v-if="playing !== true" icon="ep:video-play" :size="32" />
|
||||
<Icon v-else icon="ep:video-pause" :size="32" />
|
||||
<IconifyIcon v-if="playing !== true" icon="lucide:circle-play" :size="32" />
|
||||
<IconifyIcon v-else icon="lucide:circle-pause" :size="32" />
|
||||
<span class="amr-duration" v-if="duration">{{ duration }} 秒</span>
|
||||
<div v-if="content">
|
||||
<Tag color="success" size="small">语音识别</Tag>
|
||||
|
||||
Reference in New Issue
Block a user