|
@@ -0,0 +1,308 @@
|
|
|
+<template>
|
|
|
+ <div style="padding: 22px 18px;">
|
|
|
+ <div class="space_between_in card_add_page_title" @click="addPage">
|
|
|
+ <span>页面</span>
|
|
|
+ <el-icon color="#337ecc">
|
|
|
+ <Plus />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ <div style="width: 100%;" v-for="(item, index) in listTabs" :key="index">
|
|
|
+ <el-popover :ref="setPopoverRef" :visible="item.visible" placement="right" :width="160"
|
|
|
+ @visible-change="handleVisibleChange">
|
|
|
+ <div class="card_right_click">
|
|
|
+ <div class="title_right" @click.stop="editTitle(item)">
|
|
|
+ <div class="icon_right_click">
|
|
|
+ <el-icon>
|
|
|
+ <EditPen />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ <span>编辑标题</span>
|
|
|
+ </div>
|
|
|
+ <div class="title_right" @click.stop="deletePage(item)" v-if="item.name != '首页' && item.name != '卡片'">
|
|
|
+ <div class="icon_right_click">
|
|
|
+ <el-icon>
|
|
|
+ <Delete />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ <span>删除</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template #reference>
|
|
|
+ <div :class="[item.flag ? 'active_card_page' : '', !item.inputFlag ? 'item_tabs_page' : 'edit_card_page']"
|
|
|
+ @click="getTabs(item)" @contextmenu.stop="onContextMenu($event, item)">
|
|
|
+ <div style="display: flex;align-items: center;" v-if="!item.inputFlag"
|
|
|
+ @dblclick="handleDoubleClick(item)">
|
|
|
+ <span class="iconfont page_icon_img" :style="{ color: (item.flag ? '#409EFF' : '') }"
|
|
|
+ :class="item.icon" v-if="item.icon"></span>
|
|
|
+ <span>{{ item.name }}</span>
|
|
|
+ </div>
|
|
|
+ <input v-if="editIndex === index && item.inputFlag" :ref="setInputRef" class="title_input_edit"
|
|
|
+ v-model="item.name" type="text" @input="handleInput" @blur="handleBlur">
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ElPopover, ElMessageBox } from 'element-plus';
|
|
|
+import { ref, onMounted, onBeforeUnmount } from "vue";
|
|
|
+
|
|
|
+import { useUserStore } from '../stores/index'
|
|
|
+import { storeToRefs } from 'pinia';
|
|
|
+const storeUser = useUserStore()
|
|
|
+const { viewList } = storeToRefs(storeUser)
|
|
|
+
|
|
|
+const emit = defineEmits(['switchPage']);
|
|
|
+const listTabs = ref(viewList)
|
|
|
+function getTabs(params: any) {
|
|
|
+ listTabs.value.forEach(item => {
|
|
|
+ if (params.id == item.id) {
|
|
|
+ item.flag = true
|
|
|
+ } else {
|
|
|
+ item.flag = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ emit('switchPage');
|
|
|
+}
|
|
|
+// 右键弹窗编辑、删除
|
|
|
+const onContextMenu = (event, value) => {
|
|
|
+ listTabs.value.forEach(item => {
|
|
|
+ if (value.id == item.id) {
|
|
|
+ item.visible = true
|
|
|
+ } else {
|
|
|
+ item.visible = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ event.preventDefault();
|
|
|
+}
|
|
|
+const editIndex: any = ref(null);
|
|
|
+const inputRef: any = ref(null);
|
|
|
+const setInputRef = (el) => {
|
|
|
+ inputRef.value = el;
|
|
|
+};
|
|
|
+// 双击输入框获取焦点
|
|
|
+function handleDoubleClick(params: any) {
|
|
|
+ listTabs.value.forEach((item, index) => {
|
|
|
+ if (params.id == item.id) {
|
|
|
+ item.inputFlag = true
|
|
|
+ editIndex.value = index;
|
|
|
+ setTimeout(() => {
|
|
|
+ if (inputRef.value) {
|
|
|
+ inputRef.value.focus();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ item.inputFlag = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+// 右键编辑标题
|
|
|
+function editTitle(params: any) {
|
|
|
+ listTabs.value.forEach((item, index) => {
|
|
|
+ if (params.id == item.id) {
|
|
|
+ item.visible = false
|
|
|
+ item.inputFlag = true
|
|
|
+ editIndex.value = index;
|
|
|
+ setTimeout(() => {
|
|
|
+ if (inputRef.value) {
|
|
|
+ inputRef.value.focus();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ item.inputFlag = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+// 右键删除页面
|
|
|
+function deletePage(params: any) {
|
|
|
+ const index = listTabs.value.findIndex(item => item.id === params.id);
|
|
|
+ if (index !== -1) {
|
|
|
+ listTabs.value[index].visible = false;
|
|
|
+ listTabs.value[index].inputFlag = false;
|
|
|
+ }
|
|
|
+ ElMessageBox.confirm(
|
|
|
+ '删除后不可恢复,请谨慎操作',
|
|
|
+ '确定要删除该页面吗?',
|
|
|
+ {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ }
|
|
|
+ ).then(() => {
|
|
|
+ listTabs.value = listTabs.value.filter(item => item.id !== params.id);
|
|
|
+ }).catch((err) => {
|
|
|
+ console.log(err);
|
|
|
+ })
|
|
|
+}
|
|
|
+// 修改编辑输入框内容变化
|
|
|
+function handleInput(params: any) {
|
|
|
+ console.log(params, 3);
|
|
|
+
|
|
|
+}
|
|
|
+// 修改编辑失去焦点
|
|
|
+function handleBlur() {
|
|
|
+ listTabs.value.forEach(item => {
|
|
|
+ item.inputFlag = false
|
|
|
+ })
|
|
|
+}
|
|
|
+// 添加页面
|
|
|
+function addPage() {
|
|
|
+ listTabs.value.forEach(item => {
|
|
|
+ item.flag = false
|
|
|
+ })
|
|
|
+ let arrList: any = {
|
|
|
+ id: listTabs.value.length + 1,
|
|
|
+ flag: true,
|
|
|
+ visible: false,
|
|
|
+ inputFlag: false,
|
|
|
+ name: '未命名 ' + (listTabs.value.length + 1),
|
|
|
+ }
|
|
|
+ listTabs.value.push(arrList)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const popoverRefs = new Set<any>();
|
|
|
+const setPopoverRef = (el: any) => {
|
|
|
+ popoverRefs.add(el);
|
|
|
+};
|
|
|
+const handleVisibleChange = (visible: boolean) => {
|
|
|
+ if (!visible) {
|
|
|
+ popoverRefs.forEach((popover) => {
|
|
|
+ popover.visible = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+onMounted(() => {
|
|
|
+ document.addEventListener('click', handleClickOutside);
|
|
|
+});
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ document.removeEventListener('click', handleClickOutside);
|
|
|
+});
|
|
|
+const handleClickOutside = (event: MouseEvent) => {
|
|
|
+ for (const item of listTabs.value) {
|
|
|
+ if (item.visible && event.target instanceof Node) {
|
|
|
+ const target = event.target as Element;
|
|
|
+ let node = target;
|
|
|
+ while (node) {
|
|
|
+ if (node === document.querySelector(`[data-item-id="${item.id}"]`)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ node = node.parentNode as Element;
|
|
|
+ }
|
|
|
+ item.visible = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.card_add_page_title {
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 0px 5px;
|
|
|
+ margin-bottom: 22px;
|
|
|
+
|
|
|
+ span {
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgb(51, 51, 51);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.card_right_click {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.title_right {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ -webkit-box-align: center;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ padding-left: 23px;
|
|
|
+ height: 32px;
|
|
|
+ transition: 0.2s;
|
|
|
+ overflow: hidden;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.title_right:hover {
|
|
|
+ background-color: rgba(15, 115, 230, 0.08);
|
|
|
+
|
|
|
+ .icon_right_click {
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ span {
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.icon_right_click {
|
|
|
+ position: absolute;
|
|
|
+ left: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.item_tabs_page {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ -webkit-box-align: center;
|
|
|
+ align-items: center;
|
|
|
+ position: relative;
|
|
|
+ cursor: pointer;
|
|
|
+ padding-left: 23px;
|
|
|
+ height: 32px;
|
|
|
+ overflow: hidden;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.item_tabs_page:hover {
|
|
|
+ color: #409EFF;
|
|
|
+ background: rgba(15, 115, 230, 0.08);
|
|
|
+
|
|
|
+ span {
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.active_card_page {
|
|
|
+ color: #409EFF;
|
|
|
+ background: rgba(15, 115, 230, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.edit_card_page {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+.page_icon_img {
|
|
|
+ position: absolute;
|
|
|
+ left: 5px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+
|
|
|
+.title_input_edit {
|
|
|
+ width: 100%;
|
|
|
+ border: 1px solid #409EFF;
|
|
|
+ height: 32px;
|
|
|
+ padding: 0;
|
|
|
+ /* 添加自定义样式 */
|
|
|
+ background-color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ padding: 8px;
|
|
|
+ border-radius: 3px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 当input获得焦点时的样式 */
|
|
|
+.title_input_edit:focus {
|
|
|
+ outline: none;
|
|
|
+ border-color: #409EFF;
|
|
|
+ box-shadow: 0 0 0 2px #c6e2ff;
|
|
|
+}
|
|
|
+</style>
|