Bläddra i källkod

mp:1)引入 less-loader,解决 menu 的 less 样式;2)接入菜单列表接口

YunaiV 2 år sedan
förälder
incheckning
02ec5d455c

+ 2 - 2
yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java

@@ -51,7 +51,7 @@ public interface ErrorCodeConstants {
     ErrorCode DRAFT_UPDATE_FAIL = new ErrorCode(1006007002, "更新草稿失败,原因:{}");
     ErrorCode DRAFT_DELETE_FAIL = new ErrorCode(1006007002, "删除草稿失败,原因:{}");
 
-    // TODO 要处理下
-    ErrorCode MENU_NOT_EXISTS = new ErrorCode(1006001002, "菜单不存在");
+    // ========== 公众号菜单 1006008000============
+    ErrorCode MENU_NOT_EXISTS = new ErrorCode(1006008000, "菜单不存在");
 
 }

+ 5 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.http

@@ -32,3 +32,8 @@ tenant-id: {{adminTenentId}}
         }]
     }]
 }
+
+### 请求 /mp/menu/list 接口 => 成功
+GET {{baseUrl}}/mp/menu/list?accountId=1
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}

+ 24 - 14
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.java

@@ -1,25 +1,26 @@
 package cn.iocoder.yudao.module.mp.controller.admin.menu;
 
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuRespVO;
+import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO;
 import cn.iocoder.yudao.module.mp.convert.menu.MpMenuConvert;
 import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO;
+import cn.iocoder.yudao.module.mp.service.menu.MpMenuService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import javax.validation.Valid;
 
-import org.springframework.validation.annotation.Validated;
-import org.springframework.security.access.prepost.PreAuthorize;
-import io.swagger.annotations.*;
-
-import javax.validation.*;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
-import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.*;
-import cn.iocoder.yudao.module.mp.service.menu.MpMenuService;
-
-@Api(tags = "管理后台 - 微信菜单")
+@Api(tags = "管理后台 - 公众号菜单")
 @RestController
 @RequestMapping("/mp/menu")
 @Validated
@@ -29,14 +30,14 @@ public class MpMenuController {
     private MpMenuService mpMenuService;
 
     @PostMapping("/save")
-    @ApiOperation("保存微信菜单")
+    @ApiOperation("保存公众号菜单")
     @PreAuthorize("@ss.hasPermission('mp:menu:save')")
     public CommonResult<Long> saveMenu(@Valid @RequestBody MpMenuSaveReqVO createReqVO) {
         return success(mpMenuService.saveMenu(createReqVO));
     }
 
     @DeleteMapping("/delete")
-    @ApiOperation("删除微信菜单")
+    @ApiOperation("删除公众号菜单")
     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
     @PreAuthorize("@ss.hasPermission('mp:menu:delete')")
     public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) {
@@ -45,7 +46,7 @@ public class MpMenuController {
     }
 
     @GetMapping("/get")
-    @ApiOperation("获得微信菜单")
+    @ApiOperation("获得公众号菜单")
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
     @PreAuthorize("@ss.hasPermission('mp:menu:query')")
     public CommonResult<MpMenuRespVO> getMenu(@RequestParam("id") Long id) {
@@ -53,4 +54,13 @@ public class MpMenuController {
         return success(MpMenuConvert.INSTANCE.convert(menu));
     }
 
+    @GetMapping("/list")
+    @ApiOperation("获得公众号菜单列表")
+    @ApiImplicitParam(name = "accountId", value = "公众号账号的编号", required = true, example = "10", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('mp:menu:query')")
+    public CommonResult<List<MpMenuRespVO>> getMenuList(@RequestParam("accountId") Long accountId) {
+        List<MpMenuDO> list = mpMenuService.getMenuListByAccountId(accountId);
+        return success(MpMenuConvert.INSTANCE.convertList(list));
+    }
+
 }

+ 113 - 2
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuBaseVO.java

@@ -1,12 +1,15 @@
 package cn.iocoder.yudao.module.mp.controller.admin.menu.vo;
 
+import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
+import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
 import io.swagger.annotations.ApiModelProperty;
-import lombok.*;
-import me.chanjar.weixin.common.bean.menu.WxMenuButton;
+import lombok.Data;
+import me.chanjar.weixin.common.api.WxConsts;
 
 import javax.validation.constraints.NotNull;
 import java.util.List;
 
+// TODO 芋艿:完善 swagger 注解
 /**
  * 微信菜单 Base VO,提供给添加、修改、详细的子 VO 使用
  * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
@@ -18,4 +21,112 @@ public class MpMenuBaseVO {
     @NotNull(message = "公众号账号的编号不能为空")
     private Long accountId;
 
+    /**
+     * 微信公众号 appid
+     *
+     * 冗余 {@link MpAccountDO#getAppId()}
+     */
+    private String appId;
+
+    /**
+     * 菜单名称
+     */
+    private String name;
+    /**
+     * 菜单标识
+     *
+     * 支持多 DB 类型时,无法直接使用 key + @TableField("menuKey") 来实现转换,原因是 "menuKey" AS key 而存在报错
+     */
+    private String menuKey;
+    /**
+     * 父菜单编号
+     */
+    private Long parentId;
+    /**
+     * 排序
+     */
+    private Integer sort;
+
+    // ========== 按钮操作 ==========
+
+    /**
+     * 按钮类型
+     *
+     * 枚举 {@link WxConsts.MenuButtonType}
+     */
+    private String type;
+
+    /**
+     * 网页链接
+     *
+     * 用户点击菜单可打开链接,不超过 1024 字节
+     *
+     * 类型为 {@link WxConsts.XmlMsgType} 的 VIEW、MINIPROGRAM
+     */
+    private String url;
+
+    /**
+     * 小程序的 appId
+     *
+     * 类型为 {@link WxConsts.MenuButtonType} 的 MINIPROGRAM
+     */
+    private String miniProgramAppId;
+    /**
+     * 小程序的页面路径
+     *
+     * 类型为 {@link WxConsts.MenuButtonType} 的 MINIPROGRAM
+     */
+    private String miniProgramPagePath;
+
+    // ========== 消息内容 ==========
+
+    /**
+     * 消息类型
+     *
+     * 当 {@link #type} 为 CLICK、SCANCODE_WAITMSG
+     *
+     * 枚举 {@link WxConsts.XmlMsgType} 中的 TEXT、IMAGE、VOICE、VIDEO、NEWS
+     */
+    private String replyMessageType;
+
+    /**
+     * 回复的消息内容
+     *
+     * 消息类型为 {@link WxConsts.XmlMsgType} 的 TEXT
+     */
+    private String replyContent;
+
+    /**
+     * 回复的媒体 id
+     *
+     * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO
+     */
+    private String replyMediaId;
+    /**
+     * 回复的媒体 URL
+     *
+     * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO
+     */
+    private String replyMediaUrl;
+
+    /**
+     * 回复的标题
+     *
+     * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO
+     */
+    private String replyTitle;
+    /**
+     * 回复的描述
+     *
+     * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO
+     */
+    private String replyDescription;
+
+    /**
+     * 回复的图文消息数组
+     *
+     * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS
+     */
+    private List<MpMessageDO.Article> replyArticles;
+
 }

+ 7 - 4
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/menu/MpMenuConvert.java

@@ -1,14 +1,15 @@
 package cn.iocoder.yudao.module.mp.convert.menu;
 
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-
+import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuRespVO;
+import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO;
+import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO;
 import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
 import org.mapstruct.factory.Mappers;
-import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.*;
-import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO;
+
+import java.util.List;
 
 @Mapper
 public interface MpMenuConvert {
@@ -19,6 +20,8 @@ public interface MpMenuConvert {
 
     MpMenuRespVO convert(MpMenuDO bean);
 
+    List<MpMenuRespVO> convertList(List<MpMenuDO> list);
+
     @Mappings({
             @Mapping(source = "menu.appId", target = "appId"),
             @Mapping(source = "menu.replyMessageType", target = "type"),

+ 6 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/menu/MpMenuMapper.java

@@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 @Mapper
 public interface MpMenuMapper extends BaseMapperX<MpMenuDO> {
 
@@ -12,4 +14,8 @@ public interface MpMenuMapper extends BaseMapperX<MpMenuDO> {
                 MpMenuDO::getMenuKey, menuKey);
     }
 
+    default List<MpMenuDO> selectListByAccountId(Long accountId) {
+        return selectList(MpMenuDO::getAccountId, accountId);
+    }
+
 }

+ 17 - 9
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuService.java

@@ -1,21 +1,21 @@
 package cn.iocoder.yudao.module.mp.service.menu;
 
-import javax.validation.*;
-
-import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.*;
+import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO;
-import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
 
+import javax.validation.Valid;
+import java.util.List;
+
 /**
- * 微信菜单 Service 接口
+ * 公众号菜单 Service 接口
  *
  * @author 芋道源码
  */
 public interface MpMenuService {
 
     /**
-     * 保存微信菜单
+     * 保存公众号菜单
      *
      * @param createReqVO 创建信息
      * @return 编号
@@ -23,17 +23,17 @@ public interface MpMenuService {
     Long saveMenu(@Valid MpMenuSaveReqVO createReqVO);
 
     /**
-     * 删除微信菜单
+     * 删除公众号菜单
      *
      * @param id 编号
      */
     void deleteMenu(Long id);
 
     /**
-     * 获得微信菜单
+     * 获得公众号菜单
      *
      * @param id 编号
-     * @return 微信菜单
+     * @return 公众号菜单
      */
     MpMenuDO getMenu(Long id);
 
@@ -47,4 +47,12 @@ public interface MpMenuService {
      */
     WxMpXmlOutMessage reply(String appId, String key, String openid);
 
+    /**
+     * 获得公众号菜单列表
+     *
+     * @param accountId 公众号编号
+     * @return 公众号菜单列表
+     */
+    List<MpMenuDO> getMenuListByAccountId(Long accountId);
+
 }

+ 11 - 9
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuServiceImpl.java

@@ -1,8 +1,10 @@
 package cn.iocoder.yudao.module.mp.service.menu;
 
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO;
 import cn.iocoder.yudao.module.mp.convert.menu.MpMenuConvert;
 import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO;
+import cn.iocoder.yudao.module.mp.dal.mysql.menu.MpMenuMapper;
 import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
 import cn.iocoder.yudao.module.mp.service.message.MpMessageService;
 import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO;
@@ -13,20 +15,16 @@ import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-
 import org.springframework.validation.annotation.Validated;
 
-import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.*;
-
-import cn.iocoder.yudao.module.mp.dal.mysql.menu.MpMenuMapper;
+import javax.annotation.Resource;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MENU_NOT_EXISTS;
 
 /**
- * 微信菜单 Service 实现类
+ * 公众号菜单 Service 实现类
  *
  * @author 芋道源码
  */
@@ -76,7 +74,6 @@ public class MpMenuServiceImpl implements MpMenuService {
 
     private void validateMenuExists(Long id) {
         if (mpMenuMapper.selectById(id) == null) {
-            // TODO 芋艿:错误码不太对
             throw exception(MENU_NOT_EXISTS);
         }
     }
@@ -105,4 +102,9 @@ public class MpMenuServiceImpl implements MpMenuService {
         return mpMessageService.sendOutMessage(sendReqBO);
     }
 
+    @Override
+    public List<MpMenuDO> getMenuListByAccountId(Long accountId) {
+        return mpMenuMapper.selectListByAccountId(accountId);
+    }
+
 }

+ 2 - 0
yudao-ui-admin/package.json

@@ -90,6 +90,8 @@
     "eslint-plugin-prettier": "^3.1.0",
     "eslint-plugin-vue": "9.0.0",
     "fs-extra": "^8.1.0",
+    "less": "^4.1.3",
+    "less-loader": "^7.3.0",
     "lint-staged": "12.5.0",
     "runjs": "4.4.2",
     "sass": "1.32.13",

+ 9 - 0
yudao-ui-admin/src/api/mp/menu.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 获得公众号菜单列表
+export function getMenuList(accountId) {
+  return request({
+    url: '/mp/menu/list?accountId=' + accountId,
+    method: 'get',
+  })
+}

+ 525 - 464
yudao-ui-admin/src/views/mp/menu/index.vue

@@ -23,344 +23,405 @@ SOFTWARE.
 -->
 <template>
   <div class="app-container">
-        <div class="public-account-management clearfix" v-loading="saveLoading">
-                        <!--左边配置菜单-->
-                        <div class="left">
-                            <div class="weixin-hd">
-                                <div class="weixin-title">
-                                    {{menuName}}
-                                </div>
-                            </div>
-                            <div class="weixin-menu menu_main clearfix">
-                                <div class="menu_bottom" v-for="(item, i) of menu.button" :key="i" >
-                                    <!-- 一级菜单 -->
-                                    <div @click="menuFun(i,item)" class="menu_item el-icon-s-fold" :class="{'active': isActive == i}">{{item.name}}</div>
-                                    <!--以下为二级菜单-->
-                                    <div class="submenu" v-if="isSubMenuFlag == i">
-                                        <div class="subtitle menu_bottom" v-if="item.sub_button" v-for="(subItem, k) in item.sub_button" :key="k">
-                                            <div class="menu_subItem" :class="{'active': isSubMenuActive == i + '' +k}" @click="subMenuFun(subItem, i, k)">{{subItem.name}}</div>
-                                        </div>
-                                        <!--  二级菜单加号, 当长度 小于  5 才显示二级菜单的加号  -->
-                                        <div class="menu_bottom menu_addicon" v-if="!item.sub_button || item.sub_button.length < 5" @click="addSubMenu(i,item)"><i class="el-icon-plus"></i></div>
-                                    </div>
-                                </div>
-                                <!-- 一级菜单加号 -->
-                                <div class="menu_bottom menu_addicon" v-if="menuKeyLength < 3" @click="addMenu"><i class="el-icon-plus"></i></div>
-                            </div>
-                            <div class="save_div">
-                                <!--<el-button class="save_btn" type="warning" size="small" @click="saveFun">保存菜单</el-button>-->
-                                <el-button class="save_btn" type="success" size="small" @click="saveAndReleaseFun">保存并发布菜单</el-button>
-                            </div>
-                        </div>
-                        <!--右边配置-->
-                        <div v-if="showRightFlag" class="right">
-                            <div class="configure_page">
-                                <div class="delete_btn">
-                                    <el-button size="mini"  type="danger" icon="el-icon-delete" @click="deleteMenu(tempObj)">删除当前菜单</el-button>
-                                </div>
-                                <div>
-                                    <span>菜单名称:</span>
-                                    <el-input class="input_width" v-model="tempObj.name" placeholder="请输入菜单名称" :maxlength=nameMaxlength clearable></el-input>
-                                </div>
-                                <div v-if="showConfigurContent">
-                                    <div class="menu_content">
-                                        <span>菜单内容:</span>
-                                        <el-select v-model="tempObj.type" clearable placeholder="请选择" class="menu_option">
-                                            <el-option v-for="item in menuOptions" :label="item.label" :value="item.value" :key="item.value"></el-option>
-                                        </el-select>
-                                    </div>
-                                    <div class="configur_content" v-if="tempObj.type == 'view'">
-                                        <span>跳转链接:</span>
-                                        <el-input class="input_width"  v-model="tempObj.url" placeholder="请输入链接" clearable></el-input>
-                                    </div>
-                                    <div class="configur_content" v-if="tempObj.type == 'miniprogram'">
-                                        <div class="applet">
-                                            <span>小程序的appid:</span>
-                                            <el-input class="input_width" v-model="tempObj.appid" placeholder="请输入小程序的appid" clearable></el-input>
-                                        </div>
-                                        <div class="applet">
-                                            <span>小程序的页面路径:</span>
-                                            <el-input class="input_width" v-model="tempObj.pagepath" placeholder="请输入小程序的页面路径,如:pages/index" clearable></el-input>
-                                        </div>
-                                        <div class="applet">
-                                            <span>备用网页:</span>
-                                            <el-input class="input_width" v-model="tempObj.url" placeholder="不支持小程序的老版本客户端将打开本网页" clearable></el-input>
-                                        </div>
-                                        <p class="blue">tips:需要和公众号进行关联才可以把小程序绑定带微信菜单上哟!</p>
-                                    </div>
-                                    <div class="configur_content" v-if="tempObj.type == 'article_view_limited'">
-                                        <el-row>
-                                            <div class="select-item" v-if="tempObj && tempObj.content && tempObj.content.articles">
-                                                <WxNews :objData="tempObj.content.articles"></WxNews>
-                                                <el-row class="ope-row">
-                                                    <el-button type="danger" icon="el-icon-delete" circle @click="deleteTempObj"></el-button>
-                                                </el-row>
-                                            </div>
-                                            <div v-if="!tempObj.content || !tempObj.content.articles">
-                                                <el-row>
-                                                    <el-col :span="24" style="text-align: center">
-                                                        <el-button type="success" @click="openMaterial">素材库选择<i class="el-icon-circle-check el-icon--right"></i></el-button>
-                                                    </el-col>
-                                                </el-row>
-                                            </div>
-                                            <el-dialog title="选择图文" :visible.sync="dialogNewsVisible" width="90%">
-                                                <WxMaterialSelect :objData="{repType:'news'}" @selectMaterial="selectMaterial"></WxMaterialSelect>
-                                            </el-dialog>
-                                        </el-row>
-                                    </div>
-                                    <div class="configur_content" v-if="tempObj.type == 'click' || tempObj.type == 'scancode_waitmsg'">
-                                        <WxReplySelect :objData="tempObj" v-if="hackResetWxReplySelect"></WxReplySelect>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                        <!--一进页面就显示的默认页面,当点击左边按钮的时候,就不显示了-->
-                        <div v-if="!showRightFlag" class="right">
-                            <p>请选择菜单配置</p>
-                        </div>
-                    </div>
+    <!-- 搜索工作栏 -->
+    <el-form ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="公众号" prop="accountId">
+        <el-select v-model="accountId" placeholder="请选择公众号">
+          <el-option v-for="item in accounts" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <div class="public-account-management clearfix" v-loading="loading">
+      <!--左边配置菜单-->
+      <div class="left">
+        <div class="weixin-hd">
+            <div class="weixin-title">{{menuName}}</div>
+        </div>
+        <div class="weixin-menu menu_main clearfix">
+          <div class="menu_bottom" v-for="(item, i) of menuList" :key="i" >
+            <!-- 一级菜单 -->
+            <div @click="menuClick(i, item)" class="menu_item el-icon-s-fold" :class="{'active': isActive === i}">{{item.name}}</div>
+            <!-- 以下为二级菜单-->
+            <div class="submenu" v-if="isSubMenuFlag === i">
+              <div class="subtitle menu_bottom" v-if="item.children" v-for="(subItem, k) in item.children" :key="k">
+                <div class="menu_subItem" :class="{'active': isSubMenuActive === i + '' + k}" @click="subMenuClick(subItem, i, k)">
+                  {{subItem.name}}
+                </div>
+              </div>
+              <!-- 二级菜单加号, 当长度 小于 5 才显示二级菜单的加号  -->
+              <div class="menu_bottom menu_addicon" v-if="!item.children || item.children.length < 5" @click="addSubMenu(i,item)">
+                <i class="el-icon-plus" />
+              </div>
+            </div>
+          </div>
+          <!-- 一级菜单加号 -->
+          <div class="menu_bottom menu_addicon" v-if="menuKeyLength < 3" @click="addMenu"><i class="el-icon-plus"></i></div>
+        </div>
+        <div class="save_div">
+            <!--<el-button class="save_btn" type="warning" size="small" @click="saveFun">保存菜单</el-button>-->
+            <el-button class="save_btn" type="success" size="small" @click="saveAndReleaseFun">保存并发布菜单</el-button>
+        </div>
+      </div>
+      <!--右边配置-->
+      <div v-if="showRightFlag" class="right">
+          <div class="configure_page">
+              <div class="delete_btn">
+                  <el-button size="mini"  type="danger" icon="el-icon-delete" @click="deleteMenu(tempObj)">删除当前菜单</el-button>
+              </div>
+              <div>
+                  <span>菜单名称:</span>
+                  <el-input class="input_width" v-model="tempObj.name" placeholder="请输入菜单名称" :maxlength=nameMaxlength clearable></el-input>
+              </div>
+              <div v-if="showConfigurContent">
+                  <div class="menu_content">
+                      <span>菜单内容:</span>
+                      <el-select v-model="tempObj.type" clearable placeholder="请选择" class="menu_option">
+                          <el-option v-for="item in menuOptions" :label="item.label" :value="item.value" :key="item.value"></el-option>
+                      </el-select>
+                  </div>
+                  <div class="configur_content" v-if="tempObj.type === 'view'">
+                      <span>跳转链接:</span>
+                      <el-input class="input_width"  v-model="tempObj.url" placeholder="请输入链接" clearable></el-input>
+                  </div>
+                  <div class="configur_content" v-if="tempObj.type === 'miniprogram'">
+                      <div class="applet">
+                          <span>小程序的appid:</span>
+                          <el-input class="input_width" v-model="tempObj.appid" placeholder="请输入小程序的appid" clearable></el-input>
+                      </div>
+                      <div class="applet">
+                          <span>小程序的页面路径:</span>
+                          <el-input class="input_width" v-model="tempObj.pagepath" placeholder="请输入小程序的页面路径,如:pages/index" clearable></el-input>
+                      </div>
+                      <div class="applet">
+                          <span>备用网页:</span>
+                          <el-input class="input_width" v-model="tempObj.url" placeholder="不支持小程序的老版本客户端将打开本网页" clearable></el-input>
+                      </div>
+                      <p class="blue">tips:需要和公众号进行关联才可以把小程序绑定带微信菜单上哟!</p>
+                  </div>
+                  <div class="configur_content" v-if="tempObj.type == 'article_view_limited'">
+                      <el-row>
+                          <div class="select-item" v-if="tempObj && tempObj.content && tempObj.content.articles">
+                              <WxNews :objData="tempObj.content.articles"></WxNews>
+                              <el-row class="ope-row">
+                                  <el-button type="danger" icon="el-icon-delete" circle @click="deleteTempObj"></el-button>
+                              </el-row>
+                          </div>
+                          <div v-if="!tempObj.content || !tempObj.content.articles">
+                              <el-row>
+                                  <el-col :span="24" style="text-align: center">
+                                      <el-button type="success" @click="openMaterial">素材库选择<i class="el-icon-circle-check el-icon--right"></i></el-button>
+                                  </el-col>
+                              </el-row>
+                          </div>
+                          <el-dialog title="选择图文" :visible.sync="dialogNewsVisible" width="90%">
+                              <WxMaterialSelect :objData="{repType:'news'}" @selectMaterial="selectMaterial"></WxMaterialSelect>
+                          </el-dialog>
+                      </el-row>
+                  </div>
+                  <div class="configur_content" v-if="tempObj.type == 'click' || tempObj.type == 'scancode_waitmsg'">
+                      <WxReplySelect :objData="tempObj" v-if="hackResetWxReplySelect"></WxReplySelect>
+                  </div>
+              </div>
+          </div>
+      </div>
+      <!--一进页面就显示的默认页面,当点击左边按钮的时候,就不显示了-->
+      <div v-if="!showRightFlag" class="right">
+          <p>请选择菜单配置</p>
+      </div>
     </div>
+  </div>
 </template>
 
 <script>
-    // import { save, saveAndRelease ,getList} from '@/api/wxmp/wxmenu'
-    import WxReplySelect from '@/views/mp/components/wx-news/main.vue'
-    import WxNews from '@/views/mp/components/wx-news/main.vue';
-    import WxMaterialSelect from '@/views/mp/components/wx-news/main.vue'
+// import { save, saveAndRelease ,getList} from '@/api/wxmp/wxmenu'
+import WxReplySelect from '@/views/mp/components/wx-news/main.vue'
+import WxNews from '@/views/mp/components/wx-news/main.vue';
+import WxMaterialSelect from '@/views/mp/components/wx-news/main.vue'
+import {getMenuList} from "@/api/mp/menu";
+import {getSimpleAccounts} from "@/api/mp/account";
 
-    export default {
-        name: 'mpMenu',
-        components: {
-            WxReplySelect,
-            WxNews,
-            WxMaterialSelect
-        },
-        data(){
-            return{
-                showRightFlag:false,//右边配置显示默认详情还是配置详情
-                menu:{
-                    button:[
-                    ]
-                },//横向菜单
-                isActive: -1,// 一级菜单点中样式
-                isSubMenuActive: -1,// 一级菜单点中样式
-                isSubMenuFlag: -1,// 二级菜单显示标志
-                tempObj:{},//右边临时变量,作为中间值牵引关系
-                tempSelfObj:{
-                    //一些临时值放在这里进行判断,如果放在tempObj,由于引用关系,menu也会多了多余的参数
-                },
-                visible2: false,//素材内容  "选择素材"按钮弹框显示隐藏
-                tableData:[], //素材内容弹框数据,
-                menuName:'',
-                showConfigurContent:true,
-                nameMaxlength:0,//名称最大长度
-                menuOptions: [{
-                    value: 'view',
-                    label: '跳转网页'
-                }, {
-                    value: 'miniprogram',
-                    label: '跳转小程序'
-                }, {
-                    value: 'click',
-                    label: '点击回复'
-                }, {
-                    value: 'article_view_limited',
-                    label: '跳转图文消息'
-                }, {
-                    value: 'scancode_push',
-                    label: '扫码直接返回结果'
-                }, {
-                    value: 'scancode_waitmsg',
-                    label: '扫码回复'
-                }, {
-                    value: 'pic_sysphoto',
-                    label: '系统拍照发图'
-                }, {
-                    value: 'pic_photo_or_album',
-                    label: '拍照或者相册'
-                }, {
-                    value: 'pic_weixin',
-                    label: '微信相册'
-                }, {
-                    value: 'location_select',
-                    label: '选择地理位置'
-                }],
-                dialogNewsVisible:false,
-                saveLoading:false,
-                hackResetWxReplySelect:false
-            }
-        },
-        created() {
-            this.getMenuFun()
-        },
-        mounted() {
+export default {
+  name: 'mpMenu',
+  components: {
+      WxReplySelect,
+      WxNews,
+      WxMaterialSelect
+  },
+  data(){
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 查询参数
+      accountId: undefined,
+      menuList: {
+        children: [],
+      },
 
-        },
-        filters:{
-        },
-        computed: {
-        },
-        methods:{
-            deleteTempObj(){
-                this.$delete(this.tempObj,'repName')
-                this.$delete(this.tempObj,'repUrl')
-                this.$delete(this.tempObj,'content')
-            },
-            openMaterial(){
-                this.dialogNewsVisible = true
-            },
-            selectMaterial(item){
-                if(item.content.articles.length>1){
-                    this.$alert('您选择的是多图文,将默认跳转第一篇', '提示', {
-                        confirmButtonText: '确定'
-                    })
-                }
-                this.dialogNewsVisible = false
-                this.tempObj.article_id = item.articleId
-                this.tempObj.mediaName = item.name
-                this.tempObj.url = item.url
-                item.mediaType = this.tempObj.mediaType
-                item.content.articles = item.content.articles.slice(0,1)
-                this.tempObj.content = item.content
-            },
-            getMenuFun(){
-                getList().then((res)=>{
-                    this.menu.button = JSON.parse(res.msg).button;
-                });
-            },
-            handleClick(tab, event){
-                this.tempObj.mediaType = tab.name
-            },
-            saveAndReleaseFun(){
-                this.$confirm('确定要保证并发布该菜单吗?', '提示', {
-                    confirmButtonText: '确定',
-                    cancelButtonText: '取消',
-                    type: 'warning'
-                }).then(() => {
-                    this.saveLoading = true
-                    saveAndRelease({
-                        strWxMenu:this.menu
-                    }).then(response => {
-                        this.saveLoading = false
-                        if(response.code == 200){
-                            this.$message({
-                                showClose: true,
-                                message: '发布成功',
-                                type: 'success'
-                            })
-                        }else{
-                            this.$message.error(response.data.msg)
-                        }
-                    }).catch(() => {
-                        this.saveLoading = false
+      showRightFlag:false, // 右边配置显示默认详情还是配置详情
+      menu:{ // 横向菜单
+          button:[
+          ]
+      },
+
+      isActive: -1,// 一级菜单点中样式
+      isSubMenuActive: -1, // 一级菜单点中样式
+      isSubMenuFlag: -1, // 二级菜单显示标志
+      tempObj:{}, // 右边临时变量,作为中间值牵引关系
+      tempSelfObj: {
+          // 一些临时值放在这里进行判断,如果放在 tempObj,由于引用关系,menu 也会多了多余的参数
+      },
+      visible2: false, //素材内容  "选择素材"按钮弹框显示隐藏
+      tableData:[], //素材内容弹框数据,
+      menuName:'',
+      showConfigurContent:true,
+      nameMaxlength:0,//名称最大长度
+      menuOptions: [{
+          value: 'view',
+          label: '跳转网页'
+      }, {
+          value: 'miniprogram',
+          label: '跳转小程序'
+      }, {
+          value: 'click',
+          label: '点击回复'
+      }, {
+          value: 'article_view_limited',
+          label: '跳转图文消息'
+      }, {
+          value: 'scancode_push',
+          label: '扫码直接返回结果'
+      }, {
+          value: 'scancode_waitmsg',
+          label: '扫码回复'
+      }, {
+          value: 'pic_sysphoto',
+          label: '系统拍照发图'
+      }, {
+          value: 'pic_photo_or_album',
+          label: '拍照或者相册'
+      }, {
+          value: 'pic_weixin',
+          label: '微信相册'
+      }, {
+          value: 'location_select',
+          label: '选择地理位置'
+      }],
+      dialogNewsVisible: false,
+      hackResetWxReplySelect: false,
+
+      // 公众号账号列表
+      accounts: [],
+    }
+  },
+  created() {
+    getSimpleAccounts().then(response => {
+      this.accounts = response.data;
+      // 默认选中第一个
+      if (this.accounts.length > 0) {
+        this.setAccountId(this.accounts[0].id);
+      }
+      // 加载数据
+      this.getList();
+    })
+  },
+  computed: {
+    menuKeyLength:function() {
+      // menuObj 的长度,当长度小于 3 才显示一级菜单的加号
+      return this.menu.button.length;
+    }
+  },
+  methods: {
+    // ======================== 列表查询 ========================
+    /** 设置账号编号 */
+    setAccountId(accountId) {
+      this.accountId = accountId;
+      // this.uploadData.accountId = accountId;
+    },
+    getList() {
+      this.loading = false;
+      getMenuList(this.accountId).then(response => {
+        this.menuList = this.handleTree(response.data, "id");
+        console.log(this.menuList)
+      }).finally(() => {
+        this.loading = false;
+      })
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      // 默认选中第一个
+      if (this.accountId) {
+        this.setAccountId(this.accountId)
+      }
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm('queryForm')
+      // 默认选中第一个
+      if (this.accounts.length > 0) {
+        this.setAccountId(this.accounts[0].id)
+      }
+      this.handleQuery()
+    },
+
+    // TODO 芋艿:未归类
+
+    deleteTempObj(){
+        this.$delete(this.tempObj,'repName')
+        this.$delete(this.tempObj,'repUrl')
+        this.$delete(this.tempObj,'content')
+    },
+    openMaterial(){
+        this.dialogNewsVisible = true
+    },
+    selectMaterial(item){
+        if(item.content.articles.length>1){
+            this.$alert('您选择的是多图文,将默认跳转第一篇', '提示', {
+                confirmButtonText: '确定'
+            })
+        }
+        this.dialogNewsVisible = false
+        this.tempObj.article_id = item.articleId
+        this.tempObj.mediaName = item.name
+        this.tempObj.url = item.url
+        item.mediaType = this.tempObj.mediaType
+        item.content.articles = item.content.articles.slice(0,1)
+        this.tempObj.content = item.content
+    },
+    handleClick(tab, event){
+        this.tempObj.mediaType = tab.name
+    },
+    saveAndReleaseFun(){
+        this.$confirm('确定要保证并发布该菜单吗?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+        }).then(() => {
+            this.loading = true
+            saveAndRelease({
+                strWxMenu:this.menu
+            }).then(response => {
+                this.loading = false
+                if(response.code == 200){
+                    this.$message({
+                        showClose: true,
+                        message: '发布成功',
+                        type: 'success'
                     })
-                }).catch(() => {
-                })
-            },
-            // 一级菜单点击事件
-            menuFun(i, item){
-                this.hackResetWxReplySelect = false//销毁组件
-                this.$nextTick(() => {
-                    this.hackResetWxReplySelect = true//重建组件
-                })
-                this.showRightFlag = true;//右边菜单
-                this.tempObj = item;//这个如果放在顶部,flag会没有。因为重新赋值了。
-                this.tempSelfObj.grand = "1";//表示一级菜单
-                this.tempSelfObj.index = i;//表示一级菜单索引
-                this.isActive = i; //一级菜单选中样式
-                this.isSubMenuFlag = i; //二级菜单显示标志
-                this.isSubMenuActive = -1; //二级菜单去除选中样式
-                this.nameMaxlength = 4
-                if(item.sub_button&&item.sub_button.length>0){
-                    this.showConfigurContent = false
                 }else{
-                    this.showConfigurContent = true
-                }
-            },
-            // 二级菜单点击事件
-            subMenuFun(subItem, index, k){
-                this.hackResetWxReplySelect = false//销毁组件
-                this.$nextTick(() => {
-                    this.hackResetWxReplySelect = true//重建组件
-                })
-                this.showRightFlag = true;//右边菜单
-                this.tempObj = subItem;//将点击的数据放到临时变量,对象有引用作用
-                this.tempSelfObj.grand = "2";//表示二级菜单
-                this.tempSelfObj.index = index;//表示一级菜单索引
-                this.tempSelfObj.secondIndex = k;//表示二级菜单索引
-                this.isSubMenuActive = index + "" + k; //二级菜单选中样式
-                this.isActive = -1;//一级菜单去除样式
-                this.showConfigurContent = true;
-                this.nameMaxlength = 7
-            },
-            // 添加横向一级菜单
-            addMenu(){
-                let menuKeyLength = this.menuKeyLength
-                let addButton = {
-                    name: "菜单名称",
-                    sub_button: []
-                }
-                this.$set(this.menu.button,menuKeyLength,addButton)
-                this.menuFun(this.menuKeyLength-1, addButton)
-            },
-            // 添加横向二级菜单
-            addSubMenu(i,item){
-                if(!item.sub_button||item.sub_button.length<=0){
-                    this.$set( item, 'sub_button',[])
-                    this.$delete( item, 'type')
-                    this.$delete( item, 'pagepath')
-                    this.$delete( item, 'url')
-                    this.$delete( item, 'key')
-                    this.$delete( item, 'article_id')
-                    this.$delete( item, 'textContent')
-                    this.showConfigurContent = false
-                }
-                let subMenuKeyLength = item.sub_button.length;//获取二级菜单key长度
-                let addButton = {
-                    name: "子菜单名称"
+                    this.$message.error(response.data.msg)
                 }
-                this.$set(item.sub_button,subMenuKeyLength,addButton);
-                this.subMenuFun(item.sub_button[subMenuKeyLength], i, subMenuKeyLength)
-            },
-            //删除当前菜单
-            deleteMenu(obj){
-                let _this = this;
-                this.$confirm('确定要删除吗?', '提示', {
-                    confirmButtonText: '确定',
-                    cancelButtonText: '取消',
-                    type: 'warning'
-                }).then(() => {
-                    _this.deleteData();// 删除菜单数据
-                    _this.tempObj = {};
-                    _this.showRightFlag = false;
-                    this.isActive = -1;
-                    this.isSubMenuActive = -1;
-                }).catch(() => {
-                });
-            },
-            // 删除菜单数据
-            deleteData(){
-                // 一级菜单的删除方法
-                if(this.tempSelfObj.grand == "1"){
-                    this.menu.button.splice(this.tempSelfObj.index,1);
-                }
-                // 二级菜单的删除方法
-                if(this.tempSelfObj.grand == "2"){
-                    this.menu.button[this.tempSelfObj.index].sub_button.splice(this.tempSelfObj.secondIndex, 1);
-                }
-                this.$message({
-                    type: 'success',
-                    message: '删除成功!'
-                });
-            }
-        },
-        computed:{
-            // menuObj的长度,当长度 小于  3 才显示一级菜单的加号
-            menuKeyLength:function(){
-                return this.menu.button.length;
-            }
+            }).catch(() => {
+                this.loading = false
+            })
+        }).catch(() => {
+        })
+    },
+    // 一级菜单点击事件
+    menuClick(i, item){
+        this.hackResetWxReplySelect = false//销毁组件
+        this.$nextTick(() => {
+            this.hackResetWxReplySelect = true//重建组件
+        })
+        this.showRightFlag = true;//右边菜单
+        this.tempObj = item;//这个如果放在顶部,flag会没有。因为重新赋值了。
+        this.tempSelfObj.grand = "1";//表示一级菜单
+        this.tempSelfObj.index = i;//表示一级菜单索引
+        this.isActive = i; //一级菜单选中样式
+        this.isSubMenuFlag = i; //二级菜单显示标志
+        this.isSubMenuActive = -1; //二级菜单去除选中样式
+        this.nameMaxlength = 4
+        if(item.sub_button && item.sub_button.length > 0){
+            this.showConfigurContent = false
+        }else{
+            this.showConfigurContent = true
+        }
+    },
+    // 二级菜单点击事件
+    subMenuClick(subItem, index, k){
+        this.hackResetWxReplySelect = false//销毁组件
+        this.$nextTick(() => {
+            this.hackResetWxReplySelect = true//重建组件
+        })
+        this.showRightFlag = true;//右边菜单
+        this.tempObj = subItem;//将点击的数据放到临时变量,对象有引用作用
+        this.tempSelfObj.grand = "2";//表示二级菜单
+        this.tempSelfObj.index = index;//表示一级菜单索引
+        this.tempSelfObj.secondIndex = k;//表示二级菜单索引
+        this.isSubMenuActive = index + "" + k; //二级菜单选中样式
+        this.isActive = -1;//一级菜单去除样式
+        this.showConfigurContent = true;
+        this.nameMaxlength = 7
+    },
+    // 添加横向一级菜单
+    addMenu(){
+        let menuKeyLength = this.menuKeyLength
+        let addButton = {
+            name: "菜单名称",
+            sub_button: []
+        }
+        this.$set(this.menu.button,menuKeyLength,addButton)
+        this.menuClick(this.menuKeyLength-1, addButton)
+    },
+    // 添加横向二级菜单
+    addSubMenu(i,item){
+        if(!item.sub_button||item.sub_button.length<=0){
+            this.$set( item, 'sub_button',[])
+            this.$delete( item, 'type')
+            this.$delete( item, 'pagepath')
+            this.$delete( item, 'url')
+            this.$delete( item, 'key')
+            this.$delete( item, 'article_id')
+            this.$delete( item, 'textContent')
+            this.showConfigurContent = false
         }
+        let subMenuKeyLength = item.sub_button.length;//获取二级菜单key长度
+        let addButton = {
+            name: "子菜单名称"
+        }
+        this.$set(item.sub_button,subMenuKeyLength,addButton);
+        this.subMenuClick(item.sub_button[subMenuKeyLength], i, subMenuKeyLength)
+    },
+    //删除当前菜单
+    deleteMenu(obj){
+        let _this = this;
+        this.$confirm('确定要删除吗?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+        }).then(() => {
+            _this.deleteData();// 删除菜单数据
+            _this.tempObj = {};
+            _this.showRightFlag = false;
+            this.isActive = -1;
+            this.isSubMenuActive = -1;
+        }).catch(() => {
+        });
+    },
+    // 删除菜单数据
+    deleteData(){
+        // 一级菜单的删除方法
+        if(this.tempSelfObj.grand == "1"){
+            this.menu.button.splice(this.tempSelfObj.index,1);
+        }
+        // 二级菜单的删除方法
+        if(this.tempSelfObj.grand == "2"){
+            this.menu.button[this.tempSelfObj.index].sub_button.splice(this.tempSelfObj.secondIndex, 1);
+        }
+        this.$message({
+            type: 'success',
+            message: '删除成功!'
+        });
     }
+  },
+}
 </script>
 <!--本组件样式-->
 <style lang="less" scoped="scoped">
@@ -368,153 +429,153 @@ SOFTWARE.
 .clearfix{*zoom:1;}
 .clearfix::after{content: "";display: table; clear: both;}
 div{
-    text-align: left;
+  text-align: left;
 }
 .weixin-hd{
-    color: #fff;
-    text-align: center;
-    position: relative;
-    bottom: 426px;
-    left:0px;
-    width: 300px;
-    height:64px;
-    background: transparent url(assets/menu_head.png) no-repeat 0 0;
-    background-position: 0 0;
-    background-size: 100%
+  color: #fff;
+  text-align: center;
+  position: relative;
+  bottom: 426px;
+  left:0px;
+  width: 300px;
+  height:64px;
+  background: transparent url(assets/menu_head.png) no-repeat 0 0;
+  background-position: 0 0;
+  background-size: 100%
 }
 .weixin-title{
-    color:#fff;
-    font-size:14px;
-    width:100%;
-    text-align: center;
-    position:absolute;
-    top: 33px;
-    left: 0px;
+  color:#fff;
+  font-size:14px;
+  width:100%;
+  text-align: center;
+  position:absolute;
+  top: 33px;
+  left: 0px;
 }
 .weixin-menu{
-    background: transparent url(assets/menu_foot.png) no-repeat 0 0;
-    padding-left: 43px;
-    font-size: 12px
+  background: transparent url(assets/menu_foot.png) no-repeat 0 0;
+  padding-left: 43px;
+  font-size: 12px
 }
 .menu_option{
-    width: 40%!important;
+  width: 40%!important;
 }
 .public-account-management{
-    min-width: 1200px;
-    width: 1200px;
-    margin: 0 auto;
-    .left{
-        float: left;
-        display: inline-block;
-        width: 350px;
-        height: 715px;
-        background: url("assets/iphone_backImg.png") no-repeat;
-        background-size: 100% auto;
-        padding: 518px 25px 88px;
-        position: relative;
-        box-sizing: border-box;
-        /*第一级菜单*/
-        .menu_main{
-            .menu_bottom{
-                position: relative;
-                float: left;
-                display: inline-block;
-                box-sizing: border-box;
-                width: 85.5px;
-                text-align: center;
-                border: 1px solid #ebedee;
-                background-color: #fff;
-                cursor: pointer;
-                &.menu_addicon{
-                    height: 46px;
-                    line-height: 46px;
-                }
-                .menu_item{
-                    height: 44px;
-                    line-height: 44px;
-                    text-align: center;
-                    box-sizing: border-box;
-                    width: 100%;
-                    &.active{
-                        border: 1px solid #2bb673;
-                    }
-                }
-                .menu_subItem{
-                    height: 44px;
-                    line-height: 44px;
-                    text-align: center;
-                    box-sizing: border-box;
-                    &.active{
-                        border: 1px solid #2bb673;
-                    }
-                }
-            }
-            i{
-                color:#2bb673;
-            }
-            /*第二级菜单*/
-            .submenu{
-                position: absolute;
-                width: 85.5px;
-                bottom: 45px;
-                .subtitle{
-                    background-color: #fff;
-                    box-sizing: border-box;
-                }
-            }
-        }
-        .save_div{
-            margin-top: 15px;
-            text-align: center;
-            .save_btn{
-                bottom: 20px;
-                left: 100px;
-            }
-        }
-    }
-    /*右边菜单内容*/
-    .right{
-        float: left;
-        width: 63%;
-        background-color: #e8e7e7;
-        padding: 20px;
-        margin-left: 20px;
-        -webkit-box-sizing: border-box;
-        box-sizing: border-box;
-        .configure_page{
-            .delete_btn{
-                text-align: right;
-                margin-bottom: 15px;
-            }
-            .menu_content{
-                margin-top: 20px;
-            }
-            .configur_content{
-                margin-top: 20px;
-                background-color: #fff;
-                padding: 20px 10px;
-                border-radius: 5px
-            }
-            .blue{
-                color:#29b6f6;
-                margin-top: 10px;
-            }
-            .applet{
-                margin-bottom: 20px;
-                span{
-                    width: 20%;
-                }
-            }
-            .material{
-                .input_width{
-                    width: 30%;
-                }
-                .el-textarea{
-                    width: 80%
-                }
-            }
-        }
-    }
+  min-width: 1200px;
+  width: 1200px;
+  margin: 0 auto;
+  .left{
+      float: left;
+      display: inline-block;
+      width: 350px;
+      height: 715px;
+      background: url("assets/iphone_backImg.png") no-repeat;
+      background-size: 100% auto;
+      padding: 518px 25px 88px;
+      position: relative;
+      box-sizing: border-box;
+      /*第一级菜单*/
+      .menu_main{
+          .menu_bottom{
+              position: relative;
+              float: left;
+              display: inline-block;
+              box-sizing: border-box;
+              width: 85.5px;
+              text-align: center;
+              border: 1px solid #ebedee;
+              background-color: #fff;
+              cursor: pointer;
+              &.menu_addicon{
+                  height: 46px;
+                  line-height: 46px;
+              }
+              .menu_item{
+                  height: 44px;
+                  line-height: 44px;
+                  text-align: center;
+                  box-sizing: border-box;
+                  width: 100%;
+                  &.active{
+                      border: 1px solid #2bb673;
+                  }
+              }
+              .menu_subItem{
+                  height: 44px;
+                  line-height: 44px;
+                  text-align: center;
+                  box-sizing: border-box;
+                  &.active{
+                      border: 1px solid #2bb673;
+                  }
+              }
+          }
+          i{
+              color:#2bb673;
+          }
+          /*第二级菜单*/
+          .submenu{
+              position: absolute;
+              width: 85.5px;
+              bottom: 45px;
+              .subtitle{
+                  background-color: #fff;
+                  box-sizing: border-box;
+              }
+          }
+      }
+      .save_div{
+          margin-top: 15px;
+          text-align: center;
+          .save_btn{
+              bottom: 20px;
+              left: 100px;
+          }
+      }
+  }
+  /*右边菜单内容*/
+  .right{
+      float: left;
+      width: 63%;
+      background-color: #e8e7e7;
+      padding: 20px;
+      margin-left: 20px;
+      -webkit-box-sizing: border-box;
+      box-sizing: border-box;
+      .configure_page{
+          .delete_btn{
+              text-align: right;
+              margin-bottom: 15px;
+          }
+          .menu_content{
+              margin-top: 20px;
+          }
+          .configur_content{
+              margin-top: 20px;
+              background-color: #fff;
+              padding: 20px 10px;
+              border-radius: 5px
+          }
+          .blue{
+              color:#29b6f6;
+              margin-top: 10px;
+          }
+          .applet{
+              margin-bottom: 20px;
+              span{
+                  width: 20%;
+              }
+          }
+          .material{
+              .input_width{
+                  width: 30%;
+              }
+              .el-textarea{
+                  width: 80%
+              }
+          }
+      }
+  }
 }
 </style>
 <!--修改UI框架样式-->

+ 83 - 4
yudao-ui-admin/yarn.lock

@@ -3340,6 +3340,13 @@
   "resolved" "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz"
   "version" "0.5.0"
 
+"copy-anything@^2.0.1":
+  "integrity" "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw=="
+  "resolved" "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz"
+  "version" "2.0.6"
+  dependencies:
+    "is-what" "^3.14.1"
+
 "copy-concurrently@^1.0.0":
   "integrity" "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A=="
   "resolved" "https://registry.npmmirror.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz"
@@ -3696,6 +3703,13 @@
   dependencies:
     "ms" "2.0.0"
 
+"debug@^3.2.6":
+  "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="
+  "resolved" "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz"
+  "version" "3.2.7"
+  dependencies:
+    "ms" "^2.1.1"
+
 "debug@^3.2.7":
   "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="
   "resolved" "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz"
@@ -4215,7 +4229,7 @@
   "resolved" "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz"
   "version" "2.2.0"
 
-"errno@^0.1.3", "errno@~0.1.7":
+"errno@^0.1.1", "errno@^0.1.3", "errno@~0.1.7":
   "integrity" "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A=="
   "resolved" "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz"
   "version" "0.1.8"
@@ -5633,6 +5647,13 @@
   dependencies:
     "safer-buffer" ">= 2.1.2 < 3"
 
+"iconv-lite@^0.6.3":
+  "integrity" "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="
+  "resolved" "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz"
+  "version" "0.6.3"
+  dependencies:
+    "safer-buffer" ">= 2.1.2 < 3.0.0"
+
 "icss-utils@^4.0.0", "icss-utils@^4.1.1":
   "integrity" "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA=="
   "resolved" "https://registry.npmmirror.com/icss-utils/-/icss-utils-4.1.1.tgz"
@@ -5665,7 +5686,7 @@
   "resolved" "https://registry.npmmirror.com/ignore/-/ignore-4.0.6.tgz"
   "version" "4.0.6"
 
-"image-size@^0.5.1":
+"image-size@^0.5.1", "image-size@~0.5.0":
   "integrity" "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ=="
   "resolved" "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz"
   "version" "0.5.5"
@@ -6150,6 +6171,11 @@
   dependencies:
     "call-bind" "^1.0.2"
 
+"is-what@^3.14.1":
+  "integrity" "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA=="
+  "resolved" "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz"
+  "version" "3.14.1"
+
 "is-windows@^1.0.2":
   "integrity" "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
   "resolved" "https://registry.npmmirror.com/is-windows/-/is-windows-1.0.2.tgz"
@@ -6402,6 +6428,32 @@
     "picocolors" "^1.0.0"
     "shell-quote" "^1.7.3"
 
+"less-loader@^7.3.0":
+  "integrity" "sha512-Mi8915g7NMaLlgi77mgTTQvK022xKRQBIVDSyfl3ErTuBhmZBQab0mjeJjNNqGbdR+qrfTleKXqbGI4uEFavxg=="
+  "resolved" "https://registry.npmmirror.com/less-loader/-/less-loader-7.3.0.tgz"
+  "version" "7.3.0"
+  dependencies:
+    "klona" "^2.0.4"
+    "loader-utils" "^2.0.0"
+    "schema-utils" "^3.0.0"
+
+"less@^3.5.0 || ^4.0.0", "less@^4.1.3":
+  "integrity" "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA=="
+  "resolved" "https://registry.npmmirror.com/less/-/less-4.1.3.tgz"
+  "version" "4.1.3"
+  dependencies:
+    "copy-anything" "^2.0.1"
+    "parse-node-version" "^1.0.1"
+    "tslib" "^2.3.0"
+  optionalDependencies:
+    "errno" "^0.1.1"
+    "graceful-fs" "^4.1.2"
+    "image-size" "~0.5.0"
+    "make-dir" "^2.1.0"
+    "mime" "^1.4.1"
+    "needle" "^3.1.0"
+    "source-map" "~0.6.0"
+
 "levn@^0.4.1":
   "integrity" "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="
   "resolved" "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz"
@@ -6629,6 +6681,14 @@
     "pify" "^4.0.1"
     "semver" "^5.6.0"
 
+"make-dir@^2.1.0":
+  "integrity" "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA=="
+  "resolved" "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz"
+  "version" "2.1.0"
+  dependencies:
+    "pify" "^4.0.1"
+    "semver" "^5.6.0"
+
 "make-dir@^3.0.2", "make-dir@^3.1.0":
   "integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="
   "resolved" "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz"
@@ -6819,6 +6879,11 @@
   dependencies:
     "mime-db" "1.52.0"
 
+"mime@^1.4.1":
+  "integrity" "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+  "resolved" "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz"
+  "version" "1.6.0"
+
 "mime@^2.4.4":
   "integrity" "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
   "resolved" "https://registry.npmmirror.com/mime/-/mime-2.6.0.tgz"
@@ -7111,6 +7176,15 @@
   "resolved" "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz"
   "version" "1.4.0"
 
+"needle@^3.1.0":
+  "integrity" "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ=="
+  "resolved" "https://registry.npmmirror.com/needle/-/needle-3.2.0.tgz"
+  "version" "3.2.0"
+  dependencies:
+    "debug" "^3.2.6"
+    "iconv-lite" "^0.6.3"
+    "sax" "^1.2.4"
+
 "negotiator@0.6.3":
   "integrity" "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
   "resolved" "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz"
@@ -7607,6 +7681,11 @@
     "json-parse-even-better-errors" "^2.3.0"
     "lines-and-columns" "^1.1.6"
 
+"parse-node-version@^1.0.1":
+  "integrity" "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA=="
+  "resolved" "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz"
+  "version" "1.0.1"
+
 "parse5-htmlparser2-tree-adapter@^6.0.0":
   "integrity" "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="
   "resolved" "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz"
@@ -8850,7 +8929,7 @@
   dependencies:
     "ret" "~0.1.10"
 
-"safer-buffer@^2.0.2", "safer-buffer@^2.1.0", "safer-buffer@>= 2.1.2 < 3", "safer-buffer@~2.1.0":
+"safer-buffer@^2.0.2", "safer-buffer@^2.1.0", "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", "safer-buffer@~2.1.0":
   "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
   "resolved" "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz"
   "version" "2.1.2"
@@ -10017,7 +10096,7 @@
   "resolved" "https://registry.npmmirror.com/tslib/-/tslib-2.4.1.tgz"
   "version" "2.4.1"
 
-"tslib@2.3.0":
+"tslib@^2.3.0", "tslib@2.3.0":
   "integrity" "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
   "resolved" "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz"
   "version" "2.3.0"