Commit 2173cf0364254fb620df464c162085563d4306fe
1 parent
c0b95025
mp:menu 前端接入菜单的保存、清空操作
Showing
13 changed files
with
191 additions
and
140 deletions
yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java
| ... | ... | @@ -52,6 +52,7 @@ public interface ErrorCodeConstants { |
| 52 | 52 | ErrorCode DRAFT_DELETE_FAIL = new ErrorCode(1006007002, "删除草稿失败,原因:{}"); |
| 53 | 53 | |
| 54 | 54 | // ========== 公众号菜单 1006008000============ |
| 55 | - ErrorCode MENU_NOT_EXISTS = new ErrorCode(1006008000, "菜单不存在"); | |
| 55 | + ErrorCode MENU_SAVE_FAIL = new ErrorCode(1006008000, "创建菜单失败,原因:{}"); | |
| 56 | + ErrorCode MENU_DELETE_FAIL = new ErrorCode(1006008001, "删除菜单失败,原因:{}"); | |
| 56 | 57 | |
| 57 | 58 | } | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.http
| ... | ... | @@ -6,24 +6,24 @@ tenant-id: {{adminTenentId}} |
| 6 | 6 | |
| 7 | 7 | { |
| 8 | 8 | "accountId": "1", |
| 9 | - "buttons": [ | |
| 9 | + "menus": [ | |
| 10 | 10 | { |
| 11 | 11 | "type":"click", |
| 12 | 12 | "name":"今日歌曲", |
| 13 | - "key":"V1001_TODAY_MUSIC" | |
| 13 | + "menuKey":"V1001_TODAY_MUSIC" | |
| 14 | 14 | }, |
| 15 | 15 | { |
| 16 | 16 | "name":"搜索", |
| 17 | 17 | "type":"view", |
| 18 | - "url":"http://www.soso.com/" | |
| 18 | + "url":"https://www.soso.com/" | |
| 19 | 19 | }, |
| 20 | 20 | { |
| 21 | 21 | "name": "父按钮", |
| 22 | - "subButtons": [ | |
| 22 | + "children": [ | |
| 23 | 23 | { |
| 24 | 24 | "type":"click", |
| 25 | 25 | "name":"归去来兮", |
| 26 | - "key":"MUSIC" | |
| 26 | + "menuKey":"MUSIC" | |
| 27 | 27 | }, |
| 28 | 28 | { |
| 29 | 29 | "name":"不说", |
| ... | ... | @@ -33,6 +33,17 @@ tenant-id: {{adminTenentId}} |
| 33 | 33 | }] |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | +### 请求 /mp/menu/save 接口 => 成功(清空) | |
| 37 | +POST {{baseUrl}}/mp/menu/save | |
| 38 | +Content-Type: application/json | |
| 39 | +Authorization: Bearer {{token}} | |
| 40 | +tenant-id: {{adminTenentId}} | |
| 41 | + | |
| 42 | +{ | |
| 43 | + "accountId": "1", | |
| 44 | + "menus": [] | |
| 45 | +} | |
| 46 | + | |
| 36 | 47 | ### 请求 /mp/menu/list 接口 => 成功 |
| 37 | 48 | GET {{baseUrl}}/mp/menu/list?accountId=1 |
| 38 | 49 | Authorization: Bearer {{token}} | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.java
| ... | ... | @@ -15,7 +15,6 @@ import org.springframework.web.bind.annotation.*; |
| 15 | 15 | |
| 16 | 16 | import javax.annotation.Resource; |
| 17 | 17 | import javax.validation.Valid; |
| 18 | - | |
| 19 | 18 | import java.util.List; |
| 20 | 19 | |
| 21 | 20 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| ... | ... | @@ -32,28 +31,20 @@ public class MpMenuController { |
| 32 | 31 | @PostMapping("/save") |
| 33 | 32 | @ApiOperation("保存公众号菜单") |
| 34 | 33 | @PreAuthorize("@ss.hasPermission('mp:menu:save')") |
| 35 | - public CommonResult<Long> saveMenu(@Valid @RequestBody MpMenuSaveReqVO createReqVO) { | |
| 36 | - return success(mpMenuService.saveMenu(createReqVO)); | |
| 34 | + public CommonResult<Boolean> saveMenu(@Valid @RequestBody MpMenuSaveReqVO createReqVO) { | |
| 35 | + mpMenuService.saveMenu(createReqVO); | |
| 36 | + return success(true); | |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | @DeleteMapping("/delete") |
| 40 | 40 | @ApiOperation("删除公众号菜单") |
| 41 | - @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) | |
| 41 | + @ApiImplicitParam(name = "accountId", value = "公众号账号的编号", required = true, example = "10", dataTypeClass = Long.class) | |
| 42 | 42 | @PreAuthorize("@ss.hasPermission('mp:menu:delete')") |
| 43 | - public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) { | |
| 44 | - mpMenuService.deleteMenu(id); | |
| 43 | + public CommonResult<Boolean> deleteMenu(@RequestParam("accountId") Long accountId) { | |
| 44 | + mpMenuService.deleteMenuByAccountId(accountId); | |
| 45 | 45 | return success(true); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | - @GetMapping("/get") | |
| 49 | - @ApiOperation("获得公众号菜单") | |
| 50 | - @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) | |
| 51 | - @PreAuthorize("@ss.hasPermission('mp:menu:query')") | |
| 52 | - public CommonResult<MpMenuRespVO> getMenu(@RequestParam("id") Long id) { | |
| 53 | - MpMenuDO menu = mpMenuService.getMenu(id); | |
| 54 | - return success(MpMenuConvert.INSTANCE.convert(menu)); | |
| 55 | - } | |
| 56 | - | |
| 57 | 48 | @GetMapping("/list") |
| 58 | 49 | @ApiOperation("获得公众号菜单列表") |
| 59 | 50 | @ApiImplicitParam(name = "accountId", value = "公众号账号的编号", required = true, example = "10", dataTypeClass = Long.class) | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuBaseVO.java
| 1 | 1 | package cn.iocoder.yudao.module.mp.controller.admin.menu.vo; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; | |
| 4 | 3 | import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; |
| 5 | -import io.swagger.annotations.ApiModelProperty; | |
| 6 | 4 | import lombok.Data; |
| 7 | 5 | import me.chanjar.weixin.common.api.WxConsts; |
| 8 | 6 | |
| 9 | -import javax.validation.constraints.NotNull; | |
| 10 | 7 | import java.util.List; |
| 11 | 8 | |
| 12 | 9 | // TODO 芋艿:完善 swagger 注解 |
| ... | ... | @@ -17,17 +14,6 @@ import java.util.List; |
| 17 | 14 | @Data |
| 18 | 15 | public class MpMenuBaseVO { |
| 19 | 16 | |
| 20 | - @ApiModelProperty(value = "公众号账号的编号", required = true, example = "2048") | |
| 21 | - @NotNull(message = "公众号账号的编号不能为空") | |
| 22 | - private Long accountId; | |
| 23 | - | |
| 24 | - /** | |
| 25 | - * 微信公众号 appid | |
| 26 | - * | |
| 27 | - * 冗余 {@link MpAccountDO#getAppId()} | |
| 28 | - */ | |
| 29 | - private String appId; | |
| 30 | - | |
| 31 | 17 | /** |
| 32 | 18 | * 菜单名称 |
| 33 | 19 | */ |
| ... | ... | @@ -42,10 +28,6 @@ public class MpMenuBaseVO { |
| 42 | 28 | * 父菜单编号 |
| 43 | 29 | */ |
| 44 | 30 | private Long parentId; |
| 45 | - /** | |
| 46 | - * 排序 | |
| 47 | - */ | |
| 48 | - private Integer sort; | |
| 49 | 31 | |
| 50 | 32 | // ========== 按钮操作 ========== |
| 51 | 33 | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.mp.controller.admin.menu.vo; |
| 2 | 2 | |
| 3 | -import lombok.*; | |
| 3 | +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; | |
| 4 | +import io.swagger.annotations.ApiModel; | |
| 5 | +import io.swagger.annotations.ApiModelProperty; | |
| 6 | +import lombok.Data; | |
| 7 | +import lombok.EqualsAndHashCode; | |
| 8 | +import lombok.ToString; | |
| 4 | 9 | |
| 5 | -import java.util.*; | |
| 6 | - | |
| 7 | -import io.swagger.annotations.*; | |
| 10 | +import javax.validation.constraints.NotNull; | |
| 11 | +import java.util.Date; | |
| 8 | 12 | |
| 13 | +// TODO swagger 文档 | |
| 9 | 14 | @ApiModel("管理后台 - 微信菜单 Response VO") |
| 10 | 15 | @Data |
| 11 | 16 | @EqualsAndHashCode(callSuper = true) |
| ... | ... | @@ -15,6 +20,17 @@ public class MpMenuRespVO extends MpMenuBaseVO { |
| 15 | 20 | @ApiModelProperty(value = "主键", required = true) |
| 16 | 21 | private Long id; |
| 17 | 22 | |
| 23 | + @ApiModelProperty(value = "公众号账号的编号", required = true, example = "2048") | |
| 24 | + @NotNull(message = "公众号账号的编号不能为空") | |
| 25 | + private Long accountId; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 微信公众号 appid | |
| 29 | + * | |
| 30 | + * 冗余 {@link MpAccountDO#getAppId()} | |
| 31 | + */ | |
| 32 | + private String appId; | |
| 33 | + | |
| 18 | 34 | @ApiModelProperty(value = "创建时间", required = true) |
| 19 | 35 | private Date createTime; |
| 20 | 36 | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuSaveReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.mp.controller.admin.menu.vo; |
| 2 | 2 | |
| 3 | -import lombok.*; | |
| 4 | -import io.swagger.annotations.*; | |
| 5 | -import me.chanjar.weixin.common.bean.menu.WxMenuButton; | |
| 3 | +import io.swagger.annotations.ApiModel; | |
| 4 | +import io.swagger.annotations.ApiModelProperty; | |
| 5 | +import lombok.Data; | |
| 6 | 6 | |
| 7 | +import javax.validation.Valid; | |
| 8 | +import javax.validation.constraints.NotEmpty; | |
| 7 | 9 | import javax.validation.constraints.NotNull; |
| 8 | 10 | import java.util.List; |
| 9 | 11 | |
| 10 | -@ApiModel("管理后台 - 微信菜单保存 Request VO") | |
| 12 | +// TODO 芋艿:swagger 文档 | |
| 13 | +@ApiModel("管理后台 - 公众号菜单保存 Request VO") | |
| 11 | 14 | @Data |
| 12 | -@EqualsAndHashCode(callSuper = true) | |
| 13 | -@ToString(callSuper = true) | |
| 14 | -public class MpMenuSaveReqVO extends MpMenuBaseVO { | |
| 15 | +public class MpMenuSaveReqVO { | |
| 15 | 16 | |
| 16 | - @NotNull(message = "按钮不能为空") | |
| 17 | - private List<WxMenuButton> buttons; | |
| 17 | + @ApiModelProperty(value = "公众号账号的编号", required = true, example = "2048") | |
| 18 | + @NotNull(message = "公众号账号的编号不能为空") | |
| 19 | + private Long accountId; | |
| 20 | + | |
| 21 | + @NotEmpty(message = "菜单不能为空") | |
| 22 | + @Valid | |
| 23 | + private List<Menu> menus; | |
| 24 | + | |
| 25 | + @Data | |
| 26 | + public static class Menu extends MpMenuBaseVO { | |
| 27 | + | |
| 28 | + private List<Menu> children; | |
| 29 | + | |
| 30 | + } | |
| 18 | 31 | |
| 19 | 32 | } | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/menu/MpMenuConvert.java
| ... | ... | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuRespVO; |
| 4 | 4 | import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO; |
| 5 | 5 | import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; |
| 6 | 6 | import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; |
| 7 | +import me.chanjar.weixin.common.bean.menu.WxMenuButton; | |
| 7 | 8 | import org.mapstruct.Mapper; |
| 8 | 9 | import org.mapstruct.Mapping; |
| 9 | 10 | import org.mapstruct.Mappings; |
| ... | ... | @@ -16,8 +17,6 @@ public interface MpMenuConvert { |
| 16 | 17 | |
| 17 | 18 | MpMenuConvert INSTANCE = Mappers.getMapper(MpMenuConvert.class); |
| 18 | 19 | |
| 19 | - MpMenuDO convert(MpMenuSaveReqVO bean); | |
| 20 | - | |
| 21 | 20 | MpMenuRespVO convert(MpMenuDO bean); |
| 22 | 21 | |
| 23 | 22 | List<MpMenuRespVO> convertList(List<MpMenuDO> list); |
| ... | ... | @@ -27,11 +26,20 @@ public interface MpMenuConvert { |
| 27 | 26 | @Mapping(source = "menu.replyMessageType", target = "type"), |
| 28 | 27 | @Mapping(source = "menu.replyContent", target = "content"), |
| 29 | 28 | @Mapping(source = "menu.replyMediaId", target = "mediaId"), |
| 30 | - @Mapping(source = "menu.replyMediaUrl", target = "mediaUrl"), | |
| 31 | 29 | @Mapping(source = "menu.replyTitle", target = "title"), |
| 32 | 30 | @Mapping(source = "menu.replyDescription", target = "description"), |
| 33 | 31 | @Mapping(source = "menu.replyArticles", target = "articles"), |
| 34 | 32 | }) |
| 35 | 33 | MpMessageSendOutReqBO convert(String openid, MpMenuDO menu); |
| 36 | 34 | |
| 35 | + List<WxMenuButton> convert(List<MpMenuSaveReqVO.Menu> list); | |
| 36 | + | |
| 37 | + @Mappings({ | |
| 38 | + @Mapping(source = "menuKey", target = "key"), | |
| 39 | + @Mapping(source = "children", target = "subButtons"), | |
| 40 | + }) | |
| 41 | + WxMenuButton convert(MpMenuSaveReqVO.Menu bean); | |
| 42 | + | |
| 43 | + MpMenuDO convert02(MpMenuSaveReqVO.Menu menu); | |
| 44 | + | |
| 37 | 45 | } | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/menu/MpMenuDO.java
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/menu/MpMenuMapper.java
| 1 | 1 | package cn.iocoder.yudao.module.mp.dal.mysql.menu; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 4 | 5 | import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; |
| 5 | 6 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 7 | |
| ... | ... | @@ -18,4 +19,7 @@ public interface MpMenuMapper extends BaseMapperX<MpMenuDO> { |
| 18 | 19 | return selectList(MpMenuDO::getAccountId, accountId); |
| 19 | 20 | } |
| 20 | 21 | |
| 22 | + default void deleteByAccountId(Long accountId) { | |
| 23 | + delete(new LambdaQueryWrapperX<MpMenuDO>().eq(MpMenuDO::getAccountId, accountId)); | |
| 24 | + } | |
| 21 | 25 | } | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuService.java
| ... | ... | @@ -18,24 +18,15 @@ public interface MpMenuService { |
| 18 | 18 | * 保存公众号菜单 |
| 19 | 19 | * |
| 20 | 20 | * @param createReqVO 创建信息 |
| 21 | - * @return 编号 | |
| 22 | 21 | */ |
| 23 | - Long saveMenu(@Valid MpMenuSaveReqVO createReqVO); | |
| 22 | + void saveMenu(@Valid MpMenuSaveReqVO createReqVO); | |
| 24 | 23 | |
| 25 | 24 | /** |
| 26 | 25 | * 删除公众号菜单 |
| 27 | 26 | * |
| 28 | - * @param id 编号 | |
| 27 | + * @param accountId 公众号账号的编号 | |
| 29 | 28 | */ |
| 30 | - void deleteMenu(Long id); | |
| 31 | - | |
| 32 | - /** | |
| 33 | - * 获得公众号菜单 | |
| 34 | - * | |
| 35 | - * @param id 编号 | |
| 36 | - * @return 公众号菜单 | |
| 37 | - */ | |
| 38 | - MpMenuDO getMenu(Long id); | |
| 29 | + void deleteMenuByAccountId(Long accountId); | |
| 39 | 30 | |
| 40 | 31 | /** |
| 41 | 32 | * 用户点击菜单按钮时,回复对应的消息 |
| ... | ... | @@ -50,7 +41,7 @@ public interface MpMenuService { |
| 50 | 41 | /** |
| 51 | 42 | * 获得公众号菜单列表 |
| 52 | 43 | * |
| 53 | - * @param accountId 公众号编号 | |
| 44 | + * @param accountId 公众号账号的编号 | |
| 54 | 45 | * @return 公众号菜单列表 |
| 55 | 46 | */ |
| 56 | 47 | List<MpMenuDO> getMenuListByAccountId(Long accountId); | ... | ... |
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.mp.service.menu; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.hutool.core.util.StrUtil; |
| 4 | 5 | import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO; |
| 5 | 6 | import cn.iocoder.yudao.module.mp.convert.menu.MpMenuConvert; |
| 7 | +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; | |
| 6 | 8 | import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; |
| 7 | 9 | import cn.iocoder.yudao.module.mp.dal.mysql.menu.MpMenuMapper; |
| 8 | 10 | import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; |
| 11 | +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; | |
| 9 | 12 | import cn.iocoder.yudao.module.mp.service.message.MpMessageService; |
| 10 | 13 | import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; |
| 11 | 14 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -15,13 +18,15 @@ import me.chanjar.weixin.mp.api.WxMpService; |
| 15 | 18 | import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; |
| 16 | 19 | import org.springframework.context.annotation.Lazy; |
| 17 | 20 | import org.springframework.stereotype.Service; |
| 21 | +import org.springframework.transaction.annotation.Transactional; | |
| 18 | 22 | import org.springframework.validation.annotation.Validated; |
| 19 | 23 | |
| 20 | 24 | import javax.annotation.Resource; |
| 21 | 25 | import java.util.List; |
| 22 | 26 | |
| 23 | 27 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 24 | -import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MENU_NOT_EXISTS; | |
| 28 | +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MENU_DELETE_FAIL; | |
| 29 | +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MENU_SAVE_FAIL; | |
| 25 | 30 | |
| 26 | 31 | /** |
| 27 | 32 | * 公众号菜单 Service 实现类 |
| ... | ... | @@ -35,6 +40,9 @@ public class MpMenuServiceImpl implements MpMenuService { |
| 35 | 40 | |
| 36 | 41 | @Resource |
| 37 | 42 | private MpMessageService mpMessageService; |
| 43 | + @Resource | |
| 44 | + @Lazy // 延迟加载,避免循环引用报错 | |
| 45 | + private MpAccountService mpAccountService; | |
| 38 | 46 | |
| 39 | 47 | @Resource |
| 40 | 48 | @Lazy // 延迟加载,避免循环引用报错 |
| ... | ... | @@ -44,43 +52,64 @@ public class MpMenuServiceImpl implements MpMenuService { |
| 44 | 52 | private MpMenuMapper mpMenuMapper; |
| 45 | 53 | |
| 46 | 54 | @Override |
| 47 | - public Long saveMenu(MpMenuSaveReqVO createReqVO) { | |
| 48 | - String appId = "wx5b23ba7a5589ecbb"; | |
| 49 | - // 插入 | |
| 50 | - MpMenuDO menu = MpMenuConvert.INSTANCE.convert(createReqVO); | |
| 51 | -// mpMenuMapper.insert(menu); | |
| 52 | - | |
| 53 | - // TODO 同步菜单 | |
| 54 | - WxMpService mpService = mpServiceFactory.getRequiredMpService(appId); | |
| 55 | + @Transactional(rollbackFor = Exception.class) | |
| 56 | + public void saveMenu(MpMenuSaveReqVO createReqVO) { | |
| 57 | + MpAccountDO account = mpAccountService.getRequiredAccount(createReqVO.getAccountId()); | |
| 58 | + WxMpService mpService = mpServiceFactory.getRequiredMpService(createReqVO.getAccountId()); | |
| 59 | + | |
| 60 | + // 第一步,同步公众号 | |
| 55 | 61 | WxMenu wxMenu = new WxMenu(); |
| 56 | - wxMenu.setButtons(createReqVO.getButtons()); | |
| 62 | + wxMenu.setButtons(MpMenuConvert.INSTANCE.convert(createReqVO.getMenus())); | |
| 57 | 63 | try { |
| 58 | 64 | mpService.getMenuService().menuCreate(wxMenu); |
| 59 | 65 | } catch (WxErrorException e) { |
| 60 | - throw new RuntimeException(e); | |
| 66 | + throw exception(MENU_SAVE_FAIL, e.getError().getErrorMsg()); | |
| 61 | 67 | } |
| 62 | 68 | |
| 63 | - // 返回 | |
| 64 | - return menu.getId(); | |
| 69 | + // 第二步,存储到数据库 | |
| 70 | + mpMenuMapper.deleteByAccountId(createReqVO.getAccountId()); | |
| 71 | + createReqVO.getMenus().forEach(menu -> { | |
| 72 | + // 先保存顶级菜单 | |
| 73 | + MpMenuDO menuDO = createMenu(menu, null, account); | |
| 74 | + // 再保存子菜单 | |
| 75 | + if (CollUtil.isEmpty(menu.getChildren())) { | |
| 76 | + return; | |
| 77 | + } | |
| 78 | + menu.getChildren().forEach(childMenu -> createMenu(childMenu, menuDO, account)); | |
| 79 | + }); | |
| 65 | 80 | } |
| 66 | 81 | |
| 67 | 82 | @Override |
| 68 | - public void deleteMenu(Long id) { | |
| 69 | - // 校验存在 | |
| 70 | - validateMenuExists(id); | |
| 71 | - // 删除 | |
| 72 | - mpMenuMapper.deleteById(id); | |
| 73 | - } | |
| 74 | - | |
| 75 | - private void validateMenuExists(Long id) { | |
| 76 | - if (mpMenuMapper.selectById(id) == null) { | |
| 77 | - throw exception(MENU_NOT_EXISTS); | |
| 83 | + public void deleteMenuByAccountId(Long accountId) { | |
| 84 | + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); | |
| 85 | + // 第一步,同步公众号 | |
| 86 | + try { | |
| 87 | + mpService.getMenuService().menuDelete(); | |
| 88 | + } catch (WxErrorException e) { | |
| 89 | + throw exception(MENU_DELETE_FAIL, e.getError().getErrorMsg()); | |
| 78 | 90 | } |
| 91 | + | |
| 92 | + // 第二步,存储到数据库 | |
| 93 | + mpMenuMapper.deleteByAccountId(accountId); | |
| 79 | 94 | } |
| 80 | 95 | |
| 81 | - @Override | |
| 82 | - public MpMenuDO getMenu(Long id) { | |
| 83 | - return mpMenuMapper.selectById(id); | |
| 96 | + private MpMenuDO createMenu(MpMenuSaveReqVO.Menu wxMenu, MpMenuDO parentMenu, MpAccountDO account) { | |
| 97 | + MpMenuDO menu = CollUtil.isNotEmpty(wxMenu.getChildren()) | |
| 98 | + ? new MpMenuDO().setName(wxMenu.getName()) | |
| 99 | + : MpMenuConvert.INSTANCE.convert02(wxMenu); | |
| 100 | + if (account != null) { | |
| 101 | + menu.setAccountId(account.getId()).setAppId(account.getAppId()); | |
| 102 | + } | |
| 103 | + if (parentMenu != null) { | |
| 104 | + menu.setParentId(parentMenu.getId()); | |
| 105 | + } else { | |
| 106 | + menu.setParentId(MpMenuDO.ID_ROOT); | |
| 107 | + } | |
| 108 | + if (StrUtil.isNotEmpty(wxMenu.getReplyMediaId())) { | |
| 109 | + throw new IllegalArgumentException("未实现"); | |
| 110 | + } | |
| 111 | + mpMenuMapper.insert(menu); | |
| 112 | + return menu; | |
| 84 | 113 | } |
| 85 | 114 | |
| 86 | 115 | @Override | ... | ... |
yudao-ui-admin/src/api/mp/menu.js
| ... | ... | @@ -7,3 +7,23 @@ export function getMenuList(accountId) { |
| 7 | 7 | method: 'get', |
| 8 | 8 | }) |
| 9 | 9 | } |
| 10 | + | |
| 11 | +// 保存公众号菜单 | |
| 12 | +export function saveMenu(accountId, menus) { | |
| 13 | + return request({ | |
| 14 | + url: '/mp/menu/save', | |
| 15 | + method: 'post', | |
| 16 | + data: { | |
| 17 | + accountId, | |
| 18 | + menus | |
| 19 | + } | |
| 20 | + }) | |
| 21 | +} | |
| 22 | + | |
| 23 | +// 删除公众号菜单 | |
| 24 | +export function deleteMenu(accountId) { | |
| 25 | + return request({ | |
| 26 | + url: '/mp/menu/delete?accountId=' + accountId, | |
| 27 | + method: 'delete', | |
| 28 | + }) | |
| 29 | +} | ... | ... |
yudao-ui-admin/src/views/mp/menu/index.vue
| ... | ... | @@ -63,8 +63,8 @@ SOFTWARE. |
| 63 | 63 | <div class="menu_bottom menu_addicon" v-if="this.menuList.length < 3" @click="addMenu"><i class="el-icon-plus"></i></div> |
| 64 | 64 | </div> |
| 65 | 65 | <div class="save_div"> |
| 66 | - <!--<el-button class="save_btn" type="warning" size="small" @click="saveFun">保存菜单</el-button>--> | |
| 67 | - <el-button class="save_btn" type="success" size="small" @click="handleSaveAndReleaseFun">保存并发布菜单</el-button> | |
| 66 | + <el-button class="save_btn" type="success" size="small" @click="handleSave">保存并发布菜单</el-button> | |
| 67 | + <el-button class="save_btn" type="danger" size="small" @click="handleDelete">清空菜单</el-button> | |
| 68 | 68 | </div> |
| 69 | 69 | </div> |
| 70 | 70 | <!--右边配置--> |
| ... | ... | @@ -141,7 +141,7 @@ SOFTWARE. |
| 141 | 141 | import WxReplySelect from '@/views/mp/components/wx-news/main.vue' |
| 142 | 142 | import WxNews from '@/views/mp/components/wx-news/main.vue'; |
| 143 | 143 | import WxMaterialSelect from '@/views/mp/components/wx-news/main.vue' |
| 144 | -import { getMenuList } from "@/api/mp/menu"; | |
| 144 | +import {deleteMenu, getMenuList, saveMenu} from "@/api/mp/menu"; | |
| 145 | 145 | import { getSimpleAccounts } from "@/api/mp/account"; |
| 146 | 146 | |
| 147 | 147 | export default { |
| ... | ... | @@ -164,11 +164,6 @@ export default { |
| 164 | 164 | children: [], |
| 165 | 165 | }, |
| 166 | 166 | |
| 167 | - menu:{ // 横向菜单 | |
| 168 | - button:[ | |
| 169 | - ] | |
| 170 | - }, | |
| 171 | - | |
| 172 | 167 | // ======================== 菜单操作 ======================== |
| 173 | 168 | isActive: -1,// 一级菜单点中样式 |
| 174 | 169 | isSubMenuActive: -1, // 一级菜单点中样式 |
| ... | ... | @@ -178,7 +173,7 @@ export default { |
| 178 | 173 | showRightFlag: false, // 右边配置显示默认详情还是配置详情 |
| 179 | 174 | nameMaxLength: 0, // 菜单名称最大长度;1 级是 4 字符;2 级是 7 字符; |
| 180 | 175 | showConfigureContent: true, // 是否展示配置内容;如果有子菜单,就不显示配置内容 |
| 181 | - | |
| 176 | + hackResetWxReplySelect: false, // 重置 WxReplySelect 组件 | |
| 182 | 177 | |
| 183 | 178 | tempObj:{}, // 右边临时变量,作为中间值牵引关系 |
| 184 | 179 | tempSelfObj: { // 一些临时值放在这里进行判断,如果放在 tempObj,由于引用关系,menu 也会多了多余的参数 |
| ... | ... | @@ -218,7 +213,6 @@ export default { |
| 218 | 213 | label: '选择地理位置' |
| 219 | 214 | }], |
| 220 | 215 | dialogNewsVisible: false, |
| 221 | - hackResetWxReplySelect: false, | |
| 222 | 216 | |
| 223 | 217 | // 公众号账号列表 |
| 224 | 218 | accounts: [], |
| ... | ... | @@ -246,7 +240,6 @@ export default { |
| 246 | 240 | this.loading = false; |
| 247 | 241 | getMenuList(this.accountId).then(response => { |
| 248 | 242 | this.menuList = this.handleTree(response.data, "id"); |
| 249 | - console.log(this.menuList) | |
| 250 | 243 | }).finally(() => { |
| 251 | 244 | this.loading = false; |
| 252 | 245 | }) |
| ... | ... | @@ -354,31 +347,16 @@ export default { |
| 354 | 347 | }, |
| 355 | 348 | |
| 356 | 349 | // ======================== 菜单编辑 ======================== |
| 357 | - handleSaveAndReleaseFun(){ | |
| 358 | - this.$confirm('确定要保证并发布该菜单吗?', '提示', { | |
| 359 | - confirmButtonText: '确定', | |
| 360 | - cancelButtonText: '取消', | |
| 361 | - type: 'warning' | |
| 362 | - }).then(() => { | |
| 350 | + handleSave() { | |
| 351 | + this.$modal.confirm('确定要保证并发布该菜单吗?').then(() => { | |
| 363 | 352 | this.loading = true |
| 364 | - saveAndRelease({ | |
| 365 | - strWxMenu:this.menu | |
| 366 | - }).then(response => { | |
| 367 | - this.loading = false | |
| 368 | - if(response.code == 200){ | |
| 369 | - this.$message({ | |
| 370 | - showClose: true, | |
| 371 | - message: '发布成功', | |
| 372 | - type: 'success' | |
| 373 | - }) | |
| 374 | - }else{ | |
| 375 | - this.$message.error(response.data.msg) | |
| 376 | - } | |
| 377 | - }).catch(() => { | |
| 378 | - this.loading = false | |
| 379 | - }) | |
| 380 | - }).catch(() => { | |
| 381 | - }) | |
| 353 | + return saveMenu(this.accountId, this.menuList); | |
| 354 | + }).then(() => { | |
| 355 | + this.getList(); | |
| 356 | + this.$modal.msgSuccess("发布成功"); | |
| 357 | + }).catch(() => {}).finally(() => { | |
| 358 | + this.loading = false | |
| 359 | + }); | |
| 382 | 360 | }, |
| 383 | 361 | // 表单 Editor 重置 |
| 384 | 362 | resetEditor() { |
| ... | ... | @@ -387,6 +365,17 @@ export default { |
| 387 | 365 | this.hackResetEditor = true // 重建组件 |
| 388 | 366 | }) |
| 389 | 367 | }, |
| 368 | + handleDelete() { | |
| 369 | + this.$modal.confirm('确定要清空所有菜单吗?').then(() => { | |
| 370 | + this.loading = true | |
| 371 | + return deleteMenu(this.accountId); | |
| 372 | + }).then(() => { | |
| 373 | + this.getList(); | |
| 374 | + this.$modal.msgSuccess("清空成功"); | |
| 375 | + }).catch(() => {}).finally(() => { | |
| 376 | + this.loading = false | |
| 377 | + }); | |
| 378 | + }, | |
| 390 | 379 | |
| 391 | 380 | // TODO 芋艿:未归类 |
| 392 | 381 | |
| ... | ... | @@ -431,7 +420,7 @@ div{ |
| 431 | 420 | left:0px; |
| 432 | 421 | width: 300px; |
| 433 | 422 | height:64px; |
| 434 | - background: transparent url(assets/menu_head.png) no-repeat 0 0; | |
| 423 | + background: transparent url("assets/menu_head.png") no-repeat 0 0; | |
| 435 | 424 | background-position: 0 0; |
| 436 | 425 | background-size: 100% |
| 437 | 426 | } |
| ... | ... | @@ -445,7 +434,7 @@ div{ |
| 445 | 434 | left: 0px; |
| 446 | 435 | } |
| 447 | 436 | .weixin-menu{ |
| 448 | - background: transparent url(assets/menu_foot.png) no-repeat 0 0; | |
| 437 | + background: transparent url("assets/menu_foot.png") no-repeat 0 0; | |
| 449 | 438 | padding-left: 43px; |
| 450 | 439 | font-size: 12px |
| 451 | 440 | } |
| ... | ... | @@ -581,26 +570,26 @@ div{ |
| 581 | 570 | <!--</style>--> |
| 582 | 571 | <!--素材样式--> |
| 583 | 572 | <style lang="scss" scoped> |
| 584 | -.pagination{ | |
| 573 | +.pagination { | |
| 585 | 574 | text-align: right; |
| 586 | 575 | margin-right: 25px; |
| 587 | 576 | } |
| 588 | -.select-item{ | |
| 577 | +.select-item { | |
| 589 | 578 | width: 280px; |
| 590 | 579 | padding: 10px; |
| 591 | 580 | margin: 0 auto 10px auto; |
| 592 | 581 | border: 1px solid #eaeaea; |
| 593 | 582 | } |
| 594 | -.select-item2{ | |
| 583 | +.select-item2 { | |
| 595 | 584 | padding: 10px; |
| 596 | 585 | margin: 0 auto 10px auto; |
| 597 | 586 | border: 1px solid #eaeaea; |
| 598 | 587 | } |
| 599 | -.ope-row{ | |
| 588 | +.ope-row { | |
| 600 | 589 | padding-top: 10px; |
| 601 | 590 | text-align: center; |
| 602 | 591 | } |
| 603 | -.item-name{ | |
| 592 | +.item-name { | |
| 604 | 593 | font-size: 12px; |
| 605 | 594 | overflow: hidden; |
| 606 | 595 | text-overflow:ellipsis; | ... | ... |