style: 代码风格统一
This commit is contained in:
@@ -4,7 +4,7 @@ VITE_PORT=5777
|
|||||||
VITE_BASE=/
|
VITE_BASE=/
|
||||||
|
|
||||||
# 请求路径
|
# 请求路径
|
||||||
VITE_BASE_URL=http://127.0.0.1:48080
|
VITE_BASE_URL=http://47.103.66.220:48080
|
||||||
# 接口地址
|
# 接口地址
|
||||||
VITE_GLOB_API_URL=http://47.103.66.220:48080/admin-api
|
VITE_GLOB_API_URL=http://47.103.66.220:48080/admin-api
|
||||||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
|
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { Menu, RawMenu } from './components/types';
|
import type { Menu, RawMenu } from './modules/types';
|
||||||
|
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
@@ -15,10 +15,10 @@ import {
|
|||||||
|
|
||||||
import * as MpMenuApi from '#/api/mp/menu';
|
import * as MpMenuApi from '#/api/mp/menu';
|
||||||
import * as UtilsTree from '#/utils/tree';
|
import * as UtilsTree from '#/utils/tree';
|
||||||
import WxAccountSelect from '#/views/mp/components/wx-account-select/main.vue';
|
|
||||||
import { Level, MENU_NOT_SELECTED } from '#/views/mp/menu/data';
|
import { Level, MENU_NOT_SELECTED } from '#/views/mp/menu/data';
|
||||||
import MenuEditor from '#/views/mp/menu/modules/menu-editor.vue';
|
import MenuEditor from '#/views/mp/menu/modules/menu-editor.vue';
|
||||||
import MenuPreviewer from '#/views/mp/menu/modules/menu-previewer.vue';
|
import MenuPreviewer from '#/views/mp/menu/modules/menu-previewer.vue';
|
||||||
|
import WxAccountSelect from '#/views/mp/modules/wx-account-select/main.vue';
|
||||||
|
|
||||||
defineOptions({ name: 'MpMenu' });
|
defineOptions({ name: 'MpMenu' });
|
||||||
|
|
||||||
@@ -57,14 +57,14 @@ const tempSelfObj = ref<{
|
|||||||
const dialogNewsVisible = ref(false); // 跳转图文时的素材选择弹窗
|
const dialogNewsVisible = ref(false); // 跳转图文时的素材选择弹窗
|
||||||
|
|
||||||
/** 侦听公众号变化 */
|
/** 侦听公众号变化 */
|
||||||
const onAccountChanged = (id: number, name: string) => {
|
function onAccountChanged(id: number, name: string) {
|
||||||
accountId.value = id;
|
accountId.value = id;
|
||||||
accountName.value = name;
|
accountName.value = name;
|
||||||
getList();
|
getList();
|
||||||
};
|
}
|
||||||
|
|
||||||
/** 查询并转换菜单 */
|
/** 查询并转换菜单 */
|
||||||
const getList = async () => {
|
async function getList() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const data = await MpMenuApi.getMenuList(accountId.value);
|
const data = await MpMenuApi.getMenuList(accountId.value);
|
||||||
@@ -73,16 +73,16 @@ const getList = async () => {
|
|||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
function handleQuery() {
|
||||||
resetForm();
|
resetForm();
|
||||||
getList();
|
getList();
|
||||||
};
|
}
|
||||||
|
|
||||||
// 将后端返回的 menuList,转换成前端的 menuList
|
/** 将后端返回的 menuList,转换成前端的 menuList */
|
||||||
const menuListToFrontend = (list: any[]) => {
|
function menuListToFrontend(list: any[]) {
|
||||||
if (!list) return [];
|
if (!list) return [];
|
||||||
|
|
||||||
const result: RawMenu[] = [];
|
const result: RawMenu[] = [];
|
||||||
@@ -107,10 +107,10 @@ const menuListToFrontend = (list: any[]) => {
|
|||||||
result.push(menu as RawMenu);
|
result.push(menu as RawMenu);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
|
|
||||||
// 重置表单,清空表单数据
|
/** 重置表单,清空表单数据 */
|
||||||
const resetForm = () => {
|
function resetForm() {
|
||||||
// 菜单操作
|
// 菜单操作
|
||||||
activeIndex.value = MENU_NOT_SELECTED;
|
activeIndex.value = MENU_NOT_SELECTED;
|
||||||
parentIndex.value = -1;
|
parentIndex.value = -1;
|
||||||
@@ -120,11 +120,11 @@ const resetForm = () => {
|
|||||||
activeMenu.value = {};
|
activeMenu.value = {};
|
||||||
tempSelfObj.value = { grand: Level.Undefined, x: 0, y: 0 };
|
tempSelfObj.value = { grand: Level.Undefined, x: 0, y: 0 };
|
||||||
dialogNewsVisible.value = false;
|
dialogNewsVisible.value = false;
|
||||||
};
|
}
|
||||||
|
|
||||||
// ======================== 菜单操作 ========================
|
// ======================== 菜单操作 ========================
|
||||||
// 一级菜单点击事件
|
/** 一级菜单点击事件 */
|
||||||
const menuClicked = (parent: Menu, x: number) => {
|
function menuClicked(parent: Menu, x: number) {
|
||||||
// 右侧的表单相关
|
// 右侧的表单相关
|
||||||
showRightPanel.value = true; // 右边菜单
|
showRightPanel.value = true; // 右边菜单
|
||||||
activeMenu.value = parent; // 这个如果放在顶部,flag 会没有。因为重新赋值了。
|
activeMenu.value = parent; // 这个如果放在顶部,flag 会没有。因为重新赋值了。
|
||||||
@@ -135,10 +135,10 @@ const menuClicked = (parent: Menu, x: number) => {
|
|||||||
// 左侧的选中
|
// 左侧的选中
|
||||||
activeIndex.value = `${x}`; // 菜单选中样式
|
activeIndex.value = `${x}`; // 菜单选中样式
|
||||||
parentIndex.value = x; // 二级菜单显示标志
|
parentIndex.value = x; // 二级菜单显示标志
|
||||||
};
|
}
|
||||||
|
|
||||||
// 二级菜单点击事件
|
/** 二级菜单点击事件 */
|
||||||
const subMenuClicked = (child: Menu, x: number, y: number) => {
|
function subMenuClicked(child: Menu, x: number, y: number) {
|
||||||
// 右侧的表单相关
|
// 右侧的表单相关
|
||||||
showRightPanel.value = true; // 右边菜单
|
showRightPanel.value = true; // 右边菜单
|
||||||
activeMenu.value = child; // 将点击的数据放到临时变量,对象有引用作用
|
activeMenu.value = child; // 将点击的数据放到临时变量,对象有引用作用
|
||||||
@@ -149,10 +149,10 @@ const subMenuClicked = (child: Menu, x: number, y: number) => {
|
|||||||
|
|
||||||
// 左侧的选中
|
// 左侧的选中
|
||||||
activeIndex.value = `${x}-${y}`;
|
activeIndex.value = `${x}-${y}`;
|
||||||
};
|
}
|
||||||
|
|
||||||
// 删除当前菜单
|
/** 删除当前菜单 */
|
||||||
const onDeleteMenu = async () => {
|
async function onDeleteMenu() {
|
||||||
try {
|
try {
|
||||||
await confirm('确定要删除吗?');
|
await confirm('确定要删除吗?');
|
||||||
if (tempSelfObj.value.grand === Level.Parent) {
|
if (tempSelfObj.value.grand === Level.Parent) {
|
||||||
@@ -175,10 +175,11 @@ const onDeleteMenu = async () => {
|
|||||||
} catch {
|
} catch {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// ======================== 菜单编辑 ========================
|
// ======================== 菜单编辑 ========================
|
||||||
const onSave = async () => {
|
/** 保存菜单 */
|
||||||
|
async function onSave() {
|
||||||
try {
|
try {
|
||||||
await confirm('确定要保存吗?');
|
await confirm('确定要保存吗?');
|
||||||
const loadingInstance = ElLoading.service({
|
const loadingInstance = ElLoading.service({
|
||||||
@@ -194,9 +195,10 @@ const onSave = async () => {
|
|||||||
} catch {
|
} catch {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const onClear = async () => {
|
/** 清空菜单 */
|
||||||
|
async function onClear() {
|
||||||
try {
|
try {
|
||||||
await confirm('确定要删除吗?');
|
await confirm('确定要删除吗?');
|
||||||
const loadingInstance = ElLoading.service({
|
const loadingInstance = ElLoading.service({
|
||||||
@@ -212,10 +214,10 @@ const onClear = async () => {
|
|||||||
} catch {
|
} catch {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// 将前端的 menuList,转换成后端接收的 menuList
|
/** 将前端的 menuList,转换成后端接收的 menuList */
|
||||||
const menuListToBackend = () => {
|
function menuListToBackend() {
|
||||||
const result: any[] = [];
|
const result: any[] = [];
|
||||||
menuList.value.forEach((item) => {
|
menuList.value.forEach((item) => {
|
||||||
const menu = menuToBackend(item);
|
const menu = menuToBackend(item);
|
||||||
@@ -231,11 +233,11 @@ const menuListToBackend = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
|
|
||||||
// 将前端的 menu,转换成后端接收的 menu
|
/** 将前端的 menu,转换成后端接收的 menu */
|
||||||
// TODO: @芋艿,需要根据后台API删除不需要的字段
|
// TODO: @芋艿,需要根据后台API删除不需要的字段
|
||||||
const menuToBackend = (menu: any) => {
|
function menuToBackend(menu: any) {
|
||||||
const result = {
|
const result = {
|
||||||
...menu,
|
...menu,
|
||||||
children: undefined, // 不处理子节点
|
children: undefined, // 不处理子节点
|
||||||
@@ -254,7 +256,7 @@ const menuToBackend = (menu: any) => {
|
|||||||
result.replyHqMusicUrl = menu.reply.hqMusicUrl;
|
result.replyHqMusicUrl = menu.reply.hqMusicUrl;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ import {
|
|||||||
ElSelect,
|
ElSelect,
|
||||||
} from 'element-plus';
|
} from 'element-plus';
|
||||||
|
|
||||||
import WxMaterialSelect from '#/views/mp/components/wx-material-select';
|
import WxMaterialSelect from '#/views/mp/modules/wx-material-select';
|
||||||
import WxNews from '#/views/mp/components/wx-news';
|
import WxNews from '#/views/mp/modules/wx-news';
|
||||||
import WxReplySelect from '#/views/mp/components/wx-reply';
|
import WxReplySelect from '#/views/mp/modules/wx-reply';
|
||||||
|
|
||||||
import menuOptions from '../components/menuOptions';
|
import menuOptions from './menuOptions';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
accountId: number;
|
accountId: number;
|
||||||
@@ -51,7 +51,8 @@ watch(menu, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ======================== 菜单编辑(素材选择) ========================
|
// ======================== 菜单编辑(素材选择) ========================
|
||||||
const selectMaterial = (item: any) => {
|
/** 选择素材 */
|
||||||
|
function selectMaterial(item: any) {
|
||||||
const articleId = item.articleId;
|
const articleId = item.articleId;
|
||||||
const articles = item.content.newsItem;
|
const articles = item.content.newsItem;
|
||||||
// 提示,针对多图文
|
// 提示,针对多图文
|
||||||
@@ -71,12 +72,13 @@ const selectMaterial = (item: any) => {
|
|||||||
url: article.url,
|
url: article.url,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
const deleteMaterial = () => {
|
/** 删除素材 */
|
||||||
|
function deleteMaterial() {
|
||||||
delete menu.value.articleId;
|
delete menu.value.articleId;
|
||||||
delete menu.value.replyArticles;
|
delete menu.value.replyArticles;
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { Menu } from '../components/types';
|
import type { Menu } from './types';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ const menuList = computed<Menu[]>({
|
|||||||
set: (val) => emit('update:modelValue', val),
|
set: (val) => emit('update:modelValue', val),
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加横向一级菜单
|
/** 添加横向一级菜单 */
|
||||||
const addMenu = () => {
|
function addMenu() {
|
||||||
const index = menuList.value.length;
|
const index = menuList.value.length;
|
||||||
const menu = {
|
const menu = {
|
||||||
name: '菜单名称',
|
name: '菜单名称',
|
||||||
@@ -39,10 +39,10 @@ const addMenu = () => {
|
|||||||
};
|
};
|
||||||
menuList.value[index] = menu;
|
menuList.value[index] = menu;
|
||||||
menuClicked(menu, index - 1);
|
menuClicked(menu, index - 1);
|
||||||
};
|
}
|
||||||
|
|
||||||
// 添加横向二级菜单;parent 表示要操作的父菜单
|
/** 添加横向二级菜单;parent 表示要操作的父菜单 */
|
||||||
const addSubMenu = (i: number, parent: any) => {
|
function addSubMenu(i: number, parent: any) {
|
||||||
const subMenuKeyLength = parent.children.length; // 获取二级菜单key长度
|
const subMenuKeyLength = parent.children.length; // 获取二级菜单key长度
|
||||||
const addButton = {
|
const addButton = {
|
||||||
name: '子菜单名称',
|
name: '子菜单名称',
|
||||||
@@ -54,15 +54,17 @@ const addSubMenu = (i: number, parent: any) => {
|
|||||||
};
|
};
|
||||||
parent.children[subMenuKeyLength] = addButton;
|
parent.children[subMenuKeyLength] = addButton;
|
||||||
subMenuClicked(parent.children[subMenuKeyLength], i, subMenuKeyLength);
|
subMenuClicked(parent.children[subMenuKeyLength], i, subMenuKeyLength);
|
||||||
};
|
}
|
||||||
|
|
||||||
const menuClicked = (parent: Menu, x: number) => {
|
/** 一级菜单点击 */
|
||||||
|
function menuClicked(parent: Menu, x: number) {
|
||||||
emit('menuClicked', parent, x);
|
emit('menuClicked', parent, x);
|
||||||
};
|
}
|
||||||
|
|
||||||
const subMenuClicked = (child: Menu, x: number, y: number) => {
|
/** 二级菜单点击 */
|
||||||
|
function subMenuClicked(child: Menu, x: number, y: number) {
|
||||||
emit('submenuClicked', child, x, y);
|
emit('submenuClicked', child, x, y);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理一级菜单展开后被拖动,激活(展开)原来活动的一级菜单
|
* 处理一级菜单展开后被拖动,激活(展开)原来活动的一级菜单
|
||||||
@@ -71,13 +73,13 @@ const subMenuClicked = (child: Menu, x: number, y: number) => {
|
|||||||
* @param options.oldIndex - 一级菜单拖动前的位置
|
* @param options.oldIndex - 一级菜单拖动前的位置
|
||||||
* @param options.newIndex - 一级菜单拖动后的位置
|
* @param options.newIndex - 一级菜单拖动后的位置
|
||||||
*/
|
*/
|
||||||
const onParentDragEnd = ({
|
function onParentDragEnd({
|
||||||
oldIndex,
|
oldIndex,
|
||||||
newIndex,
|
newIndex,
|
||||||
}: {
|
}: {
|
||||||
newIndex: number;
|
newIndex: number;
|
||||||
oldIndex: number;
|
oldIndex: number;
|
||||||
}) => {
|
}) {
|
||||||
// 二级菜单没有展开,直接返回
|
// 二级菜单没有展开,直接返回
|
||||||
if (props.activeIndex === '__MENU_NOT_SELECTED__') {
|
if (props.activeIndex === '__MENU_NOT_SELECTED__') {
|
||||||
return;
|
return;
|
||||||
@@ -95,7 +97,7 @@ const onParentDragEnd = ({
|
|||||||
if (parent && newParentIndex !== -1) {
|
if (parent && newParentIndex !== -1) {
|
||||||
emit('menuClicked', parent, newParentIndex);
|
emit('menuClicked', parent, newParentIndex);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理二级菜单展开后被拖动,激活被拖动的菜单
|
* 处理二级菜单展开后被拖动,激活被拖动的菜单
|
||||||
@@ -103,7 +105,7 @@ const onParentDragEnd = ({
|
|||||||
* @param options - 拖动参数对象
|
* @param options - 拖动参数对象
|
||||||
* @param options.newIndex - 二级菜单拖动后的位置
|
* @param options.newIndex - 二级菜单拖动后的位置
|
||||||
*/
|
*/
|
||||||
const onChildDragEnd = ({ newIndex }: { newIndex: number }) => {
|
function onChildDragEnd({ newIndex }: { newIndex: number }) {
|
||||||
const x = props.parentIndex;
|
const x = props.parentIndex;
|
||||||
const y = newIndex;
|
const y = newIndex;
|
||||||
const children = menuList.value[x]?.children;
|
const children = menuList.value[x]?.children;
|
||||||
@@ -113,7 +115,7 @@ const onChildDragEnd = ({ newIndex }: { newIndex: number }) => {
|
|||||||
emit('submenuClicked', child, x, y);
|
emit('submenuClicked', child, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ const account: MpAccountApi.AccountSimple = reactive({
|
|||||||
|
|
||||||
const accountList = ref<MpAccountApi.AccountSimple[]>([]);
|
const accountList = ref<MpAccountApi.AccountSimple[]>([]);
|
||||||
|
|
||||||
const handleQuery = async () => {
|
/** 查询公众号列表 */
|
||||||
|
async function handleQuery() {
|
||||||
accountList.value = await getSimpleAccountList();
|
accountList.value = await getSimpleAccountList();
|
||||||
if (accountList.value.length === 0) {
|
if (accountList.value.length === 0) {
|
||||||
message.error('未配置公众号,请在【公众号管理 -> 账号管理】菜单,进行配置');
|
message.error('未配置公众号,请在【公众号管理 -> 账号管理】菜单,进行配置');
|
||||||
@@ -43,9 +44,10 @@ const handleQuery = async () => {
|
|||||||
emit('change', account.id, account.name);
|
emit('change', account.id, account.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const onChanged = (id?: number) => {
|
/** 公众号变化 */
|
||||||
|
function onChanged(id?: number) {
|
||||||
const found = accountList.value.find(
|
const found = accountList.value.find(
|
||||||
(v: MpAccountApi.AccountSimple) => v.id === id,
|
(v: MpAccountApi.AccountSimple) => v.id === id,
|
||||||
);
|
);
|
||||||
@@ -53,7 +55,7 @@ const onChanged = (id?: number) => {
|
|||||||
account.name = found.name;
|
account.name = found.name;
|
||||||
emit('change', account.id, account.name);
|
emit('change', account.id, account.name);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/** 初始化 */
|
/** 初始化 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -12,9 +12,9 @@ import { formatTime } from '@vben/utils';
|
|||||||
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/modules/wx-news';
|
||||||
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
import WxVideoPlayer from '#/views/mp/modules/wx-video-play';
|
||||||
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
import WxVoicePlayer from '#/views/mp/modules/wx-voice-play';
|
||||||
|
|
||||||
import { NewsType } from './types';
|
import { NewsType } from './types';
|
||||||
|
|
||||||
@@ -46,11 +46,13 @@ const queryParams = reactive({
|
|||||||
accountId: props.accountId,
|
accountId: props.accountId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectMaterialFun = (item: any) => {
|
/** 选择素材 */
|
||||||
|
function selectMaterialFun(item: any) {
|
||||||
emit('selectMaterial', item);
|
emit('selectMaterial', item);
|
||||||
};
|
}
|
||||||
|
|
||||||
const getPage = async () => {
|
/** 获取分页数据 */
|
||||||
|
async function getPage() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
if (props.type === 'news' && props.newsType === NewsType.Published) {
|
if (props.type === 'news' && props.newsType === NewsType.Published) {
|
||||||
@@ -66,18 +68,20 @@ const getPage = async () => {
|
|||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const getMaterialPageFun = async () => {
|
/** 获取素材分页 */
|
||||||
|
async function getMaterialPageFun() {
|
||||||
const data = await MpMaterialApi.getMaterialPage({
|
const data = await MpMaterialApi.getMaterialPage({
|
||||||
...queryParams,
|
...queryParams,
|
||||||
type: props.type,
|
type: props.type,
|
||||||
});
|
});
|
||||||
list.value = data.list;
|
list.value = data.list;
|
||||||
total.value = data.total;
|
total.value = data.total;
|
||||||
};
|
}
|
||||||
|
|
||||||
const getFreePublishPageFun = async () => {
|
/** 获取已发布图文分页 */
|
||||||
|
async function getFreePublishPageFun() {
|
||||||
const data = await MpFreePublishApi.getFreePublishPage(queryParams);
|
const data = await MpFreePublishApi.getFreePublishPage(queryParams);
|
||||||
data.list.forEach((item: any) => {
|
data.list.forEach((item: any) => {
|
||||||
const articles = item.content.newsItem;
|
const articles = item.content.newsItem;
|
||||||
@@ -87,9 +91,10 @@ const getFreePublishPageFun = async () => {
|
|||||||
});
|
});
|
||||||
list.value = data.list;
|
list.value = data.list;
|
||||||
total.value = data.total;
|
total.value = data.total;
|
||||||
};
|
}
|
||||||
|
|
||||||
const getDraftPageFun = async () => {
|
/** 获取草稿图文分页 */
|
||||||
|
async function getDraftPageFun() {
|
||||||
const data = await MpDraftApi.getDraftPage(queryParams);
|
const data = await MpDraftApi.getDraftPage(queryParams);
|
||||||
data.list.forEach((draft: any) => {
|
data.list.forEach((draft: any) => {
|
||||||
const articles = draft.content.newsItem;
|
const articles = draft.content.newsItem;
|
||||||
@@ -99,7 +104,7 @@ const getDraftPageFun = async () => {
|
|||||||
});
|
});
|
||||||
list.value = data.list;
|
list.value = data.list;
|
||||||
total.value = data.total;
|
total.value = data.total;
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
getPage();
|
getPage();
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
import WxLocation from '#/views/mp/components/wx-location';
|
import WxLocation from '#/views/mp/modules/wx-location';
|
||||||
import WxMusic from '#/views/mp/components/wx-music';
|
import WxMusic from '#/views/mp/modules/wx-music';
|
||||||
import WxNews from '#/views/mp/components/wx-news';
|
import WxNews from '#/views/mp/modules/wx-news';
|
||||||
import WxVideoPlayer from '#/views/mp/components/wx-video-play';
|
import WxVideoPlayer from '#/views/mp/modules/wx-video-play';
|
||||||
import WxVoicePlayer from '#/views/mp/components/wx-voice-play';
|
import WxVoicePlayer from '#/views/mp/modules/wx-voice-play';
|
||||||
|
|
||||||
import { MsgType } from '../types';
|
import { MsgType } from '../types';
|
||||||
import MsgEvent from './MsgEvent.vue';
|
import MsgEvent from './MsgEvent.vue';
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { User } from './types';
|
import type { User } from './types';
|
||||||
|
|
||||||
import type { Reply } from '#/views/mp/components/wx-reply';
|
import type { Reply } from '#/views/mp/modules/wx-reply';
|
||||||
|
|
||||||
import { nextTick, onMounted, reactive, ref, unref } from 'vue';
|
import { nextTick, onMounted, reactive, ref, unref } from 'vue';
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ import { ElMessage } from 'element-plus';
|
|||||||
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 profile from '#/assets/imgs/profile.jpg';
|
import profile from '#/assets/imgs/profile.jpg';
|
||||||
import WxReplySelect, { ReplyType } from '#/views/mp/components/wx-reply';
|
import WxReplySelect, { ReplyType } from '#/views/mp/modules/wx-reply';
|
||||||
|
|
||||||
import MsgList from './components/MsgList.vue';
|
import MsgList from './components/MsgList.vue';
|
||||||
|
|
||||||
@@ -76,8 +76,8 @@ onMounted(async () => {
|
|||||||
refreshChange();
|
refreshChange();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 执行发送
|
/** 执行发送 */
|
||||||
const sendMsg = async () => {
|
async function sendMsg() {
|
||||||
if (!unref(reply)) {
|
if (!unref(reply)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -104,14 +104,16 @@ const sendMsg = async () => {
|
|||||||
|
|
||||||
// 发送后清空数据
|
// 发送后清空数据
|
||||||
replySelectRef.value?.clear();
|
replySelectRef.value?.clear();
|
||||||
};
|
}
|
||||||
|
|
||||||
const loadMore = () => {
|
/** 加载更多 */
|
||||||
|
function loadMore() {
|
||||||
queryParams.pageNo++;
|
queryParams.pageNo++;
|
||||||
getPage(queryParams, null);
|
getPage(queryParams, null);
|
||||||
};
|
}
|
||||||
|
|
||||||
const getPage = async (page: any, params: any = null) => {
|
/** 获取分页数据 */
|
||||||
|
async function getPage(page: any, params: any = null) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const dataTemp = await getMessagePage(
|
const dataTemp = await getMessagePage(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
@@ -147,19 +149,20 @@ const getPage = async (page: any, params: any = null) => {
|
|||||||
msgDivRef.value.scrollHeight - scrollHeight - 100;
|
msgDivRef.value.scrollHeight - scrollHeight - 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const refreshChange = () => {
|
/** 刷新消息 */
|
||||||
|
function refreshChange() {
|
||||||
getPage(queryParams);
|
getPage(queryParams);
|
||||||
};
|
}
|
||||||
|
|
||||||
/** 定位到消息底部 */
|
/** 定位到消息底部 */
|
||||||
const scrollToBottom = async () => {
|
async function scrollToBottom() {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
if (msgDivRef.value) {
|
if (msgDivRef.value) {
|
||||||
msgDivRef.value.scrollTop = msgDivRef.value.scrollHeight;
|
msgDivRef.value.scrollTop = msgDivRef.value.scrollHeight;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -5,15 +5,20 @@ import type { Reply } from './types';
|
|||||||
|
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
|
|
||||||
// import { getAccessToken } from '#/utils/auth';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { useAccessStore } from '@vben/stores';
|
import { useAccessStore } from '@vben/stores';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElCol,
|
||||||
|
ElDialog,
|
||||||
|
ElMessage,
|
||||||
|
ElRow,
|
||||||
|
ElUpload,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
// 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';
|
||||||
|
import WxMaterialSelect from '#/views/mp/modules/wx-material-select';
|
||||||
// 设置上传的请求头部
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: Reply;
|
modelValue: Reply;
|
||||||
@@ -41,10 +46,13 @@ const uploadData = reactive({
|
|||||||
introduction: '',
|
introduction: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const beforeImageUpload = (rawFile: UploadRawFile) =>
|
/** 图片上传前校验 */
|
||||||
useBeforeUpload(UploadType.Image, 2)(rawFile);
|
function beforeImageUpload(rawFile: UploadRawFile) {
|
||||||
|
return useBeforeUpload(UploadType.Image, 2)(rawFile);
|
||||||
|
}
|
||||||
|
|
||||||
const onUploadSuccess = (res: any) => {
|
/** 上传成功 */
|
||||||
|
function onUploadSuccess(res: any) {
|
||||||
if (res.code !== 0) {
|
if (res.code !== 0) {
|
||||||
message.error(`上传出错:${res.msg}`);
|
message.error(`上传出错:${res.msg}`);
|
||||||
return false;
|
return false;
|
||||||
@@ -57,22 +65,24 @@ const onUploadSuccess = (res: any) => {
|
|||||||
|
|
||||||
// 上传好的文件,本质是个素材,所以可以进行选中
|
// 上传好的文件,本质是个素材,所以可以进行选中
|
||||||
selectMaterial(res.data);
|
selectMaterial(res.data);
|
||||||
};
|
}
|
||||||
|
|
||||||
const onDelete = () => {
|
/** 删除图片 */
|
||||||
|
function onDelete() {
|
||||||
reply.value.mediaId = null;
|
reply.value.mediaId = null;
|
||||||
reply.value.url = null;
|
reply.value.url = null;
|
||||||
reply.value.name = null;
|
reply.value.name = null;
|
||||||
};
|
}
|
||||||
|
|
||||||
const selectMaterial = (item: any) => {
|
/** 选择素材 */
|
||||||
|
function selectMaterial(item: any) {
|
||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
|
|
||||||
// reply.value.type = 'image'
|
// reply.value.type = 'image'
|
||||||
reply.value.mediaId = item.mediaId;
|
reply.value.mediaId = item.mediaId;
|
||||||
reply.value.url = item.url;
|
reply.value.url = item.url;
|
||||||
reply.value.name = item.name;
|
reply.value.name = item.name;
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -81,20 +91,20 @@ const selectMaterial = (item: any) => {
|
|||||||
<div class="select-item" v-if="reply.url">
|
<div class="select-item" v-if="reply.url">
|
||||||
<img class="material-img" :src="reply.url" />
|
<img class="material-img" :src="reply.url" />
|
||||||
<p class="item-name" v-if="reply.name">{{ reply.name }}</p>
|
<p class="item-name" v-if="reply.name">{{ reply.name }}</p>
|
||||||
<el-row class="ope-row" justify="center">
|
<ElRow class="ope-row" justify="center">
|
||||||
<el-button type="danger" circle @click="onDelete">
|
<ElButton type="danger" circle @click="onDelete">
|
||||||
<Icon icon="ep:delete" />
|
<IconifyIcon icon="ep:delete" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</div>
|
</div>
|
||||||
<!-- 情况二:未做完上述操作 -->
|
<!-- 情况二:未做完上述操作 -->
|
||||||
<el-row v-else style="text-align: center" align="middle">
|
<ElRow v-else style="text-align: center" align="middle">
|
||||||
<!-- 选择素材 -->
|
<!-- 选择素材 -->
|
||||||
<el-col :span="12" class="col-select">
|
<ElCol :span="12" class="col-select">
|
||||||
<el-button type="success" @click="showDialog = true">
|
<ElButton type="success" @click="showDialog = true">
|
||||||
素材库选择 <Icon icon="ep:circle-check" />
|
素材库选择 <IconifyIcon icon="ep:circle-check" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
<el-dialog
|
<ElDialog
|
||||||
title="选择图片"
|
title="选择图片"
|
||||||
v-model="showDialog"
|
v-model="showDialog"
|
||||||
width="90%"
|
width="90%"
|
||||||
@@ -106,11 +116,11 @@ const selectMaterial = (item: any) => {
|
|||||||
:account-id="reply.accountId"
|
:account-id="reply.accountId"
|
||||||
@select-material="selectMaterial"
|
@select-material="selectMaterial"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</ElDialog>
|
||||||
</el-col>
|
</ElCol>
|
||||||
<!-- 文件上传 -->
|
<!-- 文件上传 -->
|
||||||
<el-col :span="12" class="col-add">
|
<ElCol :span="12" class="col-add">
|
||||||
<el-upload
|
<ElUpload
|
||||||
:action="UPLOAD_URL"
|
:action="UPLOAD_URL"
|
||||||
:headers="HEADERS"
|
:headers="HEADERS"
|
||||||
multiple
|
multiple
|
||||||
@@ -120,7 +130,7 @@ const selectMaterial = (item: any) => {
|
|||||||
:before-upload="beforeImageUpload"
|
:before-upload="beforeImageUpload"
|
||||||
:on-success="onUploadSuccess"
|
:on-success="onUploadSuccess"
|
||||||
>
|
>
|
||||||
<el-button type="primary">上传图片</el-button>
|
<ElButton type="primary">上传图片</ElButton>
|
||||||
<template #tip>
|
<template #tip>
|
||||||
<span>
|
<span>
|
||||||
<div class="el-upload__tip">
|
<div class="el-upload__tip">
|
||||||
@@ -128,9 +138,9 @@ const selectMaterial = (item: any) => {
|
|||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-upload>
|
</ElUpload>
|
||||||
</el-col>
|
</ElCol>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -5,13 +5,22 @@ import type { Reply } from './types';
|
|||||||
|
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { useAccessStore } from '@vben/stores';
|
import { useAccessStore } from '@vben/stores';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElCol,
|
||||||
|
ElDialog,
|
||||||
|
ElInput,
|
||||||
|
ElMessage,
|
||||||
|
ElRow,
|
||||||
|
ElUpload,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
// import { getAccessToken } from '@/utils/auth'
|
|
||||||
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';
|
||||||
|
// import { getAccessToken } from '@/utils/auth'
|
||||||
|
import WxMaterialSelect from '#/views/mp/modules/wx-material-select';
|
||||||
|
|
||||||
// 设置上传的请求头部
|
// 设置上传的请求头部
|
||||||
|
|
||||||
@@ -41,10 +50,13 @@ const uploadData = reactive({
|
|||||||
introduction: '',
|
introduction: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const beforeImageUpload = (rawFile: UploadRawFile) =>
|
/** 图片上传前校验 */
|
||||||
useBeforeUpload(UploadType.Image, 2)(rawFile);
|
function beforeImageUpload(rawFile: UploadRawFile) {
|
||||||
|
return useBeforeUpload(UploadType.Image, 2)(rawFile);
|
||||||
|
}
|
||||||
|
|
||||||
const onUploadSuccess = (res: any) => {
|
/** 上传成功 */
|
||||||
|
function onUploadSuccess(res: any) {
|
||||||
if (res.code !== 0) {
|
if (res.code !== 0) {
|
||||||
message.error(`上传出错:${res.msg}`);
|
message.error(`上传出错:${res.msg}`);
|
||||||
return false;
|
return false;
|
||||||
@@ -57,33 +69,34 @@ const onUploadSuccess = (res: any) => {
|
|||||||
|
|
||||||
// 上传好的文件,本质是个素材,所以可以进行选中
|
// 上传好的文件,本质是个素材,所以可以进行选中
|
||||||
selectMaterial(res.data);
|
selectMaterial(res.data);
|
||||||
};
|
}
|
||||||
|
|
||||||
const selectMaterial = (item: any) => {
|
/** 选择素材 */
|
||||||
|
function selectMaterial(item: any) {
|
||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
|
|
||||||
reply.value.thumbMediaId = item.mediaId;
|
reply.value.thumbMediaId = item.mediaId;
|
||||||
reply.value.thumbMediaUrl = item.url;
|
reply.value.thumbMediaUrl = item.url;
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-row align="middle" justify="center">
|
<ElRow align="middle" justify="center">
|
||||||
<el-col :span="6">
|
<ElCol :span="6">
|
||||||
<el-row align="middle" justify="center" class="thumb-div">
|
<ElRow align="middle" justify="center" class="thumb-div">
|
||||||
<el-col :span="24">
|
<ElCol :span="24">
|
||||||
<el-row align="middle" justify="center">
|
<ElRow align="middle" justify="center">
|
||||||
<img
|
<img
|
||||||
style="width: 100px"
|
style="width: 100px"
|
||||||
v-if="reply.thumbMediaUrl"
|
v-if="reply.thumbMediaUrl"
|
||||||
:src="reply.thumbMediaUrl"
|
:src="reply.thumbMediaUrl"
|
||||||
/>
|
/>
|
||||||
<icon v-else icon="ep:plus" />
|
<IconifyIcon v-else icon="ep:plus" />
|
||||||
</el-row>
|
</ElRow>
|
||||||
<el-row align="middle" justify="center" style="margin-top: 2%">
|
<ElRow align="middle" justify="center" style="margin-top: 2%">
|
||||||
<div class="thumb-but">
|
<div class="thumb-but">
|
||||||
<el-upload
|
<ElUpload
|
||||||
:action="UPLOAD_URL"
|
:action="UPLOAD_URL"
|
||||||
:headers="HEADERS"
|
:headers="HEADERS"
|
||||||
multiple
|
multiple
|
||||||
@@ -94,22 +107,22 @@ const selectMaterial = (item: any) => {
|
|||||||
:on-success="onUploadSuccess"
|
:on-success="onUploadSuccess"
|
||||||
>
|
>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<el-button type="primary" link>本地上传</el-button>
|
<ElButton type="primary" link>本地上传</ElButton>
|
||||||
</template>
|
</template>
|
||||||
<el-button
|
<ElButton
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@click="showDialog = true"
|
@click="showDialog = true"
|
||||||
style="margin-left: 5px"
|
style="margin-left: 5px"
|
||||||
>
|
>
|
||||||
素材库选择
|
素材库选择
|
||||||
</el-button>
|
</ElButton>
|
||||||
</el-upload>
|
</ElUpload>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</el-col>
|
</ElCol>
|
||||||
</el-row>
|
</ElRow>
|
||||||
<el-dialog
|
<ElDialog
|
||||||
title="选择图片"
|
title="选择图片"
|
||||||
v-model="showDialog"
|
v-model="showDialog"
|
||||||
width="80%"
|
width="80%"
|
||||||
@@ -121,17 +134,17 @@ const selectMaterial = (item: any) => {
|
|||||||
:account-id="reply.accountId"
|
:account-id="reply.accountId"
|
||||||
@select-material="selectMaterial"
|
@select-material="selectMaterial"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</ElDialog>
|
||||||
</el-col>
|
</ElCol>
|
||||||
<el-col :span="18">
|
<ElCol :span="18">
|
||||||
<el-input v-model="reply.title" placeholder="请输入标题" />
|
<ElInput v-model="reply.title" placeholder="请输入标题" />
|
||||||
<div style="margin: 20px 0"></div>
|
<div style="margin: 20px 0"></div>
|
||||||
<el-input v-model="reply.description" placeholder="请输入描述" />
|
<ElInput v-model="reply.description" placeholder="请输入描述" />
|
||||||
</el-col>
|
</ElCol>
|
||||||
</el-row>
|
</ElRow>
|
||||||
<div style="margin: 20px 0"></div>
|
<div style="margin: 20px 0"></div>
|
||||||
<el-input v-model="reply.musicUrl" placeholder="请输入音乐链接" />
|
<ElInput v-model="reply.musicUrl" placeholder="请输入音乐链接" />
|
||||||
<div style="margin: 20px 0"></div>
|
<div style="margin: 20px 0"></div>
|
||||||
<el-input v-model="reply.hqMusicUrl" placeholder="请输入高质量音乐链接" />
|
<ElInput v-model="reply.hqMusicUrl" placeholder="请输入高质量音乐链接" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { NewsType, Reply } from './types';
|
import type { Reply } from './types';
|
||||||
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
import WxMaterialSelect from '#/views/mp/components/wx-material-select';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import WxNews from '#/views/mp/components/wx-news';
|
|
||||||
|
import { ElButton, ElCol, ElDialog, ElRow } from 'element-plus';
|
||||||
|
|
||||||
|
import WxMaterialSelect from '#/views/mp/modules/wx-material-select';
|
||||||
|
import WxNews from '#/views/mp/modules/wx-news';
|
||||||
|
|
||||||
|
import { NewsType } from './types';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: Reply;
|
modelValue: Reply;
|
||||||
@@ -20,46 +26,48 @@ const reply = computed<Reply>({
|
|||||||
|
|
||||||
const showDialog = ref(false);
|
const showDialog = ref(false);
|
||||||
|
|
||||||
const selectMaterial = (item: any) => {
|
/** 选择素材 */
|
||||||
|
function selectMaterial(item: any) {
|
||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
reply.value.articles = item.content.newsItem;
|
reply.value.articles = item.content.newsItem;
|
||||||
};
|
}
|
||||||
|
|
||||||
const onDelete = () => {
|
/** 删除图文 */
|
||||||
|
function onDelete() {
|
||||||
reply.value.articles = [];
|
reply.value.articles = [];
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-row>
|
<ElRow>
|
||||||
<div
|
<div
|
||||||
class="select-item"
|
class="select-item"
|
||||||
v-if="reply.articles && reply.articles.length > 0"
|
v-if="reply.articles && reply.articles.length > 0"
|
||||||
>
|
>
|
||||||
<WxNews :articles="reply.articles" />
|
<WxNews :articles="reply.articles" />
|
||||||
<el-col class="ope-row">
|
<ElCol class="ope-row">
|
||||||
<el-button type="danger" circle @click="onDelete">
|
<ElButton type="danger" circle @click="onDelete">
|
||||||
<Icon icon="ep:delete" />
|
<IconifyIcon icon="ep:delete" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
</el-col>
|
</ElCol>
|
||||||
</div>
|
</div>
|
||||||
<!-- 选择素材 -->
|
<!-- 选择素材 -->
|
||||||
<el-col :span="24" v-if="!reply.content">
|
<ElCol :span="24" v-if="!reply.content">
|
||||||
<el-row style="text-align: center" align="middle">
|
<ElRow style="text-align: center" align="middle">
|
||||||
<el-col :span="24">
|
<ElCol :span="24">
|
||||||
<el-button type="success" @click="showDialog = true">
|
<ElButton type="success" @click="showDialog = true">
|
||||||
{{
|
{{
|
||||||
newsType === NewsType.Published
|
newsType === NewsType.Published
|
||||||
? '选择已发布图文'
|
? '选择已发布图文'
|
||||||
: '选择草稿箱图文'
|
: '选择草稿箱图文'
|
||||||
}}
|
}}
|
||||||
<Icon icon="ep:circle-check" />
|
<IconifyIcon icon="ep:circle-check" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
</el-col>
|
</ElCol>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</el-col>
|
</ElCol>
|
||||||
<el-dialog
|
<ElDialog
|
||||||
title="选择图文"
|
title="选择图文"
|
||||||
v-model="showDialog"
|
v-model="showDialog"
|
||||||
width="90%"
|
width="90%"
|
||||||
@@ -72,8 +80,8 @@ const onDelete = () => {
|
|||||||
:news-type="newsType"
|
:news-type="newsType"
|
||||||
@select-material="selectMaterial"
|
@select-material="selectMaterial"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</ElDialog>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { ElInput } from 'element-plus';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue?: null | string;
|
modelValue?: null | string;
|
||||||
}>();
|
}>();
|
||||||
@@ -20,7 +22,7 @@ const content = computed({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-input
|
<ElInput
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="5"
|
:rows="5"
|
||||||
placeholder="请输入内容"
|
placeholder="请输入内容"
|
||||||
@@ -5,13 +5,22 @@ import type { Reply } from './types';
|
|||||||
|
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { useAccessStore } from '@vben/stores';
|
import { useAccessStore } from '@vben/stores';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElCol,
|
||||||
|
ElDialog,
|
||||||
|
ElInput,
|
||||||
|
ElMessage,
|
||||||
|
ElRow,
|
||||||
|
ElUpload,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
import WxMaterialSelect from '#/views/mp/components/wx-material-select';
|
|
||||||
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';
|
||||||
|
import WxMaterialSelect from '#/views/mp/modules/wx-material-select';
|
||||||
|
import WxVideoPlayer from '#/views/mp/modules/wx-video-play';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: Reply;
|
modelValue: Reply;
|
||||||
@@ -40,10 +49,13 @@ const uploadData = reactive({
|
|||||||
introduction: '',
|
introduction: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const beforeVideoUpload = (rawFile: UploadRawFile) =>
|
/** 视频上传前校验 */
|
||||||
useBeforeUpload(UploadType.Video, 10)(rawFile);
|
function beforeVideoUpload(rawFile: UploadRawFile) {
|
||||||
|
return useBeforeUpload(UploadType.Video, 10)(rawFile);
|
||||||
|
}
|
||||||
|
|
||||||
const onUploadSuccess = (res: any) => {
|
/** 上传成功 */
|
||||||
|
function onUploadSuccess(res: any) {
|
||||||
if (res.code !== 0) {
|
if (res.code !== 0) {
|
||||||
message.error(`上传出错:${res.msg}`);
|
message.error(`上传出错:${res.msg}`);
|
||||||
return false;
|
return false;
|
||||||
@@ -55,10 +67,10 @@ const onUploadSuccess = (res: any) => {
|
|||||||
uploadData.introduction = '';
|
uploadData.introduction = '';
|
||||||
|
|
||||||
selectMaterial(res.data);
|
selectMaterial(res.data);
|
||||||
};
|
}
|
||||||
|
|
||||||
/** 选择素材后设置 */
|
/** 选择素材后设置 */
|
||||||
const selectMaterial = (item: any) => {
|
function selectMaterial(item: any) {
|
||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
|
|
||||||
reply.value.mediaId = item.mediaId;
|
reply.value.mediaId = item.mediaId;
|
||||||
@@ -72,33 +84,33 @@ const selectMaterial = (item: any) => {
|
|||||||
if (item.introduction) {
|
if (item.introduction) {
|
||||||
reply.value.description = item.introduction || '';
|
reply.value.description = item.introduction || '';
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-row>
|
<ElRow>
|
||||||
<el-input
|
<ElInput
|
||||||
v-model="reply.title"
|
v-model="reply.title"
|
||||||
class="input-margin-bottom"
|
class="input-margin-bottom"
|
||||||
placeholder="请输入标题"
|
placeholder="请输入标题"
|
||||||
/>
|
/>
|
||||||
<el-input
|
<ElInput
|
||||||
class="input-margin-bottom"
|
class="input-margin-bottom"
|
||||||
v-model="reply.description"
|
v-model="reply.description"
|
||||||
placeholder="请输入描述"
|
placeholder="请输入描述"
|
||||||
/>
|
/>
|
||||||
<el-row class="ope-row" justify="center">
|
<ElRow class="ope-row" justify="center">
|
||||||
<WxVideoPlayer v-if="reply.url" :url="reply.url" />
|
<WxVideoPlayer v-if="reply.url" :url="reply.url" />
|
||||||
</el-row>
|
</ElRow>
|
||||||
<el-col>
|
<ElCol>
|
||||||
<el-row style="text-align: center" align="middle">
|
<ElRow style="text-align: center" align="middle">
|
||||||
<!-- 选择素材 -->
|
<!-- 选择素材 -->
|
||||||
<el-col :span="12">
|
<ElCol :span="12">
|
||||||
<el-button type="success" @click="showDialog = true">
|
<ElButton type="success" @click="showDialog = true">
|
||||||
素材库选择 <Icon icon="ep:circle-check" />
|
素材库选择 <IconifyIcon icon="ep:circle-check" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
<el-dialog
|
<ElDialog
|
||||||
title="选择视频"
|
title="选择视频"
|
||||||
v-model="showDialog"
|
v-model="showDialog"
|
||||||
width="90%"
|
width="90%"
|
||||||
@@ -110,11 +122,11 @@ const selectMaterial = (item: any) => {
|
|||||||
:account-id="reply.accountId"
|
:account-id="reply.accountId"
|
||||||
@select-material="selectMaterial"
|
@select-material="selectMaterial"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</ElDialog>
|
||||||
</el-col>
|
</ElCol>
|
||||||
<!-- 文件上传 -->
|
<!-- 文件上传 -->
|
||||||
<el-col :span="12">
|
<ElCol :span="12">
|
||||||
<el-upload
|
<ElUpload
|
||||||
:action="UPLOAD_URL"
|
:action="UPLOAD_URL"
|
||||||
:headers="HEADERS"
|
:headers="HEADERS"
|
||||||
multiple
|
multiple
|
||||||
@@ -124,14 +136,14 @@ const selectMaterial = (item: any) => {
|
|||||||
:before-upload="beforeVideoUpload"
|
:before-upload="beforeVideoUpload"
|
||||||
:on-success="onUploadSuccess"
|
:on-success="onUploadSuccess"
|
||||||
>
|
>
|
||||||
<el-button type="primary">
|
<ElButton type="primary">
|
||||||
新建视频 <Icon icon="ep:upload" />
|
新建视频 <IconifyIcon icon="ep:upload" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
</el-upload>
|
</ElUpload>
|
||||||
</el-col>
|
</ElCol>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</el-col>
|
</ElCol>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -5,13 +5,21 @@ import type { Reply } from './types';
|
|||||||
|
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { useAccessStore } from '@vben/stores';
|
import { useAccessStore } from '@vben/stores';
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus';
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElCol,
|
||||||
|
ElDialog,
|
||||||
|
ElMessage,
|
||||||
|
ElRow,
|
||||||
|
ElUpload,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
import WxMaterialSelect from '#/views/mp/components/wx-material-select';
|
|
||||||
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';
|
||||||
|
import WxMaterialSelect from '#/views/mp/modules/wx-material-select';
|
||||||
|
import WxVoicePlayer from '#/views/mp/modules/wx-voice-play';
|
||||||
|
|
||||||
// 设置上传的请求头部
|
// 设置上传的请求头部
|
||||||
|
|
||||||
@@ -41,10 +49,13 @@ const uploadData = reactive({
|
|||||||
introduction: '',
|
introduction: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const beforeVoiceUpload = (rawFile: UploadRawFile) =>
|
/** 语音上传前校验 */
|
||||||
useBeforeUpload(UploadType.Voice, 10)(rawFile);
|
function beforeVoiceUpload(rawFile: UploadRawFile) {
|
||||||
|
return useBeforeUpload(UploadType.Voice, 10)(rawFile);
|
||||||
|
}
|
||||||
|
|
||||||
const onUploadSuccess = (res: any) => {
|
/** 上传成功 */
|
||||||
|
function onUploadSuccess(res: any) {
|
||||||
if (res.code !== 0) {
|
if (res.code !== 0) {
|
||||||
message.error(`上传出错:${res.msg}`);
|
message.error(`上传出错:${res.msg}`);
|
||||||
return false;
|
return false;
|
||||||
@@ -57,43 +68,45 @@ const onUploadSuccess = (res: any) => {
|
|||||||
|
|
||||||
// 上传好的文件,本质是个素材,所以可以进行选中
|
// 上传好的文件,本质是个素材,所以可以进行选中
|
||||||
selectMaterial(res.data);
|
selectMaterial(res.data);
|
||||||
};
|
}
|
||||||
|
|
||||||
const onDelete = () => {
|
/** 删除语音 */
|
||||||
|
function onDelete() {
|
||||||
reply.value.mediaId = null;
|
reply.value.mediaId = null;
|
||||||
reply.value.url = null;
|
reply.value.url = null;
|
||||||
reply.value.name = null;
|
reply.value.name = null;
|
||||||
};
|
}
|
||||||
|
|
||||||
const selectMaterial = (item: Reply) => {
|
/** 选择素材 */
|
||||||
|
function selectMaterial(item: Reply) {
|
||||||
showDialog.value = false;
|
showDialog.value = false;
|
||||||
|
|
||||||
// reply.value.type = ReplyType.Voice
|
// reply.value.type = ReplyType.Voice
|
||||||
reply.value.mediaId = item.mediaId;
|
reply.value.mediaId = item.mediaId;
|
||||||
reply.value.url = item.url;
|
reply.value.url = item.url;
|
||||||
reply.value.name = item.name;
|
reply.value.name = item.name;
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="select-item2" v-if="reply.url">
|
<div class="select-item2" v-if="reply.url">
|
||||||
<p class="item-name">{{ reply.name }}</p>
|
<p class="item-name">{{ reply.name }}</p>
|
||||||
<el-row class="ope-row" justify="center">
|
<ElRow class="ope-row" justify="center">
|
||||||
<WxVoicePlayer :url="reply.url" />
|
<WxVoicePlayer :url="reply.url" />
|
||||||
</el-row>
|
</ElRow>
|
||||||
<el-row class="ope-row" justify="center">
|
<ElRow class="ope-row" justify="center">
|
||||||
<el-button type="danger" circle @click="onDelete">
|
<ElButton type="danger" circle @click="onDelete">
|
||||||
<Icon icon="ep:delete" />
|
<IconifyIcon icon="ep:delete" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</div>
|
</div>
|
||||||
<el-row v-else style="text-align: center">
|
<ElRow v-else style="text-align: center">
|
||||||
<!-- 选择素材 -->
|
<!-- 选择素材 -->
|
||||||
<el-col :span="12" class="col-select">
|
<ElCol :span="12" class="col-select">
|
||||||
<el-button type="success" @click="showDialog = true">
|
<ElButton type="success" @click="showDialog = true">
|
||||||
素材库选择<Icon icon="ep:circle-check" />
|
素材库选择<IconifyIcon icon="ep:circle-check" />
|
||||||
</el-button>
|
</ElButton>
|
||||||
<el-dialog
|
<ElDialog
|
||||||
title="选择语音"
|
title="选择语音"
|
||||||
v-model="showDialog"
|
v-model="showDialog"
|
||||||
width="90%"
|
width="90%"
|
||||||
@@ -105,11 +118,11 @@ const selectMaterial = (item: Reply) => {
|
|||||||
:account-id="reply.accountId"
|
:account-id="reply.accountId"
|
||||||
@select-material="selectMaterial"
|
@select-material="selectMaterial"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</ElDialog>
|
||||||
</el-col>
|
</ElCol>
|
||||||
<!-- 文件上传 -->
|
<!-- 文件上传 -->
|
||||||
<el-col :span="12" class="col-add">
|
<ElCol :span="12" class="col-add">
|
||||||
<el-upload
|
<ElUpload
|
||||||
:action="UPLOAD_URL"
|
:action="UPLOAD_URL"
|
||||||
:headers="HEADERS"
|
:headers="HEADERS"
|
||||||
multiple
|
multiple
|
||||||
@@ -119,15 +132,15 @@ const selectMaterial = (item: Reply) => {
|
|||||||
:before-upload="beforeVoiceUpload"
|
:before-upload="beforeVoiceUpload"
|
||||||
:on-success="onUploadSuccess"
|
:on-success="onUploadSuccess"
|
||||||
>
|
>
|
||||||
<el-button type="primary">点击上传</el-button>
|
<ElButton type="primary">点击上传</ElButton>
|
||||||
<template #tip>
|
<template #tip>
|
||||||
<div class="el-upload__tip">
|
<div class="el-upload__tip">
|
||||||
格式支持 mp3/wma/wav/amr,文件大小不超过 2M,播放长度不超过 60s
|
格式支持 mp3/wma/wav/amr,文件大小不超过 2M,播放长度不超过 60s
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-upload>
|
</ElUpload>
|
||||||
</el-col>
|
</ElCol>
|
||||||
</el-row>
|
</ElRow>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -12,6 +12,10 @@ import type { Reply } from './components/types';
|
|||||||
|
|
||||||
import { computed, ref, unref, watch } from 'vue';
|
import { computed, ref, unref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
|
import { ElRow, ElTabPane, ElTabs } from 'element-plus';
|
||||||
|
|
||||||
import TabImage from './components/TabImage.vue';
|
import TabImage from './components/TabImage.vue';
|
||||||
import TabMusic from './components/TabMusic.vue';
|
import TabMusic from './components/TabMusic.vue';
|
||||||
import TabNews from './components/TabNews.vue';
|
import TabNews from './components/TabNews.vue';
|
||||||
@@ -70,9 +74,9 @@ watch(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/** 清除除了`type`, `accountId`的字段 */
|
/** 清除除了`type`, `accountId`的字段 */
|
||||||
const clear = () => {
|
function clear() {
|
||||||
reply.value = createEmptyReply(reply);
|
reply.value = createEmptyReply(reply);
|
||||||
};
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
clear,
|
clear,
|
||||||
@@ -80,57 +84,57 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-tabs type="border-card" v-model="currentTab">
|
<ElTabs type="border-card" v-model="currentTab">
|
||||||
<!-- 类型 1:文本 -->
|
<!-- 类型 1:文本 -->
|
||||||
<el-tab-pane :name="ReplyType.Text">
|
<ElTabPane :name="ReplyType.Text">
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-row align="middle"><Icon icon="ep:document" /> 文本</el-row>
|
<ElRow align="middle"><IconifyIcon icon="ep:document" /> 文本</ElRow>
|
||||||
</template>
|
</template>
|
||||||
<TabText v-model="reply.content" />
|
<TabText v-model="reply.content" />
|
||||||
</el-tab-pane>
|
</ElTabPane>
|
||||||
|
|
||||||
<!-- 类型 2:图片 -->
|
<!-- 类型 2:图片 -->
|
||||||
<el-tab-pane :name="ReplyType.Image">
|
<ElTabPane :name="ReplyType.Image">
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-row align="middle">
|
<ElRow align="middle">
|
||||||
<Icon icon="ep:picture" class="mr-5px" /> 图片
|
<IconifyIcon icon="ep:picture" class="mr-5px" /> 图片
|
||||||
</el-row>
|
</ElRow>
|
||||||
</template>
|
</template>
|
||||||
<TabImage v-model="reply" />
|
<TabImage v-model="reply" />
|
||||||
</el-tab-pane>
|
</ElTabPane>
|
||||||
|
|
||||||
<!-- 类型 3:语音 -->
|
<!-- 类型 3:语音 -->
|
||||||
<el-tab-pane :name="ReplyType.Voice">
|
<ElTabPane :name="ReplyType.Voice">
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-row align="middle"><Icon icon="ep:phone" /> 语音</el-row>
|
<ElRow align="middle"><IconifyIcon icon="ep:phone" /> 语音</ElRow>
|
||||||
</template>
|
</template>
|
||||||
<TabVoice v-model="reply" />
|
<TabVoice v-model="reply" />
|
||||||
</el-tab-pane>
|
</ElTabPane>
|
||||||
|
|
||||||
<!-- 类型 4:视频 -->
|
<!-- 类型 4:视频 -->
|
||||||
<el-tab-pane :name="ReplyType.Video">
|
<ElTabPane :name="ReplyType.Video">
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-row align="middle"><Icon icon="ep:share" /> 视频</el-row>
|
<ElRow align="middle"><IconifyIcon icon="ep:share" /> 视频</ElRow>
|
||||||
</template>
|
</template>
|
||||||
<TabVideo v-model="reply" />
|
<TabVideo v-model="reply" />
|
||||||
</el-tab-pane>
|
</ElTabPane>
|
||||||
|
|
||||||
<!-- 类型 5:图文 -->
|
<!-- 类型 5:图文 -->
|
||||||
<el-tab-pane :name="ReplyType.News">
|
<ElTabPane :name="ReplyType.News">
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-row align="middle"><Icon icon="ep:reading" /> 图文</el-row>
|
<ElRow align="middle"><IconifyIcon icon="ep:reading" /> 图文</ElRow>
|
||||||
</template>
|
</template>
|
||||||
<TabNews v-model="reply" :news-type="newsType" />
|
<TabNews v-model="reply" :news-type="newsType" />
|
||||||
</el-tab-pane>
|
</ElTabPane>
|
||||||
|
|
||||||
<!-- 类型 6:音乐 -->
|
<!-- 类型 6:音乐 -->
|
||||||
<el-tab-pane :name="ReplyType.Music">
|
<ElTabPane :name="ReplyType.Music">
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-row align="middle"><Icon icon="ep:service" />音乐</el-row>
|
<ElRow align="middle"><IconifyIcon icon="ep:service" />音乐</ElRow>
|
||||||
</template>
|
</template>
|
||||||
<TabMusic v-model="reply" />
|
<TabMusic v-model="reply" />
|
||||||
</el-tab-pane>
|
</ElTabPane>
|
||||||
</el-tabs>
|
</ElTabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
Reference in New Issue
Block a user