fix: code style
This commit is contained in:
@@ -24,8 +24,8 @@ export namespace MpAccountApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 重新导出类型,方便使用
|
// 重新导出类型,方便使用
|
||||||
export type Account = MpAccountApi.Account;
|
// export type Account = MpAccountApi.Account;
|
||||||
export type AccountSimple = MpAccountApi.AccountSimple;
|
// export type AccountSimple = MpAccountApi.AccountSimple;
|
||||||
|
|
||||||
/** 查询公众号账号列表 */
|
/** 查询公众号账号列表 */
|
||||||
export function getAccountPage(params: PageParam) {
|
export function getAccountPage(params: PageParam) {
|
||||||
|
|||||||
@@ -29,5 +29,11 @@
|
|||||||
"tenant": {
|
"tenant": {
|
||||||
"placeholder": "Please select tenant",
|
"placeholder": "Please select tenant",
|
||||||
"success": "Switch tenant success"
|
"success": "Switch tenant success"
|
||||||
|
},
|
||||||
|
"mp": {
|
||||||
|
"upload": {
|
||||||
|
"invalidFormat": "Invalid {0} format!",
|
||||||
|
"maxSize": "{0} size cannot exceed {1}M!"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export * from './auth';
|
export * from './auth';
|
||||||
export * from './tagsView';
|
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
|
|
||||||
import { findIndex } from 'lodash';
|
|
||||||
import { defineStore } from 'pinia';
|
|
||||||
|
|
||||||
import { getRawRoute } from '../utils/routerHelper';
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
export interface TagsViewState {
|
|
||||||
visitedViews: RouteLocationNormalizedLoaded[];
|
|
||||||
cachedViews: Set<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useTagsViewStore = defineStore('tagsView', {
|
|
||||||
state: (): TagsViewState => ({
|
|
||||||
visitedViews: [],
|
|
||||||
cachedViews: new Set(),
|
|
||||||
}),
|
|
||||||
|
|
||||||
getters: {
|
|
||||||
getVisitedViews(): RouteLocationNormalizedLoaded[] {
|
|
||||||
return this.visitedViews;
|
|
||||||
},
|
|
||||||
getCachedViews(): string[] {
|
|
||||||
return [...this.cachedViews];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
/** 新增缓存和tag */
|
|
||||||
addView(view: RouteLocationNormalizedLoaded): void {
|
|
||||||
this.addVisitedView(view);
|
|
||||||
this.addCachedView();
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 新增tag */
|
|
||||||
addVisitedView(view: RouteLocationNormalizedLoaded) {
|
|
||||||
if (this.visitedViews.some((v) => v.fullPath === view.fullPath)) return;
|
|
||||||
if (view.meta?.noTagsView) return;
|
|
||||||
|
|
||||||
const visitedView = Object.assign({}, view, {
|
|
||||||
title: view.meta?.title || 'no-name',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (visitedView.meta) {
|
|
||||||
const suffixList: string[] = [];
|
|
||||||
this.visitedViews.forEach((v) => {
|
|
||||||
if (
|
|
||||||
v.path === visitedView.path &&
|
|
||||||
v.meta?.title === visitedView.meta?.title
|
|
||||||
) {
|
|
||||||
const rawSuffix = v.meta?.titleSuffix;
|
|
||||||
const suffixStr =
|
|
||||||
typeof rawSuffix === 'string' || typeof rawSuffix === 'number'
|
|
||||||
? `${rawSuffix}`
|
|
||||||
: undefined;
|
|
||||||
suffixList.push(suffixStr ?? '1');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (suffixList.length > 0) {
|
|
||||||
let suffix = 1;
|
|
||||||
while (suffixList.includes(`${suffix}`)) suffix += 1;
|
|
||||||
visitedView.meta.titleSuffix = suffix === 1 ? undefined : `${suffix}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.visitedViews.push(visitedView);
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 新增缓存 */
|
|
||||||
addCachedView() {
|
|
||||||
const cacheMap: Set<string> = new Set();
|
|
||||||
for (const v of this.visitedViews) {
|
|
||||||
const item = getRawRoute(v);
|
|
||||||
if (!item.meta?.noCache) {
|
|
||||||
const name = item.name as string;
|
|
||||||
cacheMap.add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
[...this.cachedViews].sort().toString() ===
|
|
||||||
[...cacheMap].sort().toString()
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.cachedViews = cacheMap;
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 删除某个tag和缓存 */
|
|
||||||
delView(view: RouteLocationNormalizedLoaded) {
|
|
||||||
this.delVisitedView(view);
|
|
||||||
this.delCachedView();
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 删除tag */
|
|
||||||
delVisitedView(view: RouteLocationNormalizedLoaded) {
|
|
||||||
const index = findIndex<RouteLocationNormalizedLoaded>(
|
|
||||||
this.visitedViews,
|
|
||||||
(v) => v.fullPath === view.fullPath,
|
|
||||||
);
|
|
||||||
if (index > -1) this.visitedViews.splice(index, 1);
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 删除缓存 */
|
|
||||||
delCachedView() {
|
|
||||||
const route = router.currentRoute.value;
|
|
||||||
const index = findIndex<string>(
|
|
||||||
this.getCachedViews,
|
|
||||||
(v) => v === route.name,
|
|
||||||
);
|
|
||||||
if (index > -1) {
|
|
||||||
const name = this.getCachedViews[index] as string;
|
|
||||||
this.cachedViews.delete(name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 删除全部tag和缓存 */
|
|
||||||
delAllViews() {
|
|
||||||
this.visitedViews = [];
|
|
||||||
this.cachedViews.clear();
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 删除其他tag和缓存 */
|
|
||||||
delOthersViews(view: RouteLocationNormalizedLoaded) {
|
|
||||||
this.visitedViews = this.visitedViews.filter(
|
|
||||||
(v) => v?.meta?.affix || v.fullPath === view.fullPath,
|
|
||||||
);
|
|
||||||
this.addCachedView();
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 删除左侧tag */
|
|
||||||
delLeftViews(view: RouteLocationNormalizedLoaded) {
|
|
||||||
const index = findIndex<RouteLocationNormalizedLoaded>(
|
|
||||||
this.visitedViews,
|
|
||||||
(v) => v.fullPath === view.fullPath,
|
|
||||||
);
|
|
||||||
if (index > -1) {
|
|
||||||
this.visitedViews = this.visitedViews.filter(
|
|
||||||
(v, i) => v?.meta?.affix || v.fullPath === view.fullPath || i > index,
|
|
||||||
);
|
|
||||||
this.addCachedView();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 删除右侧tag */
|
|
||||||
delRightViews(view: RouteLocationNormalizedLoaded) {
|
|
||||||
const index = findIndex<RouteLocationNormalizedLoaded>(
|
|
||||||
this.visitedViews,
|
|
||||||
(v) => v.fullPath === view.fullPath,
|
|
||||||
);
|
|
||||||
if (index > -1) {
|
|
||||||
this.visitedViews = this.visitedViews.filter(
|
|
||||||
(v, i) => v?.meta?.affix || v.fullPath === view.fullPath || i < index,
|
|
||||||
);
|
|
||||||
this.addCachedView();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 更新tag */
|
|
||||||
updateVisitedView(view: RouteLocationNormalizedLoaded) {
|
|
||||||
const index = findIndex<RouteLocationNormalizedLoaded>(
|
|
||||||
this.visitedViews,
|
|
||||||
(v) => v.fullPath === view.fullPath,
|
|
||||||
);
|
|
||||||
if (index > -1) {
|
|
||||||
this.visitedViews[index] = {
|
|
||||||
...this.visitedViews[index],
|
|
||||||
...view,
|
|
||||||
} as RouteLocationNormalizedLoaded;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1 +1 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxAccountSelect } from './main.vue';
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, reactive, ref, unref } from 'vue';
|
import type { SelectValue } from 'ant-design-vue/es/select';
|
||||||
|
|
||||||
|
import type { MpAccountApi } from '#/api/mp/account';
|
||||||
|
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { message } from 'ant-design-vue';
|
import { message, Select } from 'ant-design-vue';
|
||||||
|
|
||||||
import * as MpAccountApi from '#/api/mp/account';
|
import { getSimpleAccountList } from '#/api/mp/account';
|
||||||
import { useTagsViewStore } from '#/store';
|
|
||||||
|
|
||||||
defineOptions({ name: 'WxAccountSelect' });
|
defineOptions({ name: 'WxAccountSelect' });
|
||||||
|
|
||||||
@@ -14,8 +17,7 @@ const emit = defineEmits<{
|
|||||||
(e: 'change', id: number, name: string): void;
|
(e: 'change', id: number, name: string): void;
|
||||||
}>();
|
}>();
|
||||||
// 消息弹窗
|
// 消息弹窗
|
||||||
const { delView } = useTagsViewStore();
|
const { push } = useRouter();
|
||||||
const { push, currentRoute } = useRouter();
|
|
||||||
|
|
||||||
// 当前选中的公众号
|
// 当前选中的公众号
|
||||||
const account: MpAccountApi.Account = reactive({
|
const account: MpAccountApi.Account = reactive({
|
||||||
@@ -28,10 +30,9 @@ const accountList = ref<MpAccountApi.Account[]>([]);
|
|||||||
|
|
||||||
// 查询公众号列表
|
// 查询公众号列表
|
||||||
const handleQuery = async () => {
|
const handleQuery = async () => {
|
||||||
accountList.value = await MpAccountApi.getSimpleAccountList();
|
accountList.value = await getSimpleAccountList();
|
||||||
if (accountList.value.length === 0) {
|
if (accountList.value.length === 0) {
|
||||||
message.error('未配置公众号,请在【公众号管理 -> 账号管理】菜单,进行配置');
|
message.error('未配置公众号,请在【公众号管理 -> 账号管理】菜单,进行配置');
|
||||||
delView(unref(currentRoute));
|
|
||||||
await push({ name: 'MpAccount' });
|
await push({ name: 'MpAccount' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -46,7 +47,7 @@ const handleQuery = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 切换选中公众号
|
// 切换选中公众号
|
||||||
const onChanged = (id?: number) => {
|
const onChanged = (id: SelectValue) => {
|
||||||
const found = accountList.value.find((v) => v.id === id);
|
const found = accountList.value.find((v) => v.id === id);
|
||||||
if (found) {
|
if (found) {
|
||||||
account.name = found.name;
|
account.name = found.name;
|
||||||
@@ -59,24 +60,14 @@ onMounted(handleQuery);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-select
|
<Select
|
||||||
v-model:value="account.id"
|
v-model:value="account.id"
|
||||||
placeholder="请选择公众号"
|
placeholder="请选择公众号"
|
||||||
class="!w-240px"
|
class="!w-[240px]"
|
||||||
@change="onChanged"
|
@change="onChanged"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<Select.Option v-for="item in accountList" :key="item.id" :value="item.id">
|
||||||
v-for="item in accountList"
|
|
||||||
:key="item.id"
|
|
||||||
:value="item.id"
|
|
||||||
>
|
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</a-select-option>
|
</Select.Option>
|
||||||
</a-select>
|
</Select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.w-240px {
|
|
||||||
width: 240px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxLocation } from './main.vue';
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxMaterialSelect } from './main.vue';
|
||||||
|
|
||||||
export { MaterialType, NewsType } from './types';
|
export { MaterialType, NewsType } from './types';
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import { Button, Pagination, Row, Spin, Table } from 'ant-design-vue';
|
|||||||
import * as MpDraftApi from '#/api/mp/draft';
|
import * as MpDraftApi from '#/api/mp/draft';
|
||||||
import * as MpFreePublishApi from '#/api/mp/freePublish';
|
import * as MpFreePublishApi from '#/api/mp/freePublish';
|
||||||
import * as MpMaterialApi from '#/api/mp/material';
|
import * as MpMaterialApi from '#/api/mp/material';
|
||||||
import WxNews from '#/views/mp/components/wx-news';
|
import { WxNews } from '#/views/mp/components/wx-news';
|
||||||
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
import { WxVideoPlayer } from '#/views/mp/components/wx-video-play';
|
||||||
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
import { WxVoicePlayer } from '#/views/mp/components/wx-voice-play';
|
||||||
|
|
||||||
import { NewsType } from './types';
|
import { NewsType } from './types';
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import WxLocation from '#/views/mp/components/wx-location';
|
import { WxLocation } from '#/views/mp/components/wx-location';
|
||||||
import WxMusic from '#/views/mp/components/wx-music';
|
import { WxMusic } from '#/views/mp/components/wx-music';
|
||||||
import WxNews from '#/views/mp/components/wx-news';
|
import { WxNews } from '#/views/mp/components/wx-news';
|
||||||
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
import { WxVideoPlayer } from '#/views/mp/components/wx-video-play';
|
||||||
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
import { WxVoicePlayer } from '#/views/mp/components/wx-voice-play';
|
||||||
|
|
||||||
import { MsgType } from '../types';
|
import { MsgType } from '../types';
|
||||||
import MsgEvent from './MsgEvent.vue';
|
import MsgEvent from './MsgEvent.vue';
|
||||||
@@ -29,7 +29,7 @@ defineProps<{
|
|||||||
|
|
||||||
<div v-else-if="item.type === MsgType.Image">
|
<div v-else-if="item.type === MsgType.Image">
|
||||||
<a :href="item.mediaUrl" target="_blank">
|
<a :href="item.mediaUrl" target="_blank">
|
||||||
<img :src="item.mediaUrl" style="width: 100px" alt="图片消息" />
|
<img :src="item.mediaUrl" class="w-[100px]" alt="图片消息" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -40,14 +40,14 @@ defineProps<{
|
|||||||
<WxVideoPlayer :url="item.mediaUrl" />
|
<WxVideoPlayer :url="item.mediaUrl" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="item.type === MsgType.Link" class="link-card">
|
<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">
|
<a :href="item.url" target="_blank" class="text-success no-underline">
|
||||||
<div class="link-title">
|
<div class="flex items-center text-sm font-medium text-[#52c41a]">
|
||||||
<IconifyIcon icon="mdi:link" class="mr-1" />
|
<IconifyIcon icon="mdi:link" class="mr-1" />
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="link-description">{{ item.description }}</div>
|
<div class="text-xs text-[#666]">{{ item.description }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="item.type === MsgType.Location">
|
<div v-else-if="item.type === MsgType.Location">
|
||||||
@@ -58,7 +58,7 @@ defineProps<{
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="item.type === MsgType.News" class="news-wrapper">
|
<div v-else-if="item.type === MsgType.News" class="w-[300px]">
|
||||||
<WxNews :articles="item.articles" />
|
<WxNews :articles="item.articles" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -73,28 +73,3 @@ defineProps<{
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.link-card {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #52c41a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-description {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-wrapper {
|
|
||||||
width: 300px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxMsg } from './main.vue';
|
||||||
|
|
||||||
export { MsgType } from './types';
|
export { MsgType } from './types';
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Button, message, Spin } from 'ant-design-vue';
|
|||||||
|
|
||||||
import { getMessagePage, sendMessage } from '#/api/mp/message';
|
import { getMessagePage, sendMessage } from '#/api/mp/message';
|
||||||
import { getUser } from '#/api/mp/user';
|
import { getUser } from '#/api/mp/user';
|
||||||
import WxReplySelect from '#/views/mp/components/wx-reply';
|
import { WxReplySelect } from '#/views/mp/components/wx-reply';
|
||||||
|
|
||||||
import MsgList from './components/MsgList.vue';
|
import MsgList from './components/MsgList.vue';
|
||||||
|
|
||||||
@@ -144,15 +144,22 @@ const scrollToBottom = async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="wx-msg-container">
|
<div class="flex h-full flex-col">
|
||||||
<div ref="msgDivRef" class="msg-div">
|
<div ref="msgDivRef" class="mx-2.5 flex-1 overflow-auto bg-[#eaeaea]">
|
||||||
<!-- 加载更多 -->
|
<!-- 加载更多 -->
|
||||||
<Spin :spinning="loading" />
|
<Spin :spinning="loading" />
|
||||||
<div v-if="!loading">
|
<div v-if="!loading">
|
||||||
<div v-if="hasMore" class="load-more-btn" @click="loadMore">
|
<div
|
||||||
|
v-if="hasMore"
|
||||||
|
class="cursor-pointer rounded p-3 text-center text-sm text-[#409eff] transition-colors duration-300 hover:bg-[#f5f7fa]"
|
||||||
|
@click="loadMore"
|
||||||
|
>
|
||||||
<span>点击加载更多</span>
|
<span>点击加载更多</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="load-more-btn disabled">
|
<div
|
||||||
|
v-else
|
||||||
|
class="cursor-not-allowed rounded p-3 text-center text-sm text-[#909399] hover:bg-transparent"
|
||||||
|
>
|
||||||
<span>没有更多了</span>
|
<span>没有更多了</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -161,62 +168,13 @@ const scrollToBottom = async () => {
|
|||||||
<MsgList :list="list" :account-id="accountId" :user="user" />
|
<MsgList :list="list" :account-id="accountId" :user="user" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="msg-send">
|
<div class="p-2.5">
|
||||||
<Spin :spinning="sendLoading">
|
<Spin :spinning="sendLoading">
|
||||||
<WxReplySelect ref="replySelectRef" v-model="reply" />
|
<WxReplySelect ref="replySelectRef" v-model="reply" />
|
||||||
<Button type="primary" class="send-but" @click="sendMsg">
|
<Button type="primary" class="float-right mb-2 mt-2" @click="sendMsg">
|
||||||
发送(S)
|
发送(S)
|
||||||
</Button>
|
</Button>
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.wx-msg-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msg-div {
|
|
||||||
flex: 1;
|
|
||||||
height: 50vh;
|
|
||||||
margin: 0 10px;
|
|
||||||
overflow: auto;
|
|
||||||
background-color: #eaeaea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.load-more-btn {
|
|
||||||
padding: 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #409eff;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
transition: background-color 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
color: #909399;
|
|
||||||
cursor: not-allowed;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.msg-send {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-but {
|
|
||||||
float: right;
|
|
||||||
margin-top: 8px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxMusic } from './main.vue';
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxNews } from './main.vue';
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useAccessStore } from '@vben/stores';
|
|||||||
|
|
||||||
import { Button, Col, message, Modal, Row, Upload } from 'ant-design-vue';
|
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/wx-material-select';
|
||||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||||
|
|
||||||
defineOptions({ name: 'TabImage' });
|
defineOptions({ name: 'TabImage' });
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
Upload,
|
Upload,
|
||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
import WxMaterialSelect from '#/views/mp/components/wx-material-select';
|
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||||
|
|
||||||
defineOptions({ name: 'TabMusic' });
|
defineOptions({ name: 'TabMusic' });
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { IconifyIcon } from '@vben/icons';
|
|||||||
|
|
||||||
import { Button, Col, Modal, Row } from 'ant-design-vue';
|
import { Button, Col, Modal, Row } from 'ant-design-vue';
|
||||||
|
|
||||||
import WxMaterialSelect from '#/views/mp/components/wx-material-select';
|
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||||
import WxNews from '#/views/mp/components/wx-news';
|
import { WxNews } from '#/views/mp/components/wx-news';
|
||||||
|
|
||||||
import { NewsType } from './types';
|
import { NewsType } from './types';
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import {
|
|||||||
Upload,
|
Upload,
|
||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
import WxMaterialSelect from '#/views/mp/components/wx-material-select';
|
import { WxMaterialSelect } from '#/views/mp/components/wx-material-select';
|
||||||
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
import { WxVideoPlayer } from '#/views/mp/components/wx-video-play';
|
||||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||||
|
|
||||||
defineOptions({ name: 'TabVideo' });
|
defineOptions({ name: 'TabVideo' });
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { useAccessStore } from '@vben/stores';
|
|||||||
|
|
||||||
import { Button, Col, message, Modal, Row, Upload } from 'ant-design-vue';
|
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/wx-material-select';
|
||||||
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
import { WxVoicePlayer } from '#/views/mp/components/wx-voice-play';
|
||||||
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
import { UploadType, useBeforeUpload } from '#/views/mp/hooks/useUpload';
|
||||||
|
|
||||||
defineOptions({ name: 'TabVoice' });
|
defineOptions({ name: 'TabVoice' });
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export type { NewsType, Reply, ReplyType } from './components/types';
|
export type { NewsType, Reply, ReplyType } from './components/types';
|
||||||
export { createEmptyReply } from './components/types';
|
export { createEmptyReply } from './components/types';
|
||||||
|
|
||||||
export { default } from './main.vue';
|
export { default as WxReplySelect } from './main.vue';
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxVideoPlayer } from './main.vue';
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './main.vue';
|
export { default as WxVoicePlayer } from './main.vue';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { useAccess } from '@vben/access';
|
import { useAccess } from '@vben/access';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { Spin } from 'ant-design-vue';
|
import { Button, Spin } from 'ant-design-vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
list: any[];
|
list: any[];
|
||||||
@@ -25,7 +25,7 @@ const { hasAccessByCodes } = useAccess();
|
|||||||
<div class="item-name">{{ item.name }}</div>
|
<div class="item-name">{{ item.name }}</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<a-button
|
<Button
|
||||||
v-if="hasAccessByCodes(['mp:material:delete'])"
|
v-if="hasAccessByCodes(['mp:material:delete'])"
|
||||||
danger
|
danger
|
||||||
shape="circle"
|
shape="circle"
|
||||||
@@ -35,7 +35,7 @@ const { hasAccessByCodes } = useAccess();
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<IconifyIcon icon="mdi:delete" />
|
<IconifyIcon icon="mdi:delete" />
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { inject, reactive, ref } from 'vue';
|
|||||||
|
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { message, Upload } from 'ant-design-vue';
|
import { Button, message, Upload } from 'ant-design-vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
beforeImageUpload,
|
beforeImageUpload,
|
||||||
@@ -83,22 +83,19 @@ const customRequest: UploadProps['customRequest'] = async (options) => {
|
|||||||
:action="UPLOAD_URL"
|
:action="UPLOAD_URL"
|
||||||
:before-upload="onBeforeUpload"
|
:before-upload="onBeforeUpload"
|
||||||
:custom-request="customRequest"
|
:custom-request="customRequest"
|
||||||
:data="uploadData"
|
|
||||||
:file-list="fileList"
|
:file-list="fileList"
|
||||||
:headers="HEADERS"
|
:headers="HEADERS"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
>
|
>
|
||||||
<a-button type="primary">
|
<Button type="primary">
|
||||||
<IconifyIcon icon="mdi:upload" class="mr-1" />
|
<IconifyIcon icon="mdi:upload" class="mr-1" />
|
||||||
点击上传
|
点击上传
|
||||||
</a-button>
|
</Button>
|
||||||
<template #itemRender="{ file, actions }">
|
<template #itemRender="{ file, actions }">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span>{{ file.name }}</span>
|
<span>{{ file.name }}</span>
|
||||||
<a-button type="link" size="small" @click="actions.remove">
|
<Button type="link" size="small" @click="actions.remove"> 删除 </Button>
|
||||||
删除
|
|
||||||
</a-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Upload>
|
</Upload>
|
||||||
|
|||||||
@@ -7,7 +7,15 @@ import { inject, reactive, ref } from 'vue';
|
|||||||
|
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { message, Modal, Upload } from 'ant-design-vue';
|
import {
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
message,
|
||||||
|
Modal,
|
||||||
|
Upload,
|
||||||
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
import { beforeVideoUpload, HEADERS, UPLOAD_URL, UploadType } from './upload';
|
import { beforeVideoUpload, HEADERS, UPLOAD_URL, UploadType } from './upload';
|
||||||
|
|
||||||
@@ -28,8 +36,10 @@ const emit = defineEmits<{
|
|||||||
const accountId = inject<number>('accountId');
|
const accountId = inject<number>('accountId');
|
||||||
|
|
||||||
const uploadRules = {
|
const uploadRules = {
|
||||||
introduction: [{ message: '请输入描述', required: true, trigger: 'blur' }],
|
introduction: [
|
||||||
title: [{ message: '请输入标题', required: true, trigger: 'blur' }],
|
{ message: '请输入描述', required: true, trigger: 'blur' } as const,
|
||||||
|
],
|
||||||
|
title: [{ message: '请输入标题', required: true, trigger: 'blur' } as const],
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -119,36 +129,36 @@ const customRequest: UploadProps['customRequest'] = async (options) => {
|
|||||||
:multiple="true"
|
:multiple="true"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
>
|
>
|
||||||
<a-button type="primary">
|
<Button type="primary">
|
||||||
<IconifyIcon icon="mdi:video-plus" class="mr-1" />
|
<IconifyIcon icon="mdi:video-plus" class="mr-1" />
|
||||||
选择视频
|
选择视频
|
||||||
</a-button>
|
</Button>
|
||||||
</Upload>
|
</Upload>
|
||||||
<div class="mb-4 ml-1 text-sm text-gray-500">
|
<div class="mb-4 ml-1 text-sm text-gray-500">
|
||||||
格式支持 MP4,文件大小不超过 10MB
|
格式支持 MP4,文件大小不超过 10MB
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-divider />
|
<Divider />
|
||||||
|
|
||||||
<a-form
|
<Form
|
||||||
ref="uploadFormRef"
|
ref="uploadFormRef"
|
||||||
:model="uploadData"
|
:model="uploadData"
|
||||||
:rules="uploadRules"
|
:rules="uploadRules"
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
>
|
>
|
||||||
<a-form-item label="标题" name="title">
|
<Form.Item label="标题" name="title">
|
||||||
<a-input
|
<Input
|
||||||
v-model:value="uploadData.title"
|
v-model:value="uploadData.title"
|
||||||
placeholder="标题将展示在相关播放页面,建议填写清晰、准确、生动的标题"
|
placeholder="标题将展示在相关播放页面,建议填写清晰、准确、生动的标题"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</Form.Item>
|
||||||
<a-form-item label="描述" name="introduction">
|
<Form.Item label="描述" name="introduction">
|
||||||
<a-textarea
|
<Input.TextArea
|
||||||
v-model:value="uploadData.introduction"
|
v-model:value="uploadData.introduction"
|
||||||
:rows="3"
|
:rows="3"
|
||||||
placeholder="介绍语将展示在相关播放页面,建议填写简洁明确、有信息量的内容"
|
placeholder="介绍语将展示在相关播放页面,建议填写简洁明确、有信息量的内容"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</Form.Item>
|
||||||
</a-form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { useAccess } from '@vben/access';
|
|||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { formatDate2 } from '@vben/utils';
|
import { formatDate2 } from '@vben/utils';
|
||||||
|
|
||||||
|
import { Button, Table } from 'ant-design-vue';
|
||||||
|
|
||||||
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -17,18 +19,33 @@ const emit = defineEmits<{
|
|||||||
const { hasAccessByCodes } = useAccess();
|
const { hasAccessByCodes } = useAccess();
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ align: 'center', dataIndex: 'mediaId', key: 'mediaId', title: '编号' },
|
|
||||||
{ align: 'center', dataIndex: 'name', key: 'name', title: '文件名' },
|
|
||||||
{ align: 'center', dataIndex: 'title', key: 'title', title: '标题' },
|
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center' as const,
|
||||||
|
dataIndex: 'mediaId',
|
||||||
|
key: 'mediaId',
|
||||||
|
title: '编号',
|
||||||
|
},
|
||||||
|
{ align: 'center' as const, dataIndex: 'name', key: 'name', title: '文件名' },
|
||||||
|
{ align: 'center' as const, dataIndex: 'title', key: 'title', title: '标题' },
|
||||||
|
{
|
||||||
|
align: 'center' as const,
|
||||||
dataIndex: 'introduction',
|
dataIndex: 'introduction',
|
||||||
key: 'introduction',
|
key: 'introduction',
|
||||||
title: '介绍',
|
title: '介绍',
|
||||||
},
|
},
|
||||||
{ align: 'center', key: 'video', title: '视频' },
|
{ align: 'center' as const, key: 'video', title: '视频' },
|
||||||
{ align: 'center', key: 'createTime', title: '上传时间', width: 180 },
|
{
|
||||||
{ align: 'center', fixed: 'right', key: 'action', title: '操作' },
|
align: 'center' as const,
|
||||||
|
key: 'createTime',
|
||||||
|
title: '上传时间',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'center' as const,
|
||||||
|
fixed: 'right' as const,
|
||||||
|
key: 'action',
|
||||||
|
title: '操作',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 下载文件
|
// 下载文件
|
||||||
@@ -38,7 +55,7 @@ const handleDownload = (url: string) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-table
|
<Table
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data-source="props.list"
|
:data-source="props.list"
|
||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
@@ -55,11 +72,11 @@ const handleDownload = (url: string) => {
|
|||||||
{{ formatDate2(record.createTime) }}
|
{{ formatDate2(record.createTime) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'action'">
|
<template v-else-if="column.key === 'action'">
|
||||||
<a-button type="link" @click="handleDownload(record.url)">
|
<Button type="link" @click="handleDownload(record.url)">
|
||||||
<IconifyIcon icon="mdi:download" />
|
<IconifyIcon icon="mdi:download" />
|
||||||
下载
|
下载
|
||||||
</a-button>
|
</Button>
|
||||||
<a-button
|
<Button
|
||||||
v-if="hasAccessByCodes(['mp:material:delete'])"
|
v-if="hasAccessByCodes(['mp:material:delete'])"
|
||||||
danger
|
danger
|
||||||
type="link"
|
type="link"
|
||||||
@@ -67,8 +84,8 @@ const handleDownload = (url: string) => {
|
|||||||
>
|
>
|
||||||
<IconifyIcon icon="mdi:delete" />
|
<IconifyIcon icon="mdi:delete" />
|
||||||
删除
|
删除
|
||||||
</a-button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</Table>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { useAccess } from '@vben/access';
|
|||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { formatDate2 } from '@vben/utils';
|
import { formatDate2 } from '@vben/utils';
|
||||||
|
|
||||||
|
import { Button, Table } from 'ant-design-vue';
|
||||||
|
|
||||||
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -17,11 +19,26 @@ const emit = defineEmits<{
|
|||||||
const { hasAccessByCodes } = useAccess();
|
const { hasAccessByCodes } = useAccess();
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ align: 'center', dataIndex: 'mediaId', key: 'mediaId', title: '编号' },
|
{
|
||||||
{ align: 'center', dataIndex: 'name', key: 'name', title: '文件名' },
|
align: 'center' as const,
|
||||||
{ align: 'center', key: 'voice', title: '语音' },
|
dataIndex: 'mediaId',
|
||||||
{ align: 'center', key: 'createTime', title: '上传时间', width: 180 },
|
key: 'mediaId',
|
||||||
{ align: 'center', fixed: 'right', key: 'action', title: '操作' },
|
title: '编号',
|
||||||
|
},
|
||||||
|
{ align: 'center' as const, dataIndex: 'name', key: 'name', title: '文件名' },
|
||||||
|
{ align: 'center' as const, key: 'voice', title: '语音' },
|
||||||
|
{
|
||||||
|
align: 'center' as const,
|
||||||
|
key: 'createTime',
|
||||||
|
title: '上传时间',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'center' as const,
|
||||||
|
fixed: 'right' as const,
|
||||||
|
key: 'action',
|
||||||
|
title: '操作',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleDownload = (url: string) => {
|
const handleDownload = (url: string) => {
|
||||||
@@ -30,7 +47,7 @@ const handleDownload = (url: string) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-table
|
<Table
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data-source="props.list"
|
:data-source="props.list"
|
||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
@@ -47,11 +64,11 @@ const handleDownload = (url: string) => {
|
|||||||
{{ formatDate2(record.createTime) }}
|
{{ formatDate2(record.createTime) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'action'">
|
<template v-else-if="column.key === 'action'">
|
||||||
<a-button type="link" @click="handleDownload(record.url)">
|
<Button type="link" @click="handleDownload(record.url)">
|
||||||
<IconifyIcon icon="mdi:download" />
|
<IconifyIcon icon="mdi:download" />
|
||||||
下载
|
下载
|
||||||
</a-button>
|
</Button>
|
||||||
<a-button
|
<Button
|
||||||
v-if="hasAccessByCodes(['mp:material:delete'])"
|
v-if="hasAccessByCodes(['mp:material:delete'])"
|
||||||
danger
|
danger
|
||||||
type="link"
|
type="link"
|
||||||
@@ -59,8 +76,8 @@ const handleDownload = (url: string) => {
|
|||||||
>
|
>
|
||||||
<IconifyIcon icon="mdi:delete" />
|
<IconifyIcon icon="mdi:delete" />
|
||||||
删除
|
删除
|
||||||
</a-button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</Table>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,10 +5,18 @@ import { useAccess } from '@vben/access';
|
|||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { message, Modal, Tabs } from 'ant-design-vue';
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Form,
|
||||||
|
message,
|
||||||
|
Modal,
|
||||||
|
Pagination,
|
||||||
|
Tabs,
|
||||||
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
import * as MpMaterialApi from '#/api/mp/material';
|
import * as MpMaterialApi from '#/api/mp/material';
|
||||||
import WxAccountSelect from '#/views/mp/components/wx-account-select';
|
import { WxAccountSelect } from '#/views/mp/components/wx-account-select';
|
||||||
|
|
||||||
import ImageTable from './components/ImageTable.vue';
|
import ImageTable from './components/ImageTable.vue';
|
||||||
import { UploadType } from './components/upload';
|
import { UploadType } from './components/upload';
|
||||||
@@ -97,15 +105,15 @@ const handleDelete = async (id: number) => {
|
|||||||
title="公众号素材"
|
title="公众号素材"
|
||||||
>
|
>
|
||||||
<!-- 搜索工作栏 -->
|
<!-- 搜索工作栏 -->
|
||||||
<a-card class="mb-4" :bordered="false">
|
<Card class="mb-4" :bordered="false">
|
||||||
<a-form :model="queryParams" layout="inline">
|
<Form :model="queryParams" layout="inline">
|
||||||
<a-form-item label="公众号">
|
<Form.Item label="公众号">
|
||||||
<WxAccountSelect @change="onAccountChanged" />
|
<WxAccountSelect @change="onAccountChanged" />
|
||||||
</a-form-item>
|
</Form.Item>
|
||||||
</a-form>
|
</Form>
|
||||||
</a-card>
|
</Card>
|
||||||
|
|
||||||
<a-card :bordered="false">
|
<Card :bordered="false">
|
||||||
<Tabs v-model:active-key="type" @change="onTabChange">
|
<Tabs v-model:active-key="type" @change="onTabChange">
|
||||||
<!-- tab 1:图片 -->
|
<!-- tab 1:图片 -->
|
||||||
<Tabs.TabPane :key="UploadType.Image">
|
<Tabs.TabPane :key="UploadType.Image">
|
||||||
@@ -126,7 +134,7 @@ const handleDelete = async (id: number) => {
|
|||||||
<ImageTable :list="list" :loading="loading" @delete="handleDelete" />
|
<ImageTable :list="list" :loading="loading" @delete="handleDelete" />
|
||||||
<!-- 分页组件 -->
|
<!-- 分页组件 -->
|
||||||
<div class="mt-4 flex justify-end">
|
<div class="mt-4 flex justify-end">
|
||||||
<a-pagination
|
<Pagination
|
||||||
v-model:current="queryParams.pageNo"
|
v-model:current="queryParams.pageNo"
|
||||||
v-model:page-size="queryParams.pageSize"
|
v-model:page-size="queryParams.pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
@@ -140,10 +148,9 @@ const handleDelete = async (id: number) => {
|
|||||||
<!-- tab 2:语音 -->
|
<!-- tab 2:语音 -->
|
||||||
<Tabs.TabPane :key="UploadType.Voice">
|
<Tabs.TabPane :key="UploadType.Voice">
|
||||||
<template #tab>
|
<template #tab>
|
||||||
<span class="flex items-center">
|
<span class="flex items-center"></span>
|
||||||
<IconifyIcon icon="mdi:microphone" class="mr-1" />
|
<IconifyIcon icon="mdi:microphone" class="mr-1" />
|
||||||
语音
|
<span>语音</span>
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
<UploadFile
|
<UploadFile
|
||||||
v-if="hasAccessByCodes(['mp:material:upload-permanent'])"
|
v-if="hasAccessByCodes(['mp:material:upload-permanent'])"
|
||||||
@@ -156,7 +163,7 @@ const handleDelete = async (id: number) => {
|
|||||||
<VoiceTable :list="list" :loading="loading" @delete="handleDelete" />
|
<VoiceTable :list="list" :loading="loading" @delete="handleDelete" />
|
||||||
<!-- 分页组件 -->
|
<!-- 分页组件 -->
|
||||||
<div class="mt-4 flex justify-end">
|
<div class="mt-4 flex justify-end">
|
||||||
<a-pagination
|
<Pagination
|
||||||
v-model:current="queryParams.pageNo"
|
v-model:current="queryParams.pageNo"
|
||||||
v-model:page-size="queryParams.pageSize"
|
v-model:page-size="queryParams.pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
@@ -175,20 +182,20 @@ const handleDelete = async (id: number) => {
|
|||||||
视频
|
视频
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<a-button
|
<Button
|
||||||
v-if="hasAccessByCodes(['mp:material:upload-permanent'])"
|
v-if="hasAccessByCodes(['mp:material:upload-permanent'])"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="showCreateVideo = true"
|
@click="showCreateVideo = true"
|
||||||
>
|
>
|
||||||
新建视频
|
新建视频
|
||||||
</a-button>
|
</Button>
|
||||||
<!-- 新建视频的弹窗 -->
|
<!-- 新建视频的弹窗 -->
|
||||||
<UploadVideo v-model:open="showCreateVideo" @uploaded="getList" />
|
<UploadVideo v-model:open="showCreateVideo" @uploaded="getList" />
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<VideoTable :list="list" :loading="loading" @delete="handleDelete" />
|
<VideoTable :list="list" :loading="loading" @delete="handleDelete" />
|
||||||
<!-- 分页组件 -->
|
<!-- 分页组件 -->
|
||||||
<div class="mt-4 flex justify-end">
|
<div class="mt-4 flex justify-end">
|
||||||
<a-pagination
|
<Pagination
|
||||||
v-model:current="queryParams.pageNo"
|
v-model:current="queryParams.pageNo"
|
||||||
v-model:page-size="queryParams.pageSize"
|
v-model:page-size="queryParams.pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
@@ -199,6 +206,6 @@ const handleDelete = async (id: number) => {
|
|||||||
</div>
|
</div>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</a-card>
|
</Card>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import { formatDate2 } from '@vben/utils';
|
|||||||
|
|
||||||
import { Button, Image, Table, Tag } from 'ant-design-vue';
|
import { Button, Image, Table, Tag } from 'ant-design-vue';
|
||||||
|
|
||||||
import WxLocation from '#/views/mp/components/wx-location';
|
import { WxLocation } from '#/views/mp/components/wx-location';
|
||||||
import { MsgType } from '#/views/mp/components/wx-msg/types';
|
import { MsgType } from '#/views/mp/components/wx-msg/types';
|
||||||
import WxMusic from '#/views/mp/components/wx-music';
|
import { WxMusic } from '#/views/mp/components/wx-music';
|
||||||
import WxNews from '#/views/mp/components/wx-news';
|
import { WxNews } from '#/views/mp/components/wx-news';
|
||||||
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
import { WxVideoPlayer } from '#/views/mp/components/wx-video-play';
|
||||||
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
import { WxVoicePlayer } from '#/views/mp/components/wx-voice-play';
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import {
|
|||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
import { getMessagePage } from '#/api/mp/message';
|
import { getMessagePage } from '#/api/mp/message';
|
||||||
import WxAccountSelect from '#/views/mp/components/wx-account-select';
|
import { WxAccountSelect } from '#/views/mp/components/wx-account-select';
|
||||||
import WxMsg from '#/views/mp/components/wx-msg';
|
import { WxMsg } from '#/views/mp/components/wx-msg';
|
||||||
import { MsgType } from '#/views/mp/components/wx-msg/types';
|
import { MsgType } from '#/views/mp/components/wx-msg/types';
|
||||||
|
|
||||||
import MessageTable from './MessageTable.vue';
|
import MessageTable from './MessageTable.vue';
|
||||||
|
|||||||
Reference in New Issue
Block a user