refactor: 前端布局 菜单,部门:重构

This commit is contained in:
H0nGzA1
2023-05-17 21:25:59 +08:00
parent 3cccfaa7f4
commit 17b67e43c9
2 changed files with 470 additions and 433 deletions

View File

@@ -1,10 +1,10 @@
<template> <template>
<fs-page> <fs-page>
<el-row class="mx-2"> <splitpanes>
<el-col :span="4" class="p-1"> <pane max-size="20">
<el-card :body-style="{ height: '100%' }"> <el-card :body-style="{ height: '100%' }">
<p class="font-mono font-black text-center text-xl pb-5">部门列表</p> <p class="font-mono font-black text-center text-xl pb-5">部门列表</p>
<el-input v-model="filterText" :placeholder="placeholder" /> <el-input v-model="filterText" :placeholder="placeholder"/>
<el-tree <el-tree
ref="treeRef" ref="treeRef"
class="font-mono font-bold leading-6 text-7xl" class="font-mono font-bold leading-6 text-7xl"
@@ -20,13 +20,15 @@
@node-click="handleNodeClick" @node-click="handleNodeClick"
> >
<template #default="{ node, data }"> <template #default="{ node, data }">
<span v-if="data.status" class="text-center font-black text-xl"><SvgIcon :name="node.data.icon" />&nbsp;{{ node.label }}</span> <span v-if="data.status" class="text-center font-black text-xl"><SvgIcon
<span v-else class="text-center font-black text-xl text-red-700"><SvgIcon :name="node.data.icon" />&nbsp;{{ node.label }}</span> :name="node.data.icon"/>&nbsp;{{ node.label }}</span>
<span v-else class="text-center font-black text-xl text-red-700"><SvgIcon
:name="node.data.icon"/>&nbsp;{{ node.label }}</span>
</template> </template>
</el-tree> </el-tree>
</el-card> </el-card>
</el-col> </pane>
<el-col :span="20" class="p-1"> <pane>
<el-card :body-style="{ height: '100%' }"> <el-card :body-style="{ height: '100%' }">
<el-form ref="formRef" :rules="rules" :model="form" label-width="120px" label-position="right"> <el-form ref="formRef" :rules="rules" :model="form" label-width="120px" label-position="right">
<el-divider> <el-divider>
@@ -34,55 +36,76 @@
</el-divider> </el-divider>
<el-row> <el-row>
<el-col :span="10"> <el-col :span="10">
<el-form-item label="部门ID" prop="id"> <el-input v-model="form.id" disabled /> </el-form-item> <el-form-item label="部门ID" prop="id">
<el-input v-model="form.id" disabled/>
</el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item label="父级部门ID" prop="parent"> <el-input v-model="form.parent" /> </el-form-item> <el-form-item label="父级部门ID" prop="parent">
<el-input v-model="form.parent"/>
</el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item required label="部门名称" prop="name"> <el-input v-model="form.name" /> </el-form-item> <el-form-item required label="部门名称" prop="name">
<el-input v-model="form.name"/>
</el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item required label="部门标识" prop="key"> <el-input v-model="form.key" /> </el-form-item> <el-form-item required label="部门标识" prop="key">
<el-input v-model="form.key"/>
</el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item label="负责人" prop="owner"> <el-input v-model="form.owner" /> </el-form-item> <el-form-item label="负责人" prop="owner">
<el-input v-model="form.owner"/>
</el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item label="联系电话" prop="phone"> <el-input v-model="form.phone" /> </el-form-item> <el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone"/>
</el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item label="邮箱" prop="email"> <el-input v-model="form.email" /> </el-form-item> <el-form-item label="邮箱" prop="email">
<el-input v-model="form.email"/>
</el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item label="排序" prop="sort"> <el-form-item label="排序" prop="sort">
<el-input-number v-model="form.sort" controls-position="right" /> <el-input-number v-model="form.sort" controls-position="right"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col class="center"> <el-col class="center">
<el-divider> <el-divider>
<el-button @click="saveMenu()" type="primary" round>保存</el-button> <el-button @click="saveMenu()" type="primary" round>保存</el-button>
<el-button @click="newMenu()" type="success" round :disabled="!form.id">新建</el-button> <el-button @click="newMenu()" type="success" round :disabled="!form.id">新建
<el-button @click="addChildMenu()" type="info" round :disabled="!form.id">添加子级</el-button> </el-button>
<el-button @click="addSameLevelMenu()" type="warning" round :disabled="!form.id">添加</el-button> <el-button @click="addChildMenu()" type="info" round :disabled="!form.id">添加
<el-button @click="deleteMenu()" type="danger" round :disabled="!form.id">删除部门</el-button> </el-button>
<el-button @click="addSameLevelMenu()" type="warning" round :disabled="!form.id">
添加同级
</el-button>
<el-button @click="deleteMenu()" type="danger" round :disabled="!form.id">删除部门
</el-button>
</el-divider> </el-divider>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
</el-card> </el-card>
</el-col> </pane>
</el-row> </splitpanes>
</fs-page> </fs-page>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {Splitpanes, Pane} from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';
import * as api from './api'; import * as api from './api';
import {ElForm, ElMessageBox, ElTree, FormRules} from 'element-plus'; import {ElForm, ElMessageBox, ElTree, FormRules} from 'element-plus';
import { ref, onMounted, reactive, toRaw, watch } from 'vue'; import {ref, onMounted, reactive, toRaw, watch} from 'vue';
import XEUtils from 'xe-utils'; import XEUtils from 'xe-utils';
import { errorMessage, successMessage } from '../../../utils/message'; import {errorMessage, successMessage} from '../../../utils/message';
interface Tree { interface Tree {
id: number; id: number;
@@ -141,7 +164,7 @@ const loadNode = (node: Node, resolve: (data: Tree[]) => void) => {
// @ts-ignore // @ts-ignore
if (node.level !== 0) { if (node.level !== 0) {
// @ts-ignore // @ts-ignore
api.lazyLoadDept({ parent: node.data.id }).then((res: APIResponseData) => { api.lazyLoadDept({parent: node.data.id}).then((res: APIResponseData) => {
resolve(res.data); resolve(res.data);
}); });
} }
@@ -151,7 +174,7 @@ const nodeDrop = (draggingNode: Node, dropNode: Node, dropType: string, event: a
// @ts-ignore // @ts-ignore
if (!dropNode.isLeaf) { if (!dropNode.isLeaf) {
// @ts-ignore // @ts-ignore
api.dragMenu({ menu_id: draggingNode.data.id, parent_id: dropNode.data.id }).then((res: APIResponseData) => { api.dragMenu({menu_id: draggingNode.data.id, parent_id: dropNode.data.id}).then((res: APIResponseData) => {
successMessage(res.msg as string); successMessage(res.msg as string);
}); });
} }
@@ -175,8 +198,8 @@ const formRef = ref<InstanceType<typeof ElForm>>();
const rules = reactive<FormRules>({ const rules = reactive<FormRules>({
// @ts-ignore // @ts-ignore
name: [{ required: true, message: '部门名称必填', trigger: 'blur' }], name: [{required: true, message: '部门名称必填', trigger: 'blur'}],
key: [{ required: true, message: '部门标识必填', trigger: 'blur' }], key: [{required: true, message: '部门标识必填', trigger: 'blur'}],
}); });
const getData = () => { const getData = () => {

View File

@@ -1,53 +1,63 @@
<template> <template>
<fs-page> <fs-page>
<el-row class="mx-2"> <splitpanes>
<el-col :span="4" class="p-1"> <pane max-size="20" min-size="16" >
<el-card :body-style="{ height: '100%' }"> <el-card :body-style="{ height: '100%' }">
<p class="font-mono font-black text-center text-xl pb-5"> <p class="font-mono font-black text-center text-xl pb-5">
菜单列表 菜单列表
<el-tooltip effect="dark" :content="content" placement="right"> <el-tooltip effect="dark" :content="content" placement="right">
<el-icon> <el-icon>
<QuestionFilled /> <QuestionFilled/>
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
</p> </p>
<el-input v-model="filterText" :placeholder="placeholder" /> <el-input v-model="filterText" :placeholder="placeholder"/>
<el-tree ref="treeRef" class="font-mono font-bold leading-6 text-7xl" :data="data" :props="treeProps" <el-tree ref="treeRef" class="font-mono font-bold leading-6 text-7xl" :data="data"
:filter-node-method="filterNode" :load="loadNode" :allow-drag="allowDrag" :allow-drop="allowDrop" :props="treeProps"
:filter-node-method="filterNode" :load="loadNode" :allow-drag="allowDrag"
:allow-drop="allowDrop"
@node-drop="nodeDrop" lazy icon="ArrowRightBold" :indent="12" draggable @node-drop="nodeDrop" lazy icon="ArrowRightBold" :indent="12" draggable
@node-click="handleNodeClick"> @node-click="handleNodeClick">
<template #default="{ node, data }"> <template #default="{ node, data }">
<span v-if="data.status" class="text-center font-black text-xl"> <span v-if="data.status" class="text-center font-black text-xl">
<SvgIcon :name="node.data.icon" />&nbsp;{{ node.label }} <SvgIcon :name="node.data.icon"/>&nbsp;{{ node.label }}
</span> </span>
<span v-else class="text-center font-black text-xl text-red-700"> <span v-else class="text-center font-black text-xl text-red-700">
<SvgIcon :name="node.data.icon" />&nbsp;{{ node.label }} <SvgIcon :name="node.data.icon"/>&nbsp;{{ node.label }}
</span> </span>
</template> </template>
</el-tree> </el-tree>
</el-card> </el-card>
</el-col> </pane>
<el-col :span="6" class="p-1"> <pane min-size="30" >
<el-card :body-style="{ height: '100%' }"> <el-card :body-style="{ height: '100%' }">
<el-form ref="formRef" :rules="rules" :model="form" label-width="80px" label-position="right"> <el-form ref="formRef" :rules="rules" :model="form" label-width="80px"
<el-alert :title="content" type="success" effect="dark" :closable="false" center /> label-position="right">
<el-alert :title="content" type="success" effect="dark" :closable="false" center/>
<el-divider> <el-divider>
<strong>菜单配置</strong> <strong>菜单配置</strong>
</el-divider> </el-divider>
<el-form-item label="菜单ID" prop="id"> <el-input v-model="form.id" disabled /> <el-form-item label="菜单ID" prop="id">
<el-input v-model="form.id" disabled/>
</el-form-item> </el-form-item>
<el-form-item label="父级ID" prop="parent"> <el-input v-model="form.parent" /> </el-form-item> <el-form-item label="父级ID" prop="parent">
<el-form-item required label="菜单名称" prop="name"> <el-input v-model="form.name" /> <el-input v-model="form.parent"/>
</el-form-item>
<el-form-item required label="菜单名称" prop="name">
<el-input v-model="form.name"/>
</el-form-item> </el-form-item>
<el-form-item label="组件地址" prop="component"> <el-form-item label="组件地址" prop="component">
<el-autocomplete class="w-full" v-model="form.component" <el-autocomplete class="w-full" v-model="form.component"
:fetch-suggestions="querySearch" :trigger-on-focus="false" clearable debounce="100" :fetch-suggestions="querySearch" :trigger-on-focus="false"
placeholder="输入组件地址" /> clearable
debounce="100"
placeholder="输入组件地址"/>
</el-form-item> </el-form-item>
<el-form-item required label="Url" prop="web_path"> <el-input v-model="form.web_path" /> <el-form-item required label="Url" prop="web_path">
<el-input v-model="form.web_path"/>
</el-form-item> </el-form-item>
<el-form-item label="排序" prop="sort"> <el-form-item label="排序" prop="sort">
<el-input-number v-model="form.sort" controls-position="right" /> <el-input-number v-model="form.sort" controls-position="right"/>
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
@@ -62,35 +72,39 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="图标" prop="icon"> <el-form-item label="图标" prop="icon">
<IconSelector clearable v-model="form.icon" /> <IconSelector clearable v-model="form.icon"/>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-divider></el-divider> <el-divider></el-divider>
<div> <div>
<el-button @click="saveMenu()" type="primary" round>保存</el-button> <el-button @click="saveMenu()" type="primary" round>保存</el-button>
<el-button @click="newMenu()" type="success" round :disabled="!form.id">新建</el-button> <el-button @click="newMenu()" type="success" round :disabled="!form.id">新建</el-button>
<el-button @click="addChildMenu()" type="warning" round :disabled="!form.id">添加子级</el-button> <el-button @click="addChildMenu()" type="warning" round :disabled="!form.id">添加子级
<!-- <el-button @click="addSameLevelMenu()" type="warning" round>添加同级</el-button>--> </el-button>
<el-button @click="deleteMenu()" type="danger" round :disabled="!form.id">删除菜单</el-button> <!-- <el-button @click="addSameLevelMenu()" type="warning" round>添加同级</el-button>-->
<el-button @click="deleteMenu()" type="danger" round :disabled="!form.id">删除菜单
</el-button>
</div> </div>
</el-card> </el-card>
</el-col> </pane>
<el-col :span="14" class="p-1"> <pane min-size="30">
<el-card :body-style="{ height: '100%' }" > <el-card :body-style="{ height: '100%' }">
<menuButton :select-menu="form" /> <menuButton :select-menu="form"/>
</el-card> </el-card>
</el-col> </pane>
</el-row> </splitpanes>
</fs-page> </fs-page>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {Splitpanes, Pane} from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';
import * as api from './api'; import * as api from './api';
import * as menuButoonApi from './components/menuButton/api'; import * as menuButoonApi from './components/menuButton/api';
import { ElForm, ElTree, FormRules,ElMessageBox } from 'element-plus'; import {ElForm, ElTree, FormRules, ElMessageBox} from 'element-plus';
import { ref, onMounted, watch, reactive, toRaw, defineAsyncComponent, nextTick, shallowRef } from 'vue'; import {ref, onMounted, watch, reactive, toRaw, defineAsyncComponent, nextTick, shallowRef} from 'vue';
import XEUtils from 'xe-utils'; import XEUtils from 'xe-utils';
import { errorMessage, successMessage } from '../../../utils/message'; import {errorMessage, successMessage} from '../../../utils/message';
interface Tree { interface Tree {
id: number; id: number;
@@ -159,7 +173,7 @@ const loadNode = (node: Node, resolve: (data: Tree[]) => void) => {
// @ts-ignore // @ts-ignore
if (node.level !== 0) { if (node.level !== 0) {
// @ts-ignore // @ts-ignore
api.lazyLoadMenu({ parent: node.data.id }).then((res: APIResponseData) => { api.lazyLoadMenu({parent: node.data.id}).then((res: APIResponseData) => {
resolve(res.data); resolve(res.data);
}); });
} }
@@ -187,7 +201,7 @@ const nodeDrop = (draggingNode: Node, dropNode: Node, dropType: string, event: a
// @ts-ignore // @ts-ignore
if (!dropNode.isLeaf) { if (!dropNode.isLeaf) {
// @ts-ignore // @ts-ignore
api.dragMenu({ menu_id: draggingNode.data.id, parent_id: dropNode.data.id }).then((res: APIResponseData) => { api.dragMenu({menu_id: draggingNode.data.id, parent_id: dropNode.data.id}).then((res: APIResponseData) => {
successMessage(res.msg as string); successMessage(res.msg as string);
}); });
} }
@@ -250,7 +264,7 @@ const createFilter = (queryString: string) => {
const rules = reactive<FormRules>({ const rules = reactive<FormRules>({
// @ts-ignore // @ts-ignore
web_path: [{ validator: validateWebPath, trigger: 'blur' }], web_path: [{validator: validateWebPath, trigger: 'blur'}],
}); });
const getData = () => { const getData = () => {