|
@@ -0,0 +1,459 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="custom-menu">
|
|
|
|
+ <div class="menu-container">
|
|
|
|
+ <div class="device-wrap">
|
|
|
|
+ <div class="device device-iphone-x">
|
|
|
|
+ <div class="device-frame">
|
|
|
|
+ <div class="device-content">
|
|
|
|
+ <div class="wechat-header">
|
|
|
|
+ <div class="header-inner">
|
|
|
|
+ <el-icon class="ml-3">
|
|
|
|
+ <ArrowLeft />
|
|
|
|
+ </el-icon>
|
|
|
|
+ 公众号
|
|
|
|
+ <el-icon class="mr-3">
|
|
|
|
+ <User />
|
|
|
|
+ </el-icon>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="wechat-menu">
|
|
|
|
+ <Draggable :list="menus.buttons" classString="flex-warpper" @end="onEnd">
|
|
|
|
+ <template #default="{ item, index }">
|
|
|
|
+ <div class="wechat-menu-item" :key="index">
|
|
|
|
+ <p :class="['menu-name', { 'cur-menu': (index) === menus.curActiveIndex }]" @click="addMenu(index)">
|
|
|
|
+ {{ item.name }}
|
|
|
|
+ </p>
|
|
|
|
+ <div class="children-menu-items" v-if="isShowChild(item)">
|
|
|
|
+ <Draggable :list="item.sub_button" @end="onEndChild">
|
|
|
|
+ <template #default="{ item, index }">
|
|
|
|
+ <div class="children-menu-item" :key="index" @click="changeCurSubMenuIndex(index)">
|
|
|
|
+ <p :class="['menu-name', { 'cur-name': menus.curSubActiveIndex === index }]">
|
|
|
|
+ {{ item.name }}
|
|
|
|
+ </p>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </Draggable>
|
|
|
|
+ <div v-if="item?.sub_button?.length < 5" class="children-menu-item" @click="addSubMenu">
|
|
|
|
+ <el-icon>
|
|
|
|
+ <Plus />
|
|
|
|
+ </el-icon>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </Draggable>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="device-stripe"></div>
|
|
|
|
+ <div class="device-header"></div>
|
|
|
|
+ <div class="device-sensors"></div>
|
|
|
|
+ <div class="device-btns"></div>
|
|
|
|
+ <div class="device-power"></div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="edit-wrap">
|
|
|
|
+ <div v-if="menus.init">
|
|
|
|
+ <div class="edit-content-wrap">
|
|
|
|
+ <p class="edit-title">
|
|
|
|
+ {{
|
|
|
|
+ menus.clickSubMenu ?
|
|
|
|
+ menus?.buttons[menus.curActiveIndex]?.sub_button[menus.curSubActiveIndex]?.name
|
|
|
|
+ : menus?.buttons[menus.curActiveIndex]?.name
|
|
|
|
+ }}
|
|
|
|
+ <span class="del-menu" @click="delMenus(menus.clickSubMenu)">
|
|
|
|
+ 删除{{ menus.clickSubMenu ? "子菜单" : "菜单" }}
|
|
|
|
+ </span>
|
|
|
|
+ </p>
|
|
|
|
+ <p class="notice-text" v-if="(menus.buttons[menus.curActiveIndex].hasChild) && !menus.clickSubMenu">
|
|
|
|
+ 已添加子菜单,仅可设置菜单名称。
|
|
|
|
+ </p>
|
|
|
|
+ <div class="edit-form">
|
|
|
|
+ <div v-if="menus.clickSubMenu">
|
|
|
|
+ <el-form :model="menus.buttons[menus.curActiveIndex].sub_button[menus.curSubActiveIndex]"
|
|
|
|
+ label-width="100px" label-position="left">
|
|
|
|
+ <el-form-item label="子菜单名称" prop="title" v-if="hasChild">
|
|
|
|
+ <el-input v-model="menus.buttons[menus.curActiveIndex].sub_button[menus.curSubActiveIndex].name"
|
|
|
|
+ style="width: 260px"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="子菜单内容" v-if="hasChild">
|
|
|
|
+ <el-radio-group
|
|
|
|
+ v-model="menus.buttons[menus.curActiveIndex].sub_button[menus.curSubActiveIndex].type">
|
|
|
|
+ <el-radio class="radio" label="link">跳转网页</el-radio>
|
|
|
|
+ <el-radio class="radio" label="event">发送消息</el-radio>
|
|
|
|
+ <el-radio class="radio" label="hdlink">互动链</el-radio>
|
|
|
|
+ </el-radio-group>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-form>
|
|
|
|
+ </div>
|
|
|
|
+ <div v-else>
|
|
|
|
+ <el-form :model="menus?.buttons[menus?.curActiveIndex]" label-width="100px" label-position="left">
|
|
|
|
+ <el-form-item label="菜单名称" prop="title">
|
|
|
|
+ <el-input v-model="menus.buttons[menus.curActiveIndex].name" style="width: 260px" :maxlength="10"
|
|
|
|
+ placeholder="请输入菜单名称(最多10个字符)"></el-input>
|
|
|
|
+ <span style="color:#fd555d;padding-left:10px">受微信限制,如您发现微信显示有问题,请减少内容</span>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <div v-if="!menus.buttons[menus.curActiveIndex].sub_button.length">
|
|
|
|
+ <el-form-item label="菜单内容">
|
|
|
|
+ <el-radio-group v-model="menus.buttons[menus.curActiveIndex].type">
|
|
|
|
+ <el-radio class="radio" label="link">跳转网页</el-radio>
|
|
|
|
+ <el-radio class="radio" label="event">发送消息</el-radio>
|
|
|
|
+ <el-radio class="radio" label="hdlink">互动链</el-radio>
|
|
|
|
+ </el-radio-group>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </div>
|
|
|
|
+ </el-form>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div v-else>
|
|
|
|
+ <p class="no-init">点击左侧菜单进行编辑操作</p>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="menu-save">
|
|
|
|
+ <el-button type="primary" :disabled="btnDisable">保存</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
+import { Plus, ArrowLeft, User } from '@element-plus/icons-vue';
|
|
|
|
+const limitButtons = ref(3)
|
|
|
|
+const menus = ref<object>({
|
|
|
|
+ curActiveIndex: null,
|
|
|
|
+ curSubActiveIndex: null,
|
|
|
|
+ clickSubMenu: false,
|
|
|
|
+ init: false,
|
|
|
|
+ buttons: [],
|
|
|
|
+})
|
|
|
|
+const isShowChild = (item: object) => {
|
|
|
|
+ return item.showChildMenu
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const hasChild = computed(() =>
|
|
|
|
+ menus.value?.buttons[menus.value?.curActiveIndex]?.sub_button[menus.value?.curSubActiveIndex]?.name
|
|
|
|
+ ||
|
|
|
|
+ menus.value?.buttons[menus.value?.curActiveIndex]?.sub_button[menus.value?.curSubActiveIndex]?.type
|
|
|
|
+)
|
|
|
|
+const btnDisable = ref(true)
|
|
|
|
+const onEnd = (e: any) => {
|
|
|
|
+ menus.value.init = true;
|
|
|
|
+ menus.value.clickSubMenu = false;
|
|
|
|
+ menus.value.curSubActiveIndex = null;
|
|
|
|
+ menus.value.curActiveIndex = e.newDraggableIndex;
|
|
|
|
+ menus.value.buttons.forEach(el => el.showChildMenu = false)
|
|
|
|
+ menus.value.buttons[e.newDraggableIndex].showChildMenu = true
|
|
|
|
+}
|
|
|
|
+const onEndChild = (e: any) => {
|
|
|
|
+ // * 修改子菜单索引
|
|
|
|
+ menus.value.curSubActiveIndex = e.newDraggableIndex;
|
|
|
|
+}
|
|
|
|
+const addMenu = (i: any) => {
|
|
|
|
+ console.log(i, 'addMenuaddMenuaddMenu');
|
|
|
|
+ menus.value.init = true;
|
|
|
|
+ menus.value.clickSubMenu = false;
|
|
|
|
+ menus.value.curSubActiveIndex = null;
|
|
|
|
+ let buttons = menus.value.buttons;
|
|
|
|
+ if (i === menus.value.curActiveIndex) return;
|
|
|
|
+ // * 切换别的菜单时 隐藏当前菜单
|
|
|
|
+ if (menus.value.curActiveIndex !== null) {
|
|
|
|
+ menus.value.buttons[menus.value.curActiveIndex] &&
|
|
|
|
+ (menus.value.buttons[menus.value.curActiveIndex].showChildMenu = false);
|
|
|
|
+ }
|
|
|
|
+ menus.value.curActiveIndex = i;
|
|
|
|
+ if (buttons[i]) {
|
|
|
|
+ // * 已经有 则显示childMenu
|
|
|
|
+ menus.value.buttons[menus.value.curActiveIndex] &&
|
|
|
|
+ (menus.value.buttons[menus.value.curActiveIndex].showChildMenu = true);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (buttons.length >= limitButtons.value) return;
|
|
|
|
+ const menuObj = {
|
|
|
|
+ name: "菜单名称",
|
|
|
|
+ hasChild: false,
|
|
|
|
+ showChildMenu: true,
|
|
|
|
+ type: "link",
|
|
|
|
+ url: "",
|
|
|
|
+ url2: "",
|
|
|
|
+ key: "",
|
|
|
|
+ keyword: "",
|
|
|
|
+ linkcontent: "",
|
|
|
|
+ imgUrl: '',
|
|
|
|
+ sendMsgType: "template",
|
|
|
|
+ sendCustomUrl: "",
|
|
|
|
+ sub_button: [],
|
|
|
|
+ };
|
|
|
|
+ menus.value.buttons.push(menuObj);
|
|
|
|
+}
|
|
|
|
+const changeCurSubMenuIndex = (i: any) => {
|
|
|
|
+ // * 修改子菜单索引
|
|
|
|
+ if (i === menus.value.curSubActiveIndex) return;
|
|
|
|
+ menus.value.init = true;
|
|
|
|
+ menus.value.clickSubMenu = true;
|
|
|
|
+ menus.value.curSubActiveIndex = i;
|
|
|
|
+}
|
|
|
|
+const addSubMenu = () => {
|
|
|
|
+ // * 添加子菜单
|
|
|
|
+ menus.value.init = true;
|
|
|
|
+ menus.value.clickSubMenu = true;
|
|
|
|
+ let curActiveIndex = menus.value.curActiveIndex;
|
|
|
|
+ let subMenuObj = {
|
|
|
|
+ name: "子菜单名称",
|
|
|
|
+ url: "",
|
|
|
|
+ url2: "",
|
|
|
|
+ key: "",
|
|
|
|
+ type: "link",
|
|
|
|
+ keyword: "",
|
|
|
|
+ linkcontent: "",
|
|
|
|
+ imgUrl: '',
|
|
|
|
+ sendMsgType: "template",
|
|
|
|
+ sendCustomUrl: ""
|
|
|
|
+ };
|
|
|
|
+ menus.value.buttons[curActiveIndex].sub_button.push(subMenuObj);
|
|
|
|
+ // * 默认选择最新增加的子菜单
|
|
|
|
+ menus.value.curSubActiveIndex = menus.value.buttons[curActiveIndex].sub_button.length - 1;
|
|
|
|
+ menus.value.buttons[curActiveIndex].hasChild = true;
|
|
|
|
+}
|
|
|
|
+const delMenus = (isSubMenu: boolean) => {
|
|
|
|
+ // * 删除菜单或者子菜单内容
|
|
|
|
+ let curActiveIndex = menus.value.curActiveIndex;
|
|
|
|
+ let curSubActiveIndex = menus.value.curSubActiveIndex;
|
|
|
|
+ ElMessageBox.confirm(
|
|
|
|
+ isSubMenu
|
|
|
|
+ ? "删除后“子菜单名称”菜单下设置的内容将被删除"
|
|
|
|
+ : "删除后“菜单名称”菜单下设置的内容将被删除",
|
|
|
|
+ "温馨提示",
|
|
|
|
+ {
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
+ type: "warning",
|
|
|
|
+ }
|
|
|
|
+ )
|
|
|
|
+ .then(() => {
|
|
|
|
+ console.log("del");
|
|
|
|
+ if (isSubMenu) {
|
|
|
|
+ menus.value.buttons[curActiveIndex].sub_button.splice(
|
|
|
|
+ curSubActiveIndex,
|
|
|
|
+ 1
|
|
|
|
+ );
|
|
|
|
+ menus.value.buttons[curActiveIndex].hasChild =
|
|
|
|
+ menus.value.buttons[curActiveIndex].sub_button.length > 0;
|
|
|
|
+ menus.value.curSubActiveIndex = null;
|
|
|
|
+ menus.value.init = false;
|
|
|
|
+ } else {
|
|
|
|
+ menus.value.buttons.splice(curActiveIndex, 1);
|
|
|
|
+ if (!menus.value.buttons.length) btnDisable.value = true;
|
|
|
|
+ reset();
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .catch(() => {
|
|
|
|
+ console.log("cancel");
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+const reset = () => {
|
|
|
|
+ // * 重置内容
|
|
|
|
+ menus.value.curActiveIndex = null;
|
|
|
|
+ menus.value.curSubActiveIndex = null;
|
|
|
|
+ menus.value.init = false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+onMounted(() => {
|
|
|
|
+ menus.value = {
|
|
|
|
+ curActiveIndex: 0,
|
|
|
|
+ curSubActiveIndex: null,
|
|
|
|
+ clickSubMenu: false,
|
|
|
|
+ init: true,
|
|
|
|
+ buttons:
|
|
|
|
+ [
|
|
|
|
+ { name: "签到", hasChild: false, showChildMenu: true, type: "link", url: "", url2: "", key: "daily_sign", sub_button: [], keyword: "", linkcontent: "", imgUrl: "", sendMsgType: "template" },
|
|
|
|
+ { name: "最近阅读", hasChild: false, showChildMenu: false, type: "event", url: "", url2: "", key: "recent_read", sub_button: [], keyword: "", linkcontent: "", imgUrl: "", sendMsgType: "template" },
|
|
|
|
+ {
|
|
|
|
+ name: "菜单名称3", hasChild: true, showChildMenu: false, type: "link", url: "", url2: "", key: "", keyword: "", linkcontent: "", imgUrl: "", sendMsgType: "template", sendCustomUrl: "",
|
|
|
|
+ sub_button: [
|
|
|
|
+ { key: "", type: "link", name: "子菜单名称", url: "http://sitexyvz5mexll52mzn4.pre.aizhuishu.com/recent", url2: "", keyword: "", linkcontent: "", sendMsgType: "template", imgUrl: "" }]
|
|
|
|
+ }
|
|
|
|
+ ]
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+)
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
+.menu-container {
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: flex-start;
|
|
|
|
+ align-items: flex-start;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.device-wrap {
|
|
|
|
+ width: 350px;
|
|
|
|
+ margin-left: 20px;
|
|
|
|
+ margin-top: 20px;
|
|
|
|
+
|
|
|
|
+ img {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ border-bottom-left-radius: 40px;
|
|
|
|
+ border-bottom-right-radius: 40px;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.edit-wrap {
|
|
|
|
+ flex: 1;
|
|
|
|
+ min-height: 668px;
|
|
|
|
+ background: #fff;
|
|
|
|
+ margin: 20px 20px 0 20px;
|
|
|
|
+ position: relative;
|
|
|
|
+ border: 1px solid #333;
|
|
|
|
+ border-radius: 9px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.wechat-header {
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 0;
|
|
|
|
+ left: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 80px;
|
|
|
|
+ line-height: 80px;
|
|
|
|
+ background: #eee;
|
|
|
|
+ color: #000;
|
|
|
|
+ padding-top: 20px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ border-bottom: 1px solid #d6d5da;
|
|
|
|
+ border-top-left-radius: 40px;
|
|
|
|
+ border-top-right-radius: 40px;
|
|
|
|
+
|
|
|
|
+ .header-inner {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.wechat-menu {
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ position: absolute;
|
|
|
|
+ width: 100%;
|
|
|
|
+ bottom: 0;
|
|
|
|
+ left: 0;
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: flex-start;
|
|
|
|
+ align-items: center;
|
|
|
|
+ border-top: 1px solid #d6d5da;
|
|
|
|
+
|
|
|
|
+ .flex-warpper {
|
|
|
|
+ width: 100%;
|
|
|
|
+ display: flex;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .wechat-menu-item {
|
|
|
|
+ flex: 1;
|
|
|
|
+ position: relative;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+
|
|
|
|
+ p {
|
|
|
|
+ text-align: center;
|
|
|
|
+ padding: 15px 0;
|
|
|
|
+ overflow: hidden;
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+
|
|
|
|
+ &.cur-menu {
|
|
|
|
+ color: #39a4ff;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &:not(:last-child) {
|
|
|
|
+ border-right: 1px solid #d6d5da;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.children-menu-items {
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ position: absolute;
|
|
|
|
+ background: #f8f8f8;
|
|
|
|
+ border-radius: 3px;
|
|
|
|
+ left: 0%;
|
|
|
|
+ bottom: 120%;
|
|
|
|
+ width: 100%;
|
|
|
|
+ border: 1px solid #d6d5da;
|
|
|
|
+ z-index: 9;
|
|
|
|
+
|
|
|
|
+ .children-menu-item {
|
|
|
|
+ padding: 10px 0;
|
|
|
|
+ text-align: center;
|
|
|
|
+ background: #f8f8f8;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ border: 1px solid rgba($color: #d6d5da, $alpha: 1.0);
|
|
|
|
+
|
|
|
|
+ p {
|
|
|
|
+ padding: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ overflow: hidden;
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+
|
|
|
|
+ &.cur-name {
|
|
|
|
+ color: #39a4ff;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.no-init {
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 50%;
|
|
|
|
+ top: 50%;
|
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
|
+ font-size: 16px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.edit-content-wrap {
|
|
|
|
+ position: relative;
|
|
|
|
+ margin: 15px;
|
|
|
|
+
|
|
|
|
+ .edit-title {
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ align-items: center;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ padding-bottom: 10px;
|
|
|
|
+ border-bottom: 1px solid #999;
|
|
|
|
+
|
|
|
|
+ .del-menu {
|
|
|
|
+ color: #39a4ff;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .notice-text {
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ margin: 5px 0;
|
|
|
|
+ color: #999;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .edit-form {
|
|
|
|
+ margin-top: 20px;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.menu-save {
|
|
|
|
+ text-align: center;
|
|
|
|
+ margin-top: 20px;
|
|
|
|
+ padding-bottom: 20px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.choose-mode {
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: 20px;
|
|
|
|
+ top: 50%;
|
|
|
|
+ transform: translateY(-50%);
|
|
|
|
+
|
|
|
|
+ span {
|
|
|
|
+ color: #39a4ff;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|