mirror of
https://gitee.com/hhyykk/ipms-sjy-ui.git
synced 2025-07-23 15:25:07 +08:00
refactor: mp模块,一个大大的重构+fix
This commit is contained in:
3
src/views/mp/components/wx-account-select/index.ts
Normal file
3
src/views/mp/components/wx-account-select/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import WxAccountSelect from './main.vue'
|
||||
|
||||
export default WxAccountSelect
|
@ -14,7 +14,7 @@ const account: MpAccountApi.AccountVO = reactive({
|
||||
const accountList: Ref<MpAccountApi.AccountVO[]> = ref([])
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change', id?: number, name?: string): void
|
||||
(e: 'change', id: number, name: string): void
|
||||
}>()
|
||||
|
||||
const handleQuery = async () => {
|
||||
@ -22,15 +22,19 @@ const handleQuery = async () => {
|
||||
// 默认选中第一个
|
||||
if (accountList.value.length > 0) {
|
||||
account.id = accountList.value[0].id
|
||||
account.name = accountList.value[0].name
|
||||
emit('change', account.id, account.name)
|
||||
if (account.id) {
|
||||
account.name = accountList.value[0].name
|
||||
emit('change', account.id, account.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onChanged = (id?: number) => {
|
||||
const found = accountList.value.find((v) => v.id === id)
|
||||
account.name = found ? found.name : ''
|
||||
emit('change', account.id, account.name)
|
||||
if (account.id) {
|
||||
account.name = found ? found.name : ''
|
||||
emit('change', account.id, account.name)
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 */
|
||||
|
3
src/views/mp/components/wx-location/index.ts
Normal file
3
src/views/mp/components/wx-location/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import WxLocation from './main.vue'
|
||||
|
||||
export default WxLocation
|
6
src/views/mp/components/wx-material-select/index.ts
Normal file
6
src/views/mp/components/wx-material-select/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import WxMaterialSelect from './main.vue'
|
||||
import { NewsType, MaterialType } from './types'
|
||||
|
||||
export { NewsType, MaterialType }
|
||||
|
||||
export default WxMaterialSelect
|
@ -7,7 +7,7 @@
|
||||
<template>
|
||||
<div class="pb-30px">
|
||||
<!-- 类型:image -->
|
||||
<div v-if="objData.type === 'image'">
|
||||
<div v-if="props.type === 'image'">
|
||||
<div class="waterfall" v-loading="loading">
|
||||
<div class="waterfall-item" v-for="item in list" :key="item.mediaId">
|
||||
<img class="material-img" :src="item.url" />
|
||||
@ -29,7 +29,7 @@
|
||||
/>
|
||||
</div>
|
||||
<!-- 类型:voice -->
|
||||
<div v-else-if="objData.type === 'voice'">
|
||||
<div v-else-if="props.type === 'voice'">
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="mediaId" />
|
||||
@ -64,7 +64,7 @@
|
||||
/>
|
||||
</div>
|
||||
<!-- 类型:video -->
|
||||
<div v-else-if="objData.type === 'video'">
|
||||
<div v-else-if="props.type === 'video'">
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="mediaId" />
|
||||
@ -106,7 +106,7 @@
|
||||
/>
|
||||
</div>
|
||||
<!-- 类型:news -->
|
||||
<div v-else-if="objData.type === 'news'">
|
||||
<div v-else-if="props.type === 'news'">
|
||||
<div class="waterfall" v-loading="loading">
|
||||
<div class="waterfall-item" v-for="item in list" :key="item.mediaId">
|
||||
<div v-if="item.content && item.content.newsItem">
|
||||
@ -132,25 +132,25 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="WxMaterialSelect">
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue'
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue'
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue'
|
||||
import WxNews from '@/views/mp/components/wx-news'
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play'
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play'
|
||||
import { NewsType } from './types'
|
||||
import * as MpMaterialApi from '@/api/mp/material'
|
||||
import * as MpFreePublishApi from '@/api/mp/freePublish'
|
||||
import * as MpDraftApi from '@/api/mp/draft'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
|
||||
const props = defineProps({
|
||||
objData: {
|
||||
type: Object, // type - 类型;accountId - 公众号账号编号
|
||||
required: true
|
||||
},
|
||||
newsType: {
|
||||
// 图文类型:1、已发布图文;2、草稿箱图文
|
||||
type: String as PropType<string>,
|
||||
default: '1'
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
type: string
|
||||
accountId: number
|
||||
newsType?: NewsType
|
||||
}>(),
|
||||
{
|
||||
newsType: NewsType.Published
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const emit = defineEmits(['select-material'])
|
||||
|
||||
@ -159,15 +159,13 @@ const loading = ref(false)
|
||||
// 总条数
|
||||
const total = ref(0)
|
||||
// 数据列表
|
||||
const list = ref([])
|
||||
const list = ref<any[]>([])
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
accountId: props.objData.accountId
|
||||
accountId: props.accountId
|
||||
})
|
||||
const objDataRef = reactive(props.objData)
|
||||
const newsTypeRef = ref(props.newsType)
|
||||
|
||||
const selectMaterialFun = (item) => {
|
||||
emit('select-material', item)
|
||||
@ -176,10 +174,10 @@ const selectMaterialFun = (item) => {
|
||||
const getPage = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
if (objDataRef.type === 'news' && newsTypeRef.value === '1') {
|
||||
if (props.type === 'news' && props.newsType === NewsType.Published) {
|
||||
// 【图文】+ 【已发布】
|
||||
await getFreePublishPageFun()
|
||||
} else if (objDataRef.type === 'news' && newsTypeRef.value === '2') {
|
||||
} else if (props.type === 'news' && props.newsType === NewsType.Draft) {
|
||||
// 【图文】+ 【草稿】
|
||||
await getDraftPageFun()
|
||||
} else {
|
||||
@ -194,7 +192,7 @@ const getPage = async () => {
|
||||
const getMaterialPageFun = async () => {
|
||||
const data = await MpMaterialApi.getMaterialPage({
|
||||
...queryParams,
|
||||
type: objDataRef.type
|
||||
type: props.type
|
||||
})
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
@ -202,9 +200,9 @@ const getMaterialPageFun = async () => {
|
||||
|
||||
const getFreePublishPageFun = async () => {
|
||||
const data = await MpFreePublishApi.getFreePublishPage(queryParams)
|
||||
data.list.forEach((item) => {
|
||||
const newsItem = item.content.newsItem
|
||||
newsItem.forEach((article) => {
|
||||
data.list.forEach((item: any) => {
|
||||
const articles = item.content.newsItem
|
||||
articles.forEach((article: any) => {
|
||||
article.picUrl = article.thumbUrl
|
||||
})
|
||||
})
|
||||
@ -214,9 +212,9 @@ const getFreePublishPageFun = async () => {
|
||||
|
||||
const getDraftPageFun = async () => {
|
||||
const data = await MpDraftApi.getDraftPage(queryParams)
|
||||
data.list.forEach((item) => {
|
||||
const newsItem = item.content.newsItem
|
||||
newsItem.forEach((article) => {
|
||||
data.list.forEach((draft: any) => {
|
||||
const articles = draft.content.newsItem
|
||||
articles.forEach((article: any) => {
|
||||
article.picUrl = article.thumbUrl
|
||||
})
|
||||
})
|
||||
|
11
src/views/mp/components/wx-material-select/types.ts
Normal file
11
src/views/mp/components/wx-material-select/types.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export enum NewsType {
|
||||
Draft = '2',
|
||||
Published = '1'
|
||||
}
|
||||
|
||||
export enum MaterialType {
|
||||
Image = 'image',
|
||||
Voice = 'voice',
|
||||
Video = 'video',
|
||||
News = 'news'
|
||||
}
|
6
src/views/mp/components/wx-msg/index.ts
Normal file
6
src/views/mp/components/wx-msg/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import WxMsg from './main.vue'
|
||||
import { MsgType } from './types'
|
||||
|
||||
export { MsgType }
|
||||
|
||||
export default WxMsg
|
@ -125,19 +125,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-send" v-loading="sendLoading">
|
||||
<WxReplySelect ref="replySelectRef" :objData="objData" />
|
||||
<WxReplySelect ref="replySelectRef" v-model="reply" />
|
||||
<el-button type="success" class="send-but" @click="sendMsg">发送(S)</el-button>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="WxMsg">
|
||||
import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue'
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue'
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue'
|
||||
import WxLocation from '@/views/mp/components/wx-location/main.vue'
|
||||
import WxMusic from '@/views/mp/components/wx-music/main.vue'
|
||||
import WxReplySelect from '@/views/mp/components/wx-reply'
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play'
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play'
|
||||
import WxNews from '@/views/mp/components/wx-news'
|
||||
import WxLocation from '@/views/mp/components/wx-location'
|
||||
import WxMusic from '@/views/mp/components/wx-music'
|
||||
import { getMessagePage, sendMessage } from '@/api/mp/message'
|
||||
import { getUser } from '@/api/mp/user'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
@ -187,14 +187,14 @@ const mp: Mp = reactive({
|
||||
|
||||
// ========= 消息发送 =========
|
||||
const sendLoading = ref(false) // 发送消息是否加载中
|
||||
interface ObjData {
|
||||
interface Reply {
|
||||
type: MsgType
|
||||
accountId: number | null
|
||||
articles: any[]
|
||||
}
|
||||
|
||||
// 微信发送消息
|
||||
const objData: ObjData = reactive({
|
||||
const reply = ref<Reply>({
|
||||
type: MsgType.Text,
|
||||
accountId: null,
|
||||
articles: []
|
||||
@ -209,23 +209,23 @@ onMounted(async () => {
|
||||
user.avatar = user.avatar?.length > 0 ? data.avatar : user.avatar
|
||||
user.accountId = data.accountId
|
||||
queryParams.accountId = data.accountId
|
||||
objData.accountId = data.accountId
|
||||
reply.value.accountId = data.accountId
|
||||
|
||||
refreshChange()
|
||||
})
|
||||
|
||||
// 执行发送
|
||||
const sendMsg = async () => {
|
||||
if (!objData) {
|
||||
if (!reply) {
|
||||
return
|
||||
}
|
||||
// 公众号限制:客服消息,公众号只允许发送一条
|
||||
if (objData.type === MsgType.News && objData.articles.length > 1) {
|
||||
objData.articles = [objData.articles[0]]
|
||||
if (reply.value.type === MsgType.News && reply.value.articles.length > 1) {
|
||||
reply.value.articles = [reply.value.articles[0]]
|
||||
message.success('图文消息条数限制在 1 条以内,已默认发送第一条')
|
||||
}
|
||||
|
||||
const data = await sendMessage(Object.assign({ userId: props.userId }, { ...objData }))
|
||||
const data = await sendMessage({ userId: props.userId, ...reply.value })
|
||||
sendLoading.value = false
|
||||
|
||||
list.value = [...list.value, ...[data]]
|
||||
|
3
src/views/mp/components/wx-music/index.ts
Normal file
3
src/views/mp/components/wx-music/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import WxMusic from './main.vue'
|
||||
|
||||
export default WxMusic
|
3
src/views/mp/components/wx-news/index.ts
Normal file
3
src/views/mp/components/wx-news/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import WxNews from './main.vue'
|
||||
|
||||
export default WxNews
|
@ -39,12 +39,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="WxNews" setup>
|
||||
const props = defineProps({
|
||||
articles: {
|
||||
type: Array,
|
||||
default: () => null
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
articles: any[] | null
|
||||
}>(),
|
||||
{
|
||||
articles: null
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
defineExpose({
|
||||
articles: props.articles
|
||||
@ -53,9 +55,9 @@ defineExpose({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.news-home {
|
||||
background-color: #ffffff;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.news-main {
|
||||
@ -64,29 +66,29 @@ defineExpose({
|
||||
}
|
||||
|
||||
.news-content {
|
||||
background-color: #acadae;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background-color: #acadae;
|
||||
}
|
||||
|
||||
.news-content-title {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-color: black;
|
||||
left: 0;
|
||||
display: inline-block;
|
||||
width: 98%;
|
||||
padding: 1%;
|
||||
opacity: 0.65;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
white-space: normal;
|
||||
background-color: black;
|
||||
opacity: 0.65;
|
||||
box-sizing: unset !important;
|
||||
}
|
||||
|
||||
.news-main-item {
|
||||
background-color: #ffffff;
|
||||
padding: 5px 0;
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #eaeaea;
|
||||
}
|
||||
|
||||
@ -96,17 +98,17 @@ defineExpose({
|
||||
|
||||
.news-content-item-title {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
width: 70%;
|
||||
margin-left: 1%;
|
||||
font-size: 10px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.news-content-item-img {
|
||||
display: inline-block;
|
||||
width: 25%;
|
||||
background-color: #acadae;
|
||||
margin-right: 1%;
|
||||
background-color: #acadae;
|
||||
}
|
||||
|
||||
.material-img {
|
||||
|
@ -1,12 +1,9 @@
|
||||
<template>
|
||||
<el-tab-pane name="image">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:picture" class="mr-5px" /> 图片</el-row>
|
||||
</template>
|
||||
<div>
|
||||
<!-- 情况一:已经选择好素材、或者上传好图片 -->
|
||||
<div class="select-item" v-if="objData.url">
|
||||
<img class="material-img" :src="objData.url" />
|
||||
<p class="item-name" v-if="objData.name">{{ objData.name }}</p>
|
||||
<div class="select-item" v-if="reply.url">
|
||||
<img class="material-img" :src="reply.url" />
|
||||
<p class="item-name" v-if="reply.name">{{ reply.name }}</p>
|
||||
<el-row class="ope-row" justify="center">
|
||||
<el-button type="danger" circle @click="onDelete">
|
||||
<Icon icon="ep:delete" />
|
||||
@ -27,7 +24,11 @@
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<WxMaterialSelect :objData="objData" @select-material="selectMaterial" />
|
||||
<WxMaterialSelect
|
||||
type="image"
|
||||
:account-id="reply.accountId"
|
||||
@select-material="selectMaterial"
|
||||
/>
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<!-- 文件上传 -->
|
||||
@ -51,27 +52,27 @@
|
||||
</el-upload>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import { MaterialType, useBeforeUpload } from '@/views/mp/hooks/useUpload'
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select'
|
||||
import { UploadType, useBeforeUpload } from '@/views/mp/hooks/useUpload'
|
||||
import type { UploadRawFile } from 'element-plus'
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
import { ObjData } from './types'
|
||||
import { Reply } from './types'
|
||||
const message = useMessage()
|
||||
|
||||
const UPLOAD_URL = import.meta.env.VITE_API_BASEPATH + '/admin-api/mp/material/upload-temporary'
|
||||
const HEADERS = { Authorization: 'Bearer ' + getAccessToken() } // 设置上传的请求头部
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: ObjData
|
||||
modelValue: Reply
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: ObjData)
|
||||
(e: 'update:modelValue', v: Reply)
|
||||
}>()
|
||||
const objData = computed<ObjData>({
|
||||
const reply = computed<Reply>({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
@ -79,14 +80,13 @@ const objData = computed<ObjData>({
|
||||
const showDialog = ref(false)
|
||||
const fileList = ref([])
|
||||
const uploadData = reactive({
|
||||
accountId: objData.value.accountId,
|
||||
accountId: reply.value.accountId,
|
||||
type: 'image',
|
||||
title: '',
|
||||
introduction: ''
|
||||
})
|
||||
|
||||
const beforeImageUpload = (rawFile: UploadRawFile) =>
|
||||
useBeforeUpload(MaterialType.Image, 2)(rawFile)
|
||||
const beforeImageUpload = (rawFile: UploadRawFile) => useBeforeUpload(UploadType.Image, 2)(rawFile)
|
||||
|
||||
const onUploadSuccess = (res: any) => {
|
||||
if (res.code !== 0) {
|
||||
@ -104,18 +104,18 @@ const onUploadSuccess = (res: any) => {
|
||||
}
|
||||
|
||||
const onDelete = () => {
|
||||
objData.value.mediaId = null
|
||||
objData.value.url = null
|
||||
objData.value.name = null
|
||||
reply.value.mediaId = null
|
||||
reply.value.url = null
|
||||
reply.value.name = null
|
||||
}
|
||||
|
||||
const selectMaterial = (item) => {
|
||||
showDialog.value = false
|
||||
|
||||
objData.value.type = 'image'
|
||||
objData.value.mediaId = item.mediaId
|
||||
objData.value.url = item.url
|
||||
objData.value.name = item.name
|
||||
// reply.value.type = 'image'
|
||||
reply.value.mediaId = item.mediaId
|
||||
reply.value.url = item.url
|
||||
reply.value.name = item.name
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,14 +1,11 @@
|
||||
<template>
|
||||
<el-tab-pane name="music">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:service" />音乐</el-row>
|
||||
</template>
|
||||
<div>
|
||||
<el-row align="middle" justify="center">
|
||||
<el-col :span="6">
|
||||
<el-row align="middle" justify="center" class="thumb-div">
|
||||
<el-col :span="24">
|
||||
<el-row align="middle" justify="center">
|
||||
<img style="width: 100px" v-if="objData.thumbMediaUrl" :src="objData.thumbMediaUrl" />
|
||||
<img style="width: 100px" v-if="reply.thumbMediaUrl" :src="reply.thumbMediaUrl" />
|
||||
<icon v-else icon="ep:plus" />
|
||||
</el-row>
|
||||
<el-row align="middle" justify="center" style="margin-top: 2%">
|
||||
@ -42,30 +39,31 @@
|
||||
destroy-on-close
|
||||
>
|
||||
<WxMaterialSelect
|
||||
:objData="{ type: 'image', accountId: objData.accountId }"
|
||||
type="image"
|
||||
:account-id="reply.accountId"
|
||||
@select-material="selectMaterial"
|
||||
/>
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<el-input v-model="objData.title" placeholder="请输入标题" />
|
||||
<el-input v-model="reply.title" placeholder="请输入标题" />
|
||||
<div style="margin: 20px 0"></div>
|
||||
<el-input v-model="objData.description" placeholder="请输入描述" />
|
||||
<el-input v-model="reply.description" placeholder="请输入描述" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div style="margin: 20px 0"></div>
|
||||
<el-input v-model="objData.musicUrl" placeholder="请输入音乐链接" />
|
||||
<el-input v-model="reply.musicUrl" placeholder="请输入音乐链接" />
|
||||
<div style="margin: 20px 0"></div>
|
||||
<el-input v-model="objData.hqMusicUrl" placeholder="请输入高质量音乐链接" />
|
||||
</el-tab-pane>
|
||||
<el-input v-model="reply.hqMusicUrl" placeholder="请输入高质量音乐链接" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select'
|
||||
import type { UploadRawFile } from 'element-plus'
|
||||
import { MaterialType, useBeforeUpload } from '@/views/mp/hooks/useUpload'
|
||||
import { UploadType, useBeforeUpload } from '@/views/mp/hooks/useUpload'
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
import { ObjData } from './types'
|
||||
import { Reply } from './types'
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
@ -73,12 +71,12 @@ const UPLOAD_URL = import.meta.env.VITE_API_BASEPATH + '/admin-api/mp/material/u
|
||||
const HEADERS = { Authorization: 'Bearer ' + getAccessToken() } // 设置上传的请求头部
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: ObjData
|
||||
modelValue: Reply
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: ObjData)
|
||||
(e: 'update:modelValue', v: Reply)
|
||||
}>()
|
||||
const objData = computed<ObjData>({
|
||||
const reply = computed<Reply>({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
@ -86,14 +84,13 @@ const objData = computed<ObjData>({
|
||||
const showDialog = ref(false)
|
||||
const fileList = ref([])
|
||||
const uploadData = reactive({
|
||||
accountId: objData.value.accountId,
|
||||
accountId: reply.value.accountId,
|
||||
type: 'thumb', // 音乐类型为thumb
|
||||
title: '',
|
||||
introduction: ''
|
||||
})
|
||||
|
||||
const beforeImageUpload = (rawFile: UploadRawFile) =>
|
||||
useBeforeUpload(MaterialType.Image, 2)(rawFile)
|
||||
const beforeImageUpload = (rawFile: UploadRawFile) => useBeforeUpload(UploadType.Image, 2)(rawFile)
|
||||
|
||||
const onUploadSuccess = (res: any) => {
|
||||
if (res.code !== 0) {
|
||||
@ -113,7 +110,7 @@ const onUploadSuccess = (res: any) => {
|
||||
const selectMaterial = (item: any) => {
|
||||
showDialog.value = false
|
||||
|
||||
objData.value.thumbMediaId = item.mediaId
|
||||
objData.value.thumbMediaUrl = item.url
|
||||
reply.value.thumbMediaId = item.mediaId
|
||||
reply.value.thumbMediaUrl = item.url
|
||||
}
|
||||
</script>
|
||||
|
@ -1,11 +1,8 @@
|
||||
<template>
|
||||
<el-tab-pane name="news">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:reading" /> 图文</el-row>
|
||||
</template>
|
||||
<div>
|
||||
<el-row>
|
||||
<div class="select-item" v-if="objData.articles?.length > 0">
|
||||
<WxNews :articles="objData.articles" />
|
||||
<div class="select-item" v-if="reply.articles && reply.articles.length > 0">
|
||||
<WxNews :articles="reply.articles" />
|
||||
<el-col class="ope-row">
|
||||
<el-button type="danger" circle @click="onDelete">
|
||||
<Icon icon="ep:delete" />
|
||||
@ -13,7 +10,7 @@
|
||||
</el-col>
|
||||
</div>
|
||||
<!-- 选择素材 -->
|
||||
<el-col :span="24" v-if="!objData.content">
|
||||
<el-col :span="24" v-if="!reply.content">
|
||||
<el-row style="text-align: center" align="middle">
|
||||
<el-col :span="24">
|
||||
<el-button type="success" @click="showDialog = true">
|
||||
@ -25,28 +22,29 @@
|
||||
</el-col>
|
||||
<el-dialog title="选择图文" v-model="showDialog" width="90%" append-to-body destroy-on-close>
|
||||
<WxMaterialSelect
|
||||
:objData="objData"
|
||||
@select-material="selectMaterial"
|
||||
type="news"
|
||||
:account-id="reply.accountId"
|
||||
:newsType="newsType"
|
||||
@select-material="selectMaterial"
|
||||
/>
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue'
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import { ObjData, NewsType } from './types'
|
||||
import WxNews from '@/views/mp/components/wx-news'
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select'
|
||||
import { Reply, NewsType } from './types'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: ObjData
|
||||
modelValue: Reply
|
||||
newsType: NewsType
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: ObjData)
|
||||
(e: 'update:modelValue', v: Reply)
|
||||
}>()
|
||||
const objData = computed<ObjData>({
|
||||
const reply = computed<Reply>({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
@ -55,11 +53,11 @@ const showDialog = ref(false)
|
||||
|
||||
const selectMaterial = (item: any) => {
|
||||
showDialog.value = false
|
||||
objData.value.articles = item.content.newsItem
|
||||
reply.value.articles = item.content.newsItem
|
||||
}
|
||||
|
||||
const onDelete = () => {
|
||||
objData.value.articles = []
|
||||
reply.value.articles = []
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,15 +1,10 @@
|
||||
<template>
|
||||
<el-tab-pane name="text">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:document" /> 文本</el-row>
|
||||
</template>
|
||||
<el-input type="textarea" :rows="5" placeholder="请输入内容" v-model="content" />
|
||||
</el-tab-pane>
|
||||
<el-input type="textarea" :rows="5" placeholder="请输入内容" v-model="content" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
modelValue: string | null
|
||||
modelValue?: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -17,7 +12,7 @@ const emit = defineEmits<{
|
||||
(e: 'input', v: string | null)
|
||||
}>()
|
||||
|
||||
const content = computed<string | null>({
|
||||
const content = computed<string | null | undefined>({
|
||||
get: () => props.modelValue,
|
||||
set: (val: string | null) => {
|
||||
emit('update:modelValue', val)
|
||||
|
@ -1,17 +1,10 @@
|
||||
<template>
|
||||
<el-tab-pane name="video">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:share" /> 视频</el-row>
|
||||
</template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-input v-model="objData.title" class="input-margin-bottom" placeholder="请输入标题" />
|
||||
<el-input
|
||||
class="input-margin-bottom"
|
||||
v-model="objData.description"
|
||||
placeholder="请输入描述"
|
||||
/>
|
||||
<el-input v-model="reply.title" class="input-margin-bottom" placeholder="请输入标题" />
|
||||
<el-input class="input-margin-bottom" v-model="reply.description" placeholder="请输入描述" />
|
||||
<el-row class="ope-row" justify="center">
|
||||
<WxVideoPlayer v-if="objData.url" :url="objData.url" />
|
||||
<WxVideoPlayer v-if="reply.url" :url="reply.url" />
|
||||
</el-row>
|
||||
<el-col>
|
||||
<el-row style="text-align: center" align="middle">
|
||||
@ -27,7 +20,11 @@
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<WxMaterialSelect :objData="objData" @select-material="selectMaterial" />
|
||||
<WxMaterialSelect
|
||||
type="video"
|
||||
:account-id="reply.accountId"
|
||||
@select-material="selectMaterial"
|
||||
/>
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<!-- 文件上传 -->
|
||||
@ -48,16 +45,16 @@
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue'
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play'
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select'
|
||||
import type { UploadRawFile } from 'element-plus'
|
||||
import { MaterialType, useBeforeUpload } from '@/views/mp/hooks/useUpload'
|
||||
import { UploadType, useBeforeUpload } from '@/views/mp/hooks/useUpload'
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
import { ObjData } from './types'
|
||||
import { Reply } from './types'
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
@ -65,12 +62,12 @@ const UPLOAD_URL = import.meta.env.VITE_API_BASEPATH + '/admin-api/mp/material/u
|
||||
const HEADERS = { Authorization: 'Bearer ' + getAccessToken() }
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: ObjData
|
||||
modelValue: Reply
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: ObjData)
|
||||
(e: 'update:modelValue', v: Reply)
|
||||
}>()
|
||||
const objData = computed<ObjData>({
|
||||
const reply = computed<Reply>({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
@ -78,14 +75,13 @@ const objData = computed<ObjData>({
|
||||
const showDialog = ref(false)
|
||||
const fileList = ref([])
|
||||
const uploadData = reactive({
|
||||
accountId: objData.value.accountId,
|
||||
accountId: reply.value.accountId,
|
||||
type: 'video',
|
||||
title: '',
|
||||
introduction: ''
|
||||
})
|
||||
|
||||
const beforeVideoUpload = (rawFile: UploadRawFile) =>
|
||||
useBeforeUpload(MaterialType.Video, 10)(rawFile)
|
||||
const beforeVideoUpload = (rawFile: UploadRawFile) => useBeforeUpload(UploadType.Video, 10)(rawFile)
|
||||
|
||||
const onUploadSuccess = (res: any) => {
|
||||
if (res.code !== 0) {
|
||||
@ -105,16 +101,16 @@ const onUploadSuccess = (res: any) => {
|
||||
const selectMaterial = (item: any) => {
|
||||
showDialog.value = false
|
||||
|
||||
objData.value.mediaId = item.mediaId
|
||||
objData.value.url = item.url
|
||||
objData.value.name = item.name
|
||||
reply.value.mediaId = item.mediaId
|
||||
reply.value.url = item.url
|
||||
reply.value.name = item.name
|
||||
|
||||
// title、introduction:从 item 到 tempObjItem,因为素材里有 title、introduction
|
||||
if (item.title) {
|
||||
objData.value.title = item.title || ''
|
||||
reply.value.title = item.title || ''
|
||||
}
|
||||
if (item.introduction) {
|
||||
objData.value.description = item.introduction || ''
|
||||
reply.value.description = item.introduction || ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,12 +1,9 @@
|
||||
<template>
|
||||
<el-tab-pane name="voice">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:phone" /> 语音</el-row>
|
||||
</template>
|
||||
<div class="select-item2" v-if="objData.url">
|
||||
<p class="item-name">{{ objData.name }}</p>
|
||||
<div>
|
||||
<div class="select-item2" v-if="reply.url">
|
||||
<p class="item-name">{{ reply.name }}</p>
|
||||
<el-row class="ope-row" justify="center">
|
||||
<WxVoicePlayer :url="objData.url" />
|
||||
<WxVoicePlayer :url="reply.url" />
|
||||
</el-row>
|
||||
<el-row class="ope-row" justify="center">
|
||||
<el-button type="danger" circle @click="onDelete"><Icon icon="ep:delete" /></el-button>
|
||||
@ -25,7 +22,11 @@
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<WxMaterialSelect :objData="objData" @select-material="selectMaterial" />
|
||||
<WxMaterialSelect
|
||||
type="voice"
|
||||
:account-id="reply.accountId"
|
||||
@select-material="selectMaterial"
|
||||
/>
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<!-- 文件上传 -->
|
||||
@ -49,27 +50,27 @@
|
||||
</el-upload>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue'
|
||||
import { MaterialType, useBeforeUpload } from '@/views/mp/hooks/useUpload'
|
||||
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 type { UploadRawFile } from 'element-plus'
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
import { ObjData } from './types'
|
||||
import { Reply } from './types'
|
||||
const message = useMessage()
|
||||
|
||||
const UPLOAD_URL = import.meta.env.VITE_API_BASEPATH + '/admin-api/mp/material/upload-temporary'
|
||||
const HEADERS = { Authorization: 'Bearer ' + getAccessToken() } // 设置上传的请求头部
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: ObjData
|
||||
modelValue: Reply
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: ObjData)
|
||||
(e: 'update:modelValue', v: Reply)
|
||||
}>()
|
||||
const objData = computed<ObjData>({
|
||||
const reply = computed<Reply>({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
@ -77,14 +78,13 @@ const objData = computed<ObjData>({
|
||||
const showDialog = ref(false)
|
||||
const fileList = ref([])
|
||||
const uploadData = reactive({
|
||||
accountId: objData.value.accountId,
|
||||
accountId: reply.value.accountId,
|
||||
type: 'voice',
|
||||
title: '',
|
||||
introduction: ''
|
||||
})
|
||||
|
||||
const beforeVoiceUpload = (rawFile: UploadRawFile) =>
|
||||
useBeforeUpload(MaterialType.Voice, 10)(rawFile)
|
||||
const beforeVoiceUpload = (rawFile: UploadRawFile) => useBeforeUpload(UploadType.Voice, 10)(rawFile)
|
||||
|
||||
const onUploadSuccess = (res: any) => {
|
||||
if (res.code !== 0) {
|
||||
@ -102,18 +102,18 @@ const onUploadSuccess = (res: any) => {
|
||||
}
|
||||
|
||||
const onDelete = () => {
|
||||
objData.value.mediaId = null
|
||||
objData.value.url = null
|
||||
objData.value.name = null
|
||||
reply.value.mediaId = null
|
||||
reply.value.url = null
|
||||
reply.value.name = null
|
||||
}
|
||||
|
||||
const selectMaterial = (item: ObjData) => {
|
||||
const selectMaterial = (item: Reply) => {
|
||||
showDialog.value = false
|
||||
|
||||
objData.value.type = 'voice'
|
||||
objData.value.mediaId = item.mediaId
|
||||
objData.value.url = item.url
|
||||
objData.value.name = item.name
|
||||
// reply.value.type = ReplyType.Voice
|
||||
reply.value.mediaId = item.mediaId
|
||||
reply.value.url = item.url
|
||||
reply.value.name = item.name
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,25 +1,54 @@
|
||||
type ReplyType = '' | 'news' | 'image' | 'voice' | 'video' | 'music' | 'text'
|
||||
enum ReplyType {
|
||||
News = 'news',
|
||||
Image = 'image',
|
||||
Voice = 'voice',
|
||||
Video = 'video',
|
||||
Music = 'music',
|
||||
Text = 'text'
|
||||
}
|
||||
|
||||
interface ObjData {
|
||||
interface _Reply {
|
||||
accountId: number
|
||||
type: ReplyType
|
||||
name: string | null
|
||||
content: string | null
|
||||
mediaId: string | null
|
||||
url: string | null
|
||||
title: string | null
|
||||
description: string | null
|
||||
thumbMediaId: string | null
|
||||
thumbMediaUrl: string | null
|
||||
musicUrl: string | null
|
||||
hqMusicUrl: string | null
|
||||
introduction: string | null
|
||||
articles: any[]
|
||||
name?: string | null
|
||||
content?: string | null
|
||||
mediaId?: string | null
|
||||
url?: string | null
|
||||
title?: string | null
|
||||
description?: string | null
|
||||
thumbMediaId?: string | null
|
||||
thumbMediaUrl?: string | null
|
||||
musicUrl?: string | null
|
||||
hqMusicUrl?: string | null
|
||||
introduction?: string | null
|
||||
articles?: any[]
|
||||
}
|
||||
|
||||
type Reply = _Reply //Partial<_Reply>
|
||||
|
||||
enum NewsType {
|
||||
Published = '1',
|
||||
Draft = '2'
|
||||
}
|
||||
|
||||
export { ObjData, NewsType }
|
||||
/** 利用旧的reply[accountId, type]初始化新的Reply */
|
||||
const createEmptyReply = (old: Reply | Ref<Reply>): Reply => {
|
||||
return {
|
||||
accountId: unref(old).accountId,
|
||||
type: unref(old).type,
|
||||
name: null,
|
||||
content: null,
|
||||
mediaId: null,
|
||||
url: null,
|
||||
title: null,
|
||||
description: null,
|
||||
thumbMediaId: null,
|
||||
thumbMediaUrl: null,
|
||||
musicUrl: null,
|
||||
hqMusicUrl: null,
|
||||
introduction: null,
|
||||
articles: []
|
||||
}
|
||||
}
|
||||
|
||||
export { Reply, NewsType, ReplyType, createEmptyReply }
|
||||
|
7
src/views/mp/components/wx-reply/index.ts
Normal file
7
src/views/mp/components/wx-reply/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Reply, NewsType, ReplyType, createEmptyReply } from './components/types'
|
||||
|
||||
import WxReplySelect from './main.vue'
|
||||
|
||||
export type { Reply }
|
||||
export { createEmptyReply, NewsType, ReplyType }
|
||||
export default WxReplySelect
|
@ -8,24 +8,59 @@
|
||||
④ 支持发送【视频】消息时,支持新建视频
|
||||
-->
|
||||
<template>
|
||||
<el-tabs type="border-card" v-model="objData.type" @tab-click="onTabClick">
|
||||
<el-tabs type="border-card" v-model="currentTab">
|
||||
<!-- 类型 1:文本 -->
|
||||
<TabText v-model="objData.content" />
|
||||
<el-tab-pane :name="ReplyType.Text">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:document" /> 文本</el-row>
|
||||
</template>
|
||||
<TabText v-model="reply.content" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 类型 2:图片 -->
|
||||
<TabImage v-model="objData" />
|
||||
<el-tab-pane :name="ReplyType.Image">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:picture" class="mr-5px" /> 图片</el-row>
|
||||
</template>
|
||||
<TabImage v-model="reply" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 类型 3:语音 -->
|
||||
<TabVoice v-model="objData" />
|
||||
<el-tab-pane :name="ReplyType.Voice">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:phone" /> 语音</el-row>
|
||||
</template>
|
||||
<TabVoice v-model="reply" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 类型 4:视频 -->
|
||||
<TabVideo v-model="objData" />
|
||||
<el-tab-pane :name="ReplyType.Video">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:share" /> 视频</el-row>
|
||||
</template>
|
||||
<TabVideo v-model="reply" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 类型 5:图文 -->
|
||||
<TabNews v-model="objData" :news-type="newsType" />
|
||||
<el-tab-pane :name="ReplyType.News">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:reading" /> 图文</el-row>
|
||||
</template>
|
||||
<TabNews v-model="reply" :news-type="newsType" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 类型 6:音乐 -->
|
||||
<TabMusic v-model="objData" />
|
||||
<el-tab-pane :name="ReplyType.Music">
|
||||
<template #label>
|
||||
<el-row align="middle"><Icon icon="ep:service" />音乐</el-row>
|
||||
</template>
|
||||
<TabMusic v-model="reply" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="WxReplySelect">
|
||||
import { ObjData, NewsType } from './components/types'
|
||||
import { Reply, NewsType, ReplyType, createEmptyReply } from './components/types'
|
||||
import TabText from './components/TabText.vue'
|
||||
import TabImage from './components/TabImage.vue'
|
||||
import TabVoice from './components/TabVoice.vue'
|
||||
@ -34,30 +69,54 @@ import TabNews from './components/TabNews.vue'
|
||||
import TabMusic from './components/TabMusic.vue'
|
||||
|
||||
interface Props {
|
||||
objData: ObjData
|
||||
modelValue: Reply
|
||||
newsType?: NewsType
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
newsType: () => NewsType.Published
|
||||
})
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: Reply)
|
||||
}>()
|
||||
|
||||
const objData = reactive(props.objData)
|
||||
// TODO @Dhb52:Tab 切换的时候,应该表单还保留着;清除只有两个时机:1)发送成功后;2)关闭窗口后;我捉摸,是不是每个 TabXXX 组件,是个独立的 Form,然后有自己的对象,不粘在 objData 一起。这样最终就是 MusicMessageForm、ImageMessageForm
|
||||
// const tempObj = new Map().set(objData.type, Object.assign({}, objData))
|
||||
const reply = computed<Reply>({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
// 作为多个标签保存各自Reply的缓存
|
||||
const objCache = new Map<ReplyType, Reply>()
|
||||
// 采用独立的ref来保存当前tab,避免在watch标签变化,对reply进行赋值会产生了循环调用
|
||||
const currentTab = ref<ReplyType>(props.modelValue.type || ReplyType.Text)
|
||||
|
||||
/** 切换消息类型的 tab */
|
||||
const onTabClick = () => {
|
||||
clear()
|
||||
}
|
||||
watch(
|
||||
currentTab,
|
||||
(newTab, oldTab) => {
|
||||
// 第一次进入:oldTab 为 undefined
|
||||
// 判断 newTab 是因为 Reply 为 Partial
|
||||
if (oldTab === undefined || newTab === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
/** 清除除了`type`的字段 */
|
||||
objCache.set(oldTab, unref(reply))
|
||||
|
||||
// 从缓存里面取出新tab内容,有则覆盖Reply,没有则创建空Reply
|
||||
const temp = objCache.get(newTab)
|
||||
if (temp) {
|
||||
reply.value = temp
|
||||
} else {
|
||||
let newData = createEmptyReply(reply)
|
||||
newData.type = newTab
|
||||
reply.value = newData
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
/** 清除除了`type`, `accountId`的字段 */
|
||||
const clear = () => {
|
||||
objData.content = ''
|
||||
objData.mediaId = ''
|
||||
objData.url = ''
|
||||
objData.title = ''
|
||||
objData.description = ''
|
||||
objData.articles = []
|
||||
reply.value = createEmptyReply(reply)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
3
src/views/mp/components/wx-video-play/index.ts
Normal file
3
src/views/mp/components/wx-video-play/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import WxVideoPlayer from './main.vue'
|
||||
|
||||
export default WxVideoPlayer
|
3
src/views/mp/components/wx-voice-play/index.ts
Normal file
3
src/views/mp/components/wx-voice-play/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import WxVoicePlayer from './main.vue'
|
||||
|
||||
export default WxVoicePlayer
|
@ -7,7 +7,7 @@
|
||||
1)joolun 的做法:使用 mediaId 从微信公众号,下载对应的 mp4 素材,从而播放内容;
|
||||
存在的问题:mediaId 有效期是 3 天,超过时间后无法播放
|
||||
2)重构后的做法:后端接收到微信公众号的视频消息后,将视频消息的 media_id 的文件内容保存到文件服务器中,这样前端可以直接使用 URL 播放。
|
||||
② 代码优化:将 props 中的 objData 调成为 data 中对应的属性,并补充相关注释
|
||||
② 代码优化:将 props 中的 reply 调成为 data 中对应的属性,并补充相关注释
|
||||
-->
|
||||
<template>
|
||||
<div class="wx-voice-div" @click="playVoice">
|
||||
@ -89,8 +89,8 @@ const amrStop = () => {
|
||||
padding: 5px;
|
||||
background-color: #eaeaea;
|
||||
border-radius: 10px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 120px;
|
||||
height: 50px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
Reference in New Issue
Block a user