Commit 02ccf52d6c5476e549cc164e980531d45a957d6d

Authored by YunaiV
1 parent 5901ab66

mp:增加发送【图文】消息

yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.http
@@ -19,6 +19,14 @@ tenant-id: {{adminTenentId}} @@ -19,6 +19,14 @@ tenant-id: {{adminTenentId}}
19 "content": "我是内容", 19 "content": "我是内容",
20 "contentSourceUrl": "https://www.iocoder.cn", 20 "contentSourceUrl": "https://www.iocoder.cn",
21 "thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn" 21 "thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn"
  22 + },
  23 + {
  24 + "title": "我是标题 2",
  25 + "author": "我是作者 2",
  26 + "digest": "我是摘要 2",
  27 + "content": "我是内容 2",
  28 + "contentSourceUrl": "https://www.iocoder.cn",
  29 + "thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn"
22 } 30 }
23 ] 31 ]
24 } 32 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.http
@@ -5,7 +5,7 @@ Authorization: Bearer {{token}} @@ -5,7 +5,7 @@ Authorization: Bearer {{token}}
5 tenant-id: {{adminTenentId}} 5 tenant-id: {{adminTenentId}}
6 6
7 ### 请求 /mp/free-publish/submit 接口 => 成功 7 ### 请求 /mp/free-publish/submit 接口 => 成功
8 -POST {{baseUrl}}/mp/free-publish/submit?accountId=1&mediaId=r6ryvl6LrxBU0miaST4Y-pEm50d1qKxNPkZVzrRZthSJHKCgiylCf4tARZfybZ_O 8 +POST {{baseUrl}}/mp/free-publish/submit?accountId=1&mediaId=r6ryvl6LrxBU0miaST4Y-vilmd7iS51D8IPddxflWrau0hIQ2ovY8YanO5jlgUcM
9 Content-Type: application/json 9 Content-Type: application/json
10 Authorization: Bearer {{token}} 10 Authorization: Bearer {{token}}
11 tenant-id: {{adminTenentId}} 11 tenant-id: {{adminTenentId}}
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.java
@@ -44,6 +44,7 @@ public class MpFreePublishController { @@ -44,6 +44,7 @@ public class MpFreePublishController {
44 } catch (WxErrorException e) { 44 } catch (WxErrorException e) {
45 throw exception(FREE_PUBLISH_LIST_FAIL, e.getError().getErrorMsg()); 45 throw exception(FREE_PUBLISH_LIST_FAIL, e.getError().getErrorMsg());
46 } 46 }
  47 + // todo 芋艿:需要查询对应的缩略图,不然前端无法展示
47 48
48 // 返回分页 49 // 返回分页
49 return success(new PageResult<>(publicationRecords.getItems(), publicationRecords.getTotalCount().longValue())); 50 return success(new PageResult<>(publicationRecords.getItems(), publicationRecords.getTotalCount().longValue()));
yudao-ui-admin/src/api/mp/freePublish.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获得公众号素材分页
  4 +export function getFreePublishPage(query) {
  5 + return request({
  6 + url: '/mp/free-publish/page',
  7 + method: 'get',
  8 + params: query
  9 + })
  10 +}
yudao-ui-admin/src/views/mp/components/wx-material-select/main.vue
@@ -48,7 +48,7 @@ @@ -48,7 +48,7 @@
48 </el-table> 48 </el-table>
49 <!-- 分页组件 --> 49 <!-- 分页组件 -->
50 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" 50 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
51 - @pagination="getMaterialPage"/> 51 + @pagination="getPage"/>
52 </div> 52 </div>
53 <div v-else-if="objData.type === 'video'"> 53 <div v-else-if="objData.type === 'video'">
54 <!-- 列表 --> 54 <!-- 列表 -->
@@ -78,41 +78,32 @@ @@ -78,41 +78,32 @@
78 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" 78 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
79 @pagination="getMaterialPage"/> 79 @pagination="getMaterialPage"/>
80 </div> 80 </div>
81 - <div v-else-if="objData.type == 'news'"> 81 + <div v-else-if="objData.type === 'news'">
82 <div class="waterfall" v-loading="loading"> 82 <div class="waterfall" v-loading="loading">
83 - <div class="waterfall-item" v-for="item in list" :key="item.mediaId" v-if="item.content && item.content.articles">  
84 - <WxNews :objData="item.content.articles"></WxNews> 83 + <div class="waterfall-item" v-for="item in list" :key="item.mediaId" v-if="item.content && item.content.newsItem">
  84 + <wx-news :articles="item.content.newsItem" />
85 <el-row class="ope-row"> 85 <el-row class="ope-row">
86 - <el-button size="mini" type="success" @click="selectMaterial(item)">选择<i class="el-icon-circle-check el-icon--right"></i></el-button> 86 + <el-button size="mini" type="success" @click="selectMaterial(item)">
  87 + 选择<i class="el-icon-circle-check el-icon--right"></i>
  88 + </el-button>
87 </el-row> 89 </el-row>
88 </div> 90 </div>
89 </div> 91 </div>
90 - <div v-if="list.length <=0 && !loading" class="el-table__empty-block"> 92 + <!-- 分页组件 -->
  93 + <div v-if="list.length <= 0 && !loading" class="el-table__empty-block">
91 <span class="el-table__empty-text">暂无数据</span> 94 <span class="el-table__empty-text">暂无数据</span>
92 </div> 95 </div>
93 - <span slot="footer" class="dialog-footer">  
94 - <el-pagination  
95 - @size-change="sizeChange"  
96 - :current-page.sync="page.currentPage"  
97 - :page-sizes="[10, 20]"  
98 - :page-size="page.pageSize"  
99 - layout="total, sizes, prev, pager, next, jumper"  
100 - :total="page.total"  
101 - class="pagination"  
102 - >  
103 - </el-pagination>  
104 - </span> 96 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  97 + @pagination="getMaterialPage"/>
105 </div> 98 </div>
106 </template> 99 </template>
107 100
108 <script> 101 <script>
109 -  
110 - // import { tableOptionVoice } from '@/const/crud/wxmp/wxmaterial_voice'  
111 - // import { tableOptionVideo } from '@/const/crud/wxmp/wxmaterial_video'  
112 import WxNews from '@/views/mp/components/wx-news/main.vue'; 102 import WxNews from '@/views/mp/components/wx-news/main.vue';
113 import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue'; 103 import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
114 import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue'; 104 import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
115 import { getMaterialPage } from "@/api/mp/material"; 105 import { getMaterialPage } from "@/api/mp/material";
  106 + import {getFreePublishPage} from "@/api/mp/freePublish";
116 107
117 export default { 108 export default {
118 name: "wxMaterialSelect", 109 name: "wxMaterialSelect",
@@ -143,56 +134,40 @@ @@ -143,56 +134,40 @@
143 queryParams: { 134 queryParams: {
144 pageNo: 1, 135 pageNo: 1,
145 pageSize: 10, 136 pageSize: 10,
  137 + accountId: this.objData.accountId,
146 }, 138 },
147 // tableOptionVoice: tableOptionVoice, 139 // tableOptionVoice: tableOptionVoice,
148 // tableOptionVideo: tableOptionVideo, 140 // tableOptionVideo: tableOptionVideo,
149 } 141 }
150 }, 142 },
151 created() { 143 created() {
152 - this.getPage(this.page) 144 + this.getPage()
153 }, 145 },
154 methods:{ 146 methods:{
155 - selectMaterial(item){ 147 + selectMaterial(item) {
156 this.$emit('selectMaterial', item) 148 this.$emit('selectMaterial', item)
157 }, 149 },
158 - getPage(page, params) { 150 + getPage() {
159 this.loading = true 151 this.loading = true
160 - if(this.objData.type == 'news'){ // 【图文】  
161 - if(this.newsType == '1'){  
162 - getPageNews(Object.assign({  
163 - current: page.currentPage,  
164 - size: page.pageSize,  
165 - appId:this.appId,  
166 - }, params)).then(response => {  
167 - let tableData = response.data.items  
168 - tableData.forEach(item => {  
169 - item.mediaId = item.articleId  
170 - item.content.articles = item.content.newsItem  
171 - })  
172 - this.list = tableData  
173 - this.page.total = response.data.totalCount  
174 - this.page.currentPage = page.currentPage  
175 - this.page.pageSize = page.pageSize  
176 - this.loading = false  
177 - })  
178 - }else if(this.newsType == '2'){  
179 - getPageNewsDraft(Object.assign({  
180 - current: page.currentPage,  
181 - size: page.pageSize,  
182 - appId:this.appId,  
183 - }, params)).then(response => {  
184 - let tableData = response.data.items  
185 - tableData.forEach(item => {  
186 - item.mediaId = item.mediaId  
187 - item.content.articles = item.content.newsItem  
188 - })  
189 - this.list = tableData  
190 - this.page.total = response.data.totalCount  
191 - this.page.currentPage = page.currentPage  
192 - this.page.pageSize = page.pageSize  
193 - this.loading = false 152 + if (this.objData.type === 'news' && this.newsType === '1') { // 【图文】+ 【已发布】
  153 + this.getFreePublishPage();
  154 + } else if (this.objData.type === 'news' && this.newsType === '2') { // 【图文】+ 【草稿】
  155 + getPageNewsDraft(Object.assign({
  156 + current: page.currentPage,
  157 + size: page.pageSize,
  158 + appId:this.appId,
  159 + }, params)).then(response => {
  160 + let tableData = response.data.items
  161 + tableData.forEach(item => {
  162 + item.mediaId = item.mediaId
  163 + item.content.articles = item.content.newsItem
194 }) 164 })
195 - } 165 + this.list = tableData
  166 + this.page.total = response.data.totalCount
  167 + this.page.currentPage = page.currentPage
  168 + this.page.pageSize = page.pageSize
  169 + this.loading = false
  170 + })
196 } else { // 【素材】 171 } else { // 【素材】
197 this.getMaterialPage(); 172 this.getMaterialPage();
198 } 173 }
@@ -208,20 +183,20 @@ @@ -208,20 +183,20 @@
208 this.loading = false 183 this.loading = false
209 }) 184 })
210 }, 185 },
211 - sizeChange(val) {  
212 - this.page.currentPage = 1  
213 - this.page.pageSize = val  
214 - this.getPage(this.page)  
215 - },  
216 - currentChange(val) {  
217 - this.page.currentPage = val  
218 - this.getPage(this.page)  
219 - },  
220 - /**  
221 - * 刷新回调  
222 - */  
223 - refreshChange(page) {  
224 - this.getPage(this.page) 186 + getFreePublishPage() {
  187 + getFreePublishPage(this.queryParams).then(response => {
  188 + // 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面
  189 + response.data.list.forEach(item => {
  190 + const newsItem = item.content.newsItem;
  191 + newsItem.forEach(article => {
  192 + article.picUrl = article.thumbUrl;
  193 + })
  194 + })
  195 + this.list = response.data.list
  196 + this.total = response.data.total
  197 + }).finally(() => {
  198 + this.loading = false
  199 + })
225 } 200 }
226 } 201 }
227 }; 202 };
yudao-ui-admin/src/views/mp/components/wx-msg/main.vue
@@ -155,21 +155,23 @@ import { getUser } from &quot;@/api/mp/user&quot;; @@ -155,21 +155,23 @@ import { getUser } from &quot;@/api/mp/user&quot;;
155 if (!this.objData) { 155 if (!this.objData) {
156 return; 156 return;
157 } 157 }
158 - if (this.objData.type === 'news') {  
159 - this.objData.content.articles = [this.objData.content.articles[0]] 158 + // 公众号限制:客服消息,公众号只允许发送一条
  159 + if (this.objData.type === 'news'
  160 + && this.objData.articles.length > 1) {
  161 + this.objData.articles = [this.objData.articles[0]]
160 this.$message({ 162 this.$message({
161 showClose: true, 163 showClose: true,
162 - message: '图文消息条数限制在1条以内,已默认发送第一条', 164 + message: '图文消息条数限制在 1 条以内,已默认发送第一条',
163 type: 'success' 165 type: 'success'
164 }) 166 })
165 } 167 }
  168 +
  169 + // 执行发送
166 this.sendLoading = true 170 this.sendLoading = true
167 sendMessage(Object.assign({ 171 sendMessage(Object.assign({
168 userId: this.userId 172 userId: this.userId
169 }, { 173 }, {
170 - ...this.objData,  
171 - // content: this.objData.repContent,  
172 - // TODO 芋艿:临时适配,保证可用 174 + ...this.objData
173 })).then(response => { 175 })).then(response => {
174 this.sendLoading = false 176 this.sendLoading = false
175 // 添加到消息列表,并滚动 177 // 添加到消息列表,并滚动
yudao-ui-admin/src/views/mp/components/wx-news/main.vue
@@ -41,7 +41,10 @@ @@ -41,7 +41,10 @@
41 articles: { 41 articles: {
42 type: Array // title - 标题;description - 描述;picUrl - 图片连接;url - 跳转链接 42 type: Array // title - 标题;description - 描述;picUrl - 图片连接;url - 跳转链接
43 } 43 }
44 - } 44 + },
  45 + created() {
  46 + console.log(this.articles)
  47 + },
45 }; 48 };
46 </script> 49 </script>
47 50
yudao-ui-admin/src/views/mp/components/wx-reply/main.vue
@@ -118,18 +118,20 @@ @@ -118,18 +118,20 @@
118 </el-row> 118 </el-row>
119 </el-row> 119 </el-row>
120 </el-tab-pane> 120 </el-tab-pane>
  121 + <!-- 类型 5:图文 -->
121 <el-tab-pane name="news"> 122 <el-tab-pane name="news">
122 <span slot="label"><i class="el-icon-news"></i> 图文</span> 123 <span slot="label"><i class="el-icon-news"></i> 图文</span>
123 <el-row> 124 <el-row>
124 - <div class="select-item" v-if="objData.content">  
125 - <WxNews :objData="objData.content.articles"></WxNews> 125 + <div class="select-item" v-if="objData.articles">
  126 + <wx-news :articles="objData.articles" />
126 <el-row class="ope-row"> 127 <el-row class="ope-row">
127 - <el-button type="danger" icon="el-icon-delete" circle @click="deleteObj"></el-button> 128 + <el-button type="danger" icon="el-icon-delete" circle @click="deleteObj" />
128 </el-row> 129 </el-row>
129 </div> 130 </div>
  131 + <!-- 选择素材 -->
130 <div v-if="!objData.content"> 132 <div v-if="!objData.content">
131 <el-row style="text-align: center"> 133 <el-row style="text-align: center">
132 - <el-col :span="24" class="col-select2"> 134 + <el-col :span="24">
133 <el-button type="success" @click="openMaterial">{{newsType === '1' ? '选择已发布图文' : '选择草稿箱图文'}}<i class="el-icon-circle-check el-icon--right"></i></el-button> 135 <el-button type="success" @click="openMaterial">{{newsType === '1' ? '选择已发布图文' : '选择草稿箱图文'}}<i class="el-icon-circle-check el-icon--right"></i></el-button>
134 </el-col> 136 </el-col>
135 </el-row> 137 </el-row>
@@ -369,7 +371,10 @@ @@ -369,7 +371,10 @@
369 // 创建 tempObjItem 对象,并设置对应的值 371 // 创建 tempObjItem 对象,并设置对应的值
370 let tempObjItem = {} 372 let tempObjItem = {}
371 tempObjItem.type = this.objData.type; 373 tempObjItem.type = this.objData.type;
372 - if (this.objData.type === 'music') { // 音乐需要特殊处理,因为选择的是图片的缩略图 374 + if (this.objData.type === 'news') {
  375 + tempObjItem.articles = item.content.newsItem
  376 + this.objData.articles = item.content.newsItem
  377 + } else if (this.objData.type === 'music') { // 音乐需要特殊处理,因为选择的是图片的缩略图
373 tempObjItem.thumbMediaId = item.mediaId 378 tempObjItem.thumbMediaId = item.mediaId
374 this.objData.thumbMediaId = item.mediaId 379 this.objData.thumbMediaId = item.mediaId
375 tempObjItem.thumbMediaUrl = item.url 380 tempObjItem.thumbMediaUrl = item.url
@@ -431,7 +436,7 @@ @@ -431,7 +436,7 @@
431 }, 436 },
432 deleteObj() { 437 deleteObj() {
433 if (this.objData.type === 'news') { 438 if (this.objData.type === 'news') {
434 - this.objData.articles = [] 439 + this.$delete(this.objData, 'articles');
435 } else if(this.objData.type === 'image') { 440 } else if(this.objData.type === 'image') {
436 this.objData.mediaId = null 441 this.objData.mediaId = null
437 this.objData.url = null 442 this.objData.url = null