Commit d1cbe0c3fd4e18766a46f59f7a0eb1dbd99e28cd

Authored by YunaiV
1 parent 90ffe5ad

mp:增加图文草稿箱的删除、发布功能

yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java
... ... @@ -47,6 +47,7 @@ public interface ErrorCodeConstants {
47 47 ErrorCode DRAFT_LIST_FAIL = new ErrorCode(1006007000, "获得草稿列表失败,原因:{}");
48 48 ErrorCode DRAFT_CREATE_FAIL = new ErrorCode(1006007001, "创建草稿失败,原因:{}");
49 49 ErrorCode DRAFT_UPDATE_FAIL = new ErrorCode(1006007002, "更新草稿失败,原因:{}");
  50 + ErrorCode DRAFT_DELETE_FAIL = new ErrorCode(1006007002, "删除草稿失败,原因:{}");
50 51  
51 52 // TODO 要处理下
52 53 ErrorCode MENU_NOT_EXISTS = new ErrorCode(1006001002, "菜单不存在");
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.java
1 1 package cn.iocoder.yudao.module.mp.controller.admin.news;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 7 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
6 8 import cn.iocoder.yudao.module.mp.controller.admin.news.vo.MpDraftPageReqVO;
  9 +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO;
7 10 import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
  11 +import cn.iocoder.yudao.module.mp.service.material.MpMaterialService;
8 12 import io.swagger.annotations.Api;
9 13 import io.swagger.annotations.ApiImplicitParam;
10 14 import io.swagger.annotations.ApiImplicitParams;
... ... @@ -12,17 +16,21 @@ import io.swagger.annotations.ApiOperation;
12 16 import me.chanjar.weixin.common.error.WxErrorException;
13 17 import me.chanjar.weixin.mp.api.WxMpService;
14 18 import me.chanjar.weixin.mp.bean.draft.*;
  19 +import org.springframework.security.access.prepost.PreAuthorize;
15 20 import org.springframework.validation.annotation.Validated;
16 21 import org.springframework.web.bind.annotation.*;
17 22  
18 23 import javax.annotation.Resource;
  24 +import java.util.HashSet;
19 25 import java.util.List;
  26 +import java.util.Map;
  27 +import java.util.Set;
20 28  
21 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
22 30 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  31 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
23 32 import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*;
24 33  
25   -// TODO 芋艿:权限
26 34 @Api(tags = "管理后台 - 公众号草稿")
27 35 @RestController
28 36 @RequestMapping("/mp/draft")
... ... @@ -32,8 +40,12 @@ public class MpDraftController {
32 40 @Resource
33 41 private MpServiceFactory mpServiceFactory;
34 42  
  43 + @Resource
  44 + private MpMaterialService mpMaterialService;
  45 +
35 46 @GetMapping("/page")
36 47 @ApiOperation("获得草稿分页")
  48 + @PreAuthorize("@ss.hasPermission('mp:draft:query')")
37 49 public CommonResult<PageResult<WxMpDraftItem>> getDraftPage(MpDraftPageReqVO reqVO) {
38 50 // 从公众号查询草稿箱
39 51 WxMpService mpService = mpServiceFactory.getRequiredMpService(reqVO.getAccountId());
... ... @@ -43,16 +55,35 @@ public class MpDraftController {
43 55 } catch (WxErrorException e) {
44 56 throw exception(DRAFT_LIST_FAIL, e.getError().getErrorMsg());
45 57 }
  58 + // 查询对应的图片地址。目的:解决公众号的图片链接无法在我们后台展示
  59 + setDraftThumbUrl(draftList.getItems());
46 60  
47 61 // 返回分页
48 62 return success(new PageResult<>(draftList.getItems(), draftList.getTotalCount().longValue()));
49 63 }
50 64  
  65 + private void setDraftThumbUrl(List<WxMpDraftItem> items) {
  66 + // 1.1 获得 mediaId 数组
  67 + Set<String> mediaIds = new HashSet<>();
  68 + items.forEach(item -> item.getContent().getNewsItem().forEach(newsItem -> mediaIds.add(newsItem.getThumbMediaId())));
  69 + if (CollUtil.isEmpty(mediaIds)) {
  70 + return;
  71 + }
  72 + // 1.2 批量查询对应的 Media 素材
  73 + Map<String, MpMaterialDO> materials = CollectionUtils.convertMap(mpMaterialService.getMaterialListByMediaId(mediaIds),
  74 + MpMaterialDO::getMediaId);
  75 +
  76 + // 2. 设置回 WxMpDraftItem 记录
  77 + items.forEach(item -> item.getContent().getNewsItem().forEach(newsItem ->
  78 + findAndThen(materials, newsItem.getThumbMediaId(), material -> newsItem.setThumbUrl(material.getUrl()))));
  79 + }
  80 +
51 81 @PostMapping("/create")
52 82 @ApiOperation("创建草稿")
53 83 @ApiImplicitParam(name = "accountId", value = "公众号账号的编号", required = true,
54 84 example = "1024", dataTypeClass = Long.class)
55   - public CommonResult<String> createDraft(@RequestParam("accountId") Long accountId,
  85 + @PreAuthorize("@ss.hasPermission('mp:draft:create')")
  86 + public CommonResult<String> deleteDraft(@RequestParam("accountId") Long accountId,
56 87 @RequestBody WxMpAddDraft draft) {
57 88 WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId);
58 89 try {
... ... @@ -71,7 +102,8 @@ public class MpDraftController {
71 102 @ApiImplicitParam(name = "mediaId", value = "草稿素材的编号", required = true,
72 103 example = "xxx", dataTypeClass = String.class),
73 104 })
74   - public CommonResult<Boolean> createDraft(@RequestParam("accountId") Long accountId,
  105 + @PreAuthorize("@ss.hasPermission('mp:draft:update')")
  106 + public CommonResult<Boolean> deleteDraft(@RequestParam("accountId") Long accountId,
75 107 @RequestParam("mediaId") String mediaId,
76 108 @RequestBody List<WxMpDraftArticles> articles) {
77 109 WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId);
... ... @@ -86,4 +118,24 @@ public class MpDraftController {
86 118 }
87 119 }
88 120  
  121 + @DeleteMapping("/delete")
  122 + @ApiOperation("删除草稿")
  123 + @ApiImplicitParams({
  124 + @ApiImplicitParam(name = "accountId", value = "公众号账号的编号", required = true,
  125 + example = "1024", dataTypeClass = Long.class),
  126 + @ApiImplicitParam(name = "mediaId", value = "草稿素材的编号", required = true,
  127 + example = "xxx", dataTypeClass = String.class),
  128 + })
  129 + @PreAuthorize("@ss.hasPermission('mp:draft:delete')")
  130 + public CommonResult<Boolean> deleteDraft(@RequestParam("accountId") Long accountId,
  131 + @RequestParam("mediaId") String mediaId) {
  132 + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId);
  133 + try {
  134 + mpService.getDraftService().delDraft(mediaId);
  135 + return success(true);
  136 + } catch (WxErrorException e) {
  137 + throw exception(DRAFT_DELETE_FAIL, e.getError().getErrorMsg());
  138 + }
  139 + }
  140 +
89 141 }
... ...
yudao-ui-admin/src/api/mp/draft.js
... ... @@ -28,3 +28,11 @@ export function updateDraft(accountId, mediaId, articles) {
28 28 data: articles
29 29 })
30 30 }
  31 +
  32 +// 删除草稿
  33 +export function deleteDraft(accountId, mediaId) {
  34 + return request({
  35 + url: '/mp/draft/delete?accountId=' + accountId + '&mediaId=' + mediaId,
  36 + method: 'delete',
  37 + })
  38 +}
... ...
yudao-ui-admin/src/api/mp/freePublish.js
... ... @@ -16,3 +16,11 @@ export function deleteFreePublish(accountId, articleId) {
16 16 method: 'delete'
17 17 })
18 18 }
  19 +
  20 +// 发布公众号素材
  21 +export function submitFreePublish(accountId, mediaId) {
  22 + return request({
  23 + url: '/mp/free-publish/submit?accountId=' + accountId + '&mediaId=' + mediaId,
  24 + method: 'post'
  25 + })
  26 +}
... ...
yudao-ui-admin/src/views/mp/draft/index.vue
... ... @@ -22,6 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 22 SOFTWARE.
23 23 芋道源码:
24 24 ① 优化代码,和项目的代码保持一致
  25 + ② 清理冗余代码,保证代码整洁
  26 + ③ 增加注释,提升可读性
25 27 -->
26 28 <template>
27 29 <div class="app-container">
... ... @@ -53,11 +55,11 @@ SOFTWARE.
53 55 <div v-if="item.content && item.content.newsItem" class="waterfall-item" v-for="item in list"
54 56 :key='item.articleId'>
55 57 <wx-news :articles="item.content.newsItem" />
56   - <!-- TODO 芋艿:权限、样式(搜索框之类的) -->
  58 + <!-- 操作按钮 -->
57 59 <el-row class="ope-row">
58   - <el-button type="success" circle @click="handlePublishNews(item)">发布</el-button>
59   - <el-button type="primary" icon="el-icon-edit" circle @click="handleUpdate(item)"></el-button>
60   - <el-button type="danger" icon="el-icon-delete" circle @click="delMaterial(item)"></el-button>
  60 + <el-button type="success" circle @click="handlePublish(item)" v-hasPermi="['mp:free-publish:submit']">发布</el-button>
  61 + <el-button type="primary" icon="el-icon-edit" circle @click="handleUpdate(item)" v-hasPermi="['mp:draft:update']" />
  62 + <el-button type="danger" icon="el-icon-delete" circle @click="handleDelete(item)" v-hasPermi="['mp:draft:delete']" />
61 63 </el-row>
62 64 </div>
63 65 </div>
... ... @@ -147,7 +149,6 @@ SOFTWARE.
147 149 <wx-editor v-model="articlesAdd[isActiveAddNews].content" :account-id="this.uploadData.accountId"
148 150 v-if="hackResetEditor"/>
149 151 </el-row>
150   - <!-- 原文地址 -->
151 152 </div>
152 153 <div slot="footer" class="dialog-footer">
153 154 <el-button @click="dialogNewsVisible = false">取 消</el-button>
... ... @@ -158,13 +159,13 @@ SOFTWARE.
158 159 </template>
159 160  
160 161 <script>
161   -// import { getPage as getPage1 } from '@/api/wxmp/wxmaterial'
162 162 import WxEditor from '@/views/mp/components/wx-editor/WxEditor.vue';
163 163 import WxNews from '@/views/mp/components/wx-news/main.vue';
164 164 import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
165 165 import { getAccessToken } from '@/utils/auth'
166   -import {createDraft, getDraftPage, updateDraft} from "@/api/mp/draft";
  166 +import {createDraft, deleteDraft, getDraftPage, updateDraft} from "@/api/mp/draft";
167 167 import { getSimpleAccounts } from "@/api/mp/account";
  168 +import {deleteFreePublish, submitFreePublish} from "@/api/mp/freePublish";
168 169  
169 170 export default {
170 171 name: 'mpDraft',
... ... @@ -221,7 +222,7 @@ export default {
221 222 this.setAccountId(this.accounts[0].id);
222 223 }
223 224 // 加载数据
224   - // this.getList(); // TODO 芋艿:开发完,放出来
  225 + this.getList();
225 226 })
226 227 },
227 228 methods: {
... ... @@ -434,44 +435,26 @@ export default {
434 435 },
435 436  
436 437 // ======================== 草稿箱发布 ========================
437   - handlePublishNews(item){
438   - this.$confirm('你正在通过发布的方式发表内容。 发布不占用群发次数,一天可多次发布。已发布内容不会推送给用户,也不会展示在公众号主页中。 发布后,你可以前往发表记录获取链接,也可以将发布内容添加到自定义菜单、自动回复、话题和页面模板中。', '提示', {
439   - confirmButtonText: '确定',
440   - cancelButtonText: '取消',
441   - type: 'warning'
  438 + handlePublish(item) {
  439 + const accountId = this.queryParams.accountId;
  440 + const mediaId = item.mediaId;
  441 + const content = '你正在通过发布的方式发表内容。 发布不占用群发次数,一天可多次发布。已发布内容不会推送给用户,也不会展示在公众号主页中。 发布后,你可以前往发表记录获取链接,也可以将发布内容添加到自定义菜单、自动回复、话题和页面模板中。';
  442 + this.$modal.confirm(content).then(function() {
  443 + return submitFreePublish(accountId, mediaId);
442 444 }).then(() => {
443   - this.loading = true
444   - publish(item.mediaId).then(response => {
445   - this.loading = false
446   - this.$message.success('发布任务提交成功')
447   - this.getList(this.queryParams)
448   - }).catch(() => {
449   - this.loading = false
450   - })
451   - }).catch(() => {
452   - })
  445 + this.getList();
  446 + this.$modal.msgSuccess("发布成功");
  447 + }).catch(() => {});
453 448 },
454   - delMaterial(item){
455   - this.$confirm('此操作将永久删除该草稿, 是否继续?', '提示', {
456   - confirmButtonText: '确定',
457   - cancelButtonText: '取消',
458   - type: 'warning'
  449 + handleDelete(item) {
  450 + const accountId = this.queryParams.accountId;
  451 + const mediaId = item.mediaId;
  452 + this.$modal.confirm('此操作将永久删除该草稿, 是否继续?').then(function() {
  453 + return deleteDraft(accountId, mediaId);
459 454 }).then(() => {
460   - this.loading = true
461   - delObj({
462   - id:item.mediaId
463   - }).then(response => {
464   - this.loading = false
465   - if(response.code == 200){
466   - this.getList(this.queryParams)
467   - }else{
468   - this.loading = false
469   - this.$message.error('删除出错:' + response.msg)
470   - }
471   - }).catch(() => {
472   - this.loading = false
473   - })
474   - })
  455 + this.getList();
  456 + this.$modal.msgSuccess("删除成功");
  457 + }).catch(() => {});
475 458 },
476 459 }
477 460 }
... ...