Browse Source

封装统一树组件、封装统一左右布局组件

ZaiZai 2 năm trước cách đây
mục cha
commit
50b1a5e556

+ 4 - 0
src/global/components/index.js

@@ -1,10 +1,14 @@
 import HcTooltip from './hc-tooltip/index.vue'
 import HcTipItem from './hc-tooltip/item.vue'
 import HcTableForm from './table-form/index.vue'
+import HcPageLayout from './page-layout/index.vue'
+import HcTreeData from './tree-data/index.vue'
 
 //注册全局组件
 export const setupComponents = (App) => {
     App.component('HcTooltip', HcTooltip)
     App.component('HcTipItem', HcTipItem)
     App.component('HcTableForm', HcTableForm)
+    App.component('HcTreeData', HcTreeData)
+    App.component('HcPageLayout', HcPageLayout)
 }

+ 75 - 0
src/global/components/page-layout/index.vue

@@ -0,0 +1,75 @@
+<template>
+    <div class="hc-page-layout-box split" :class="ui">
+        <div class="hc-layout-left-box" :id="'page-' + left_uuid">
+            <slot name="left"></slot>
+        </div>
+        <div class="hc-page-content-box" :id="'page-' + page_uuid">
+            <slot></slot>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import {onMounted, onUnmounted, ref} from "vue";
+import {getRandom} from "js-fast-way";
+import split from "split.js";
+
+//参数
+const props = defineProps({
+    ui: String
+})
+
+//变量
+const left_uuid = getRandom(8);
+const page_uuid = getRandom(8);
+
+//渲染完成
+onMounted(()=> {
+    setSplitDom()
+})
+
+// 初始化设置拖动分割线
+const splitvar = ref(null);
+const setSplitDom = () => {
+    try {
+        //配置参考: https://split.js.org/#/?direction=vertical&snapOffset=0
+        splitvar.value = split([
+            `#page-${left_uuid}`,
+            `#page-${page_uuid}`
+        ], {
+            sizes: [20, 80],
+            minSize: [200, 900],
+        });
+    } catch (e) {
+        setTimeout(() => {
+            setSplitDom()
+        }, 500)
+    }
+}
+
+//销毁
+onUnmounted(() => {
+    if (splitvar.value) {
+        splitvar.value.destroy()
+    }
+})
+</script>
+
+<style lang="scss">
+.hc-page-layout-box.split {
+    --hc-box-shadow: 0 0 10px 0 rgba(32, 37, 50, 0.03), 0 10px 21px 20px rgba(32, 37, 50, 0.03);
+    .hc-layout-left-box {
+        margin-right: 3px;
+        box-shadow: var(--hc-box-shadow);
+    }
+    .gutter {
+        background-color: transparent;
+    }
+    .hc-page-content-box {
+        margin-left: 3px;
+        .el-card.hc-card-box {
+            box-shadow: var(--hc-box-shadow);
+        }
+    }
+}
+</style>

+ 190 - 0
src/global/components/tree-data/index.vue

@@ -0,0 +1,190 @@
+<template>
+    <HcDataTree :h-props="treeProps" :autoExpandKeys="autoExpandKeys" :treeKey="treeKey" :datas="treeLoadNode" @nodeTap="treeNodeClick">
+        <template #default="{node, data, level}">
+            <div :class="level === 1 ? 'level-name':''" class="label flex items-center">
+                <span class="hc-tree-node-type" v-if="level !== 1">县</span>
+                <span>{{node.label }}</span>
+            </div>
+            <!--树组件,操作菜单-->
+            <div v-if="isMenus" :class="node.showTreeMenu?'show':''" class="menu-icon1">
+                <div class="cu-tree-node-popover-menu-icon" @click.prevent.stop="treeLabelContextMenu($event, data, node)">
+                    <HcIcon name="apps" ui="text-2xl"/>
+                </div>
+            </div>
+        </template>
+    </HcDataTree>
+    <!--右键菜单-->
+    <HcContextMenu ref="contextMenuRef" :datas="treeMenu" @closed="handleMenuClosed" @item-click="handleMenuSelect" v-if="isMenus"/>
+</template>
+
+<script setup>
+import {ref,watch,onMounted} from "vue";
+import {isNullES} from "js-fast-way";
+
+//参数
+const props = defineProps({
+    isMenu: {
+        type: Boolean,
+        default: true
+    }
+})
+
+//渲染完成
+onMounted(()=> {
+
+})
+
+//事件
+
+const treeKey = ref('label')
+const treeRefNode = ref({});
+const treeRefData = ref({});
+const isMenus = ref(props.isMenu);
+const autoExpandKeys = ref([]);
+
+//事件
+const emit = defineEmits(['menuTap', 'nodeTap'])
+
+//数据格式
+const treeProps = {
+    label: 'label',
+    children: 'children'
+}
+
+
+//数据
+const treeLoadNode = ref([
+    {
+        label: '征拆区域',
+        children: [
+            {
+                label: 'Level two 1-1',
+                children: [
+                    {label: 'Level three 1-1-1'}
+                ]
+            },
+            {
+                label: 'Level two 2-1',
+                children: [
+                    {label: 'Level three 2-1-1'}
+                ]
+            },
+            {
+                label: 'Level two 2-2',
+                children: [
+                    {label: 'Level three 2-2-1'}
+                ]
+            },
+            {
+                label: 'Level two 3-1',
+                children: [
+                    {label: 'Level three 3-1-1'}
+                ]
+            },
+            {
+                label: 'Level two 3-2',
+                children: [
+                    {label: 'Level three 3-2-1'}
+                ]
+            }
+        ]
+    }
+])
+
+//树被点击
+const treeNodeClick = async ({node, data, keys}) => {
+    treeRefNode.value = node
+    treeRefData.value = data
+    emit('nodeTap', {node, data})
+}
+
+//标题的鼠标右键
+const treeMenu = ref([])
+const contextMenuRef = ref(null)
+const treeLabelContextMenu = (e, data, node) => {
+    if (!isMenus.value) {
+        return;
+    }
+    e.preventDefault();
+    treeRefNode.value = node;
+    treeRefData.value = data;
+    if (node.level === 1) {
+        treeMenu.value =  [{icon: 'add-circle', label: '新增节点', key: "add"}]
+    } else {
+        treeMenu.value = [
+            {icon: 'add-circle', label: '新增节点', key: "add"},
+            {icon: 'draft', label: '编辑节点', key: "edit"},
+            {icon: 'delete-bin', label: '删除节点', key: "del"}
+        ]
+    }
+    node.showTreeMenu = true
+    contextMenuRef.value?.showMenu(e)
+}
+
+
+const handleMenuClosed = () => {
+    const node = treeRefNode.value;
+    if (!isNullES(node)) {
+        treeRefNode.value['showTreeMenu'] = false
+    }
+}
+
+//鼠标右键菜单被点击
+const handleMenuSelect = async ({key}) => {
+    const node = treeRefNode.value;
+    const data = treeRefData.value;
+    const autoKeys = await getAutoKeys(node)
+    //返回事件
+    emit('menuTap', {key, node, data})
+}
+
+
+//处理自动展开的节点KEY
+const getAutoKeys = async (node) => {
+    let autoKeysArr = []
+    await getNodeExpandKeys(node, autoKeysArr)
+    return autoKeysArr.reverse()
+}
+const getNodeExpandKeys = async ({parent, data}, newKeys) => {
+    const nodeKey = data[treeKey.value] ?? ''
+    if (nodeKey) {
+        newKeys.push(nodeKey)
+        await getNodeExpandKeys(parent, newKeys)
+    }
+}
+</script>
+
+<style lang="scss">
+.data-custom-tree-node {
+    .menu-icon1 {
+        position: relative;
+        vertical-align: bottom;
+        display: inline-block;
+        width: 0;
+        right: -45px;
+        border-radius: 2px;
+        pointer-events: none;
+        background: rgba(255, 255, 255, 0.25);
+        transition: width 0.2s;
+        .cu-tree-node-popover-menu-icon {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+    }
+    &:hover {
+        .menu-icon1 {
+            right: 0;
+            width: 24px;
+            pointer-events: all;
+            cursor: context-menu;
+        }
+    }
+    .menu-icon1.show {
+        right: 0;
+        width: 24px;
+        pointer-events: all;
+        cursor: context-menu;
+    }
+}
+</style>

+ 52 - 2
src/views/base/land.vue

@@ -1,13 +1,63 @@
 <template>
-    <div>222</div>
+    <HcPageLayout>
+        <template #left>
+            <div class="hc-layout-tree-box">
+                <el-scrollbar>
+                    <HcTreeData @nodeTap="treeNodeTap" @menuTap="treeMenuTap"/>
+                </el-scrollbar>
+            </div>
+        </template>
+        <HcCard>
+            <template #header>
+                0000
+                <!--div class="w-72">
+                    <el-input v-model="searchForm.queryValue" clearable placeholder="请输入容器编号查询" size="large" @keyup="keyUpEvent"/>
+                </div>
+                <div class="ml-2">
+                    <el-button size="large" type="primary" @click="searchClick">
+                        <HcIcon name="search-2"/>
+                        <span>搜索</span>
+                    </el-button>
+                </div-->
+            </template>
+            <template #extra>
+                111
+            </template>
+            2222
+            <template #action>
+                333
+                <!--HcPages :pages="searchForm" @change="pageChange"/-->
+            </template>
+        </HcCard>
+    </HcPageLayout>
 </template>
 
 <script setup>
+import {ref} from "vue";
 
+//树节点被点击
+const treeNodeTap = ({node, data}) => {
+
+}
+
+//树菜单被点击
+const treeMenuTap = ({key, node, data}) => {
+    if (key === 'add') {
+
+    } else if (key === 'edit') {
+
+    } else if (key === 'del') {
+
+    }
+}
 </script>
 
 <style lang="scss" scoped>
-
+.hc-layout-tree-box {
+    position: relative;
+    height: 100%;
+    padding: 18px;
+}
 </style>
 
 <style lang="scss">