目录
效果
-
el-button 的 icon及text有所改变
-
table 的 template有所改变
-
el-pagination写法注意
-
引入子组件写法参照博主其他文章
主页面(父组件)
- 没法讲解了,看代码吧
- 请求接口+分页的逻辑经过时间验证
<template>
<div class="table-all-body">
<div class="content-nav-title">
<div class="content-nav-title-con">
<span>菜单管理</span>
</div>
</div>
<div class="content-box-bg">
<div class="overall-handle-box">
<el-select filterable v-model="data.now_name" style="width:300px;" @change="systemFlagChange">
<el-option v-for="item in data.systemFlags" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
<el-button class="margin-left12" :icon="CirclePlus" type="primary" @click="addRole">添加菜单</el-button>
</div>
<div class="table-body-height-common">
<el-table border :data="data.historyData" row-key="id">
<template slot="empty">
<p>{{data.dataText}}</p>
</template>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column label="图标" width="80">
<template #default="scope">
<i :class="scope.row.icon"></i>
</template>
</el-table-column>
<el-table-column label="菜单类型" width="120">
<template #default="scope">
<span v-if="scope.row.type=='1'">菜单</span>
<span v-if="scope.row.type=='2'">按钮</span>
<span v-if="scope.row.type=='0'">目录</span>
</template>
</el-table-column>
<el-table-column prop="flag" label="分类" width="80"></el-table-column>
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column label="路由" width="130">
<template #default="scope">
{{scope.row.url==''?'—':scope.row.url}}
</template>
</el-table-column>
<el-table-column label="授权标识" width="300" show-overflow-tooltip>
<template #default="scope">
{{scope.row.perms==''?'—':scope.row.perms}}
</template>
</el-table-column>
<el-table-column label="操作" width="170">
<template #default="scope">
<el-button @click="handleClick(scope.row)" link size="small" type="primary">编辑</el-button>
<el-button @click="deleteCommon(scope.row)" link type="danger" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination v-model:currentPage="data.curPage" v-model:page-size="data.pageSize"
:page-sizes="[5,10, 20, 30, 40]" :small="data.small" layout="total, jumper, prev, pager, next, sizes"
:total="data.dataCount" @size-change="handleSizeChange" @current-change="changepage"
class="page-position-common" />
</div>
<addMenuPage v-on:onItemChange="getAllDatas" ref="addMenu"></addMenuPage>
</div>
</template>
<script lang="ts" setup>
import addMenuPage from "./children/addMenu.vue";
import {
ElMessage
} from "element-plus";
import {
CirclePlus
} from '@element-plus/icons-vue'
import {
menuList,
menuDelete
} from "../../request/api.js";
import {
ref,
reactive,
onMounted,
} from 'vue';
const addMenu = ref(); //ref方法是让我们的简单类型数据变成响应式数据;在方法里改变时需要.value来获取
interface User {
icon: string
type: string
flag: string
orderNum: string
url: string
perms: string
id: string
}
// reactive 数据双向绑定;让我们的复杂类型数据变成响应式数据;不需要.value来获取
const data = reactive({
dataText: "", //表格开始置空
dataCount: 0, //共几条
pageSize: 10, // 每页显示多少条
curPage: 1, //第几页
now_name: "",
systemFlags: [{
name: '集约式直饮水智能售水系统',
id: 'water'
}, {
name: '污染源在线监测平台',
id: 'pollution'
}, {
name: '原位实时水质自动监测系统',
id: 'site'
}, {
name: '地表水数字化监测信息管理系统',
id: 'digitalRiver'
}, {
name: '农村污水处理站运行动态管控系统',
id: 'ruralSewage'
}, {
name: '超标废水应急自动拦截系统',
id: 'interception'
}, {
name: '饮用水安全在线监管系统',
id: 'dwp'
}, {
name: 'DR303C',
id: 'DR303C'
}],
historyData: [], //回显到表格的数据
small: false,
});
//获取初始数据
onMounted(() => {
if (localStorage.getItem("systemFlag") == undefined) {
data.now_name = data.systemFlags[0].id;
} else {
data.now_name = localStorage.getItem("systemFlag") || '';
};
getAllDatas()
});
const systemFlagChange = (val: string) => {
localStorage.setItem("systemFlag", val)
getAllDatas();
};
//表格初始查询
const getAllDatas = () => {
data.dataText = "";
data.historyData = [];
data.curPage = 1;
getAllListLink();
};
//获取表格列表数据
const getAllListLink = () => {
let params = {
systemFlag: data.now_name,
pageNum: data.curPage,
pageSize: data.pageSize,
}
menuList(params).then(res => {
if (res.code == 0) {
data.dataCount = res.data.total
if (res.data.total != 0) {
data.historyData = res.data.list;
} else {
data.dataText = "暂无数据";
}
} else if (res.code !== 0) {
data.dataText = "暂无数据";
ElMessage({
showClose: true,
message: res.msg,
type: 'error',
})
}
})
};
//分页改变
const changepage = (index: number) => {
data.curPage = index;
getAllListLink();
};
//每页条数切换
const handleSizeChange = (val: number) => {
data.curPage = 1;
data.pageSize = val;
getAllListLink();
};
//删除-接口
const deleteCommon = (row: User) => {
let params = {
id: row.id
}
menuDelete(params)
.then(res => {
if (res.code == 0) {
ElMessage({
showClose: true,
message: '操作成功',
type: 'success',
})
getAllDatas();
} else if (res.code !== 0) {
ElMessage({
showClose: true,
message: res.msg,
type: 'error',
})
}
})
};
//添加
const addRole = () => {
addMenu.value.addItemShow(data.now_name)
};
//编辑
const handleClick = (row: User) => {
addMenu.value.addItemShow2(row, data.now_name)
};
</script>
<style scoped>
</style>
子页面
展现
注意:
- defineExpose 注意暴露!!
- el-dialog 需要v-model
- form 的 ref="ruleFormRef" :rules="rules" :model="ruleForm"
-
onSubmit(ruleFormRef)
-
import type { FormInstance } from 'element-plus'编辑器插件版本过高会报错,我直接注释了,等待再次升级!
-
as any[]注意他的使用
-
nextTick的使用
-
push的使用
-
表单验证
源代码:
<template>
<div>
<el-dialog :title="data.titleName" v-model="data.children_page" :close-on-click-modal='false'
:append-to-body='true' width="800px">
<el-form ref="ruleFormRef" :rules="rules" :model="ruleForm" label-width="150px">
<el-form-item v-if="data.isAdd" label="所属系统:" prop="system">
<el-select v-model="ruleForm.system" @change="changeSystem" placeholder="请选择" style="width:300px;">
<el-option v-for="item in data.systems" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="角色分类:" prop="type">
<el-select v-model="ruleForm.type" style="width:300px;">
<el-option v-for="item in data.types" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="角色名称:" prop="name">
<el-input v-model.trim="ruleForm.name" style="width:300px;" />
</el-form-item>
<el-form-item label="角色字符:" prop="key">
<el-input v-model.trim="ruleForm.key" style="width:300px;" /> ( 定义角色唯一性 )
</el-form-item>
<el-form-item label="菜单配置:">
<div class="jurisdiction-border">
<el-tree show-checkbox :data="data.treeDatas" node-key="id" ref="treeRef" :check-strictly="true"
:default-checked-keys="data.nowKeys">
<template #default="{ node, data }">
<span class="custom-tree-node">
<span v-if="data.type == 0||data.type == 1">
<el-tag :type="data.flag=='app'?'success':''" size="small"> {{data.flag=='app'?'app-菜单':'pc-菜单'}}
</el-tag>
<span :title="data.name" class='tree-name-leave'> {{data.name}} </span>
</span>
<span v-else>
<el-tag type="warning" size="small"> {{data.flag}}-按钮 </el-tag>
<span :title="data.name" class='tree-name-leave'> {{data.name}} </span>
</span>
</span>
</template>
</el-tree>
</div>
</el-form-item>
<el-form-item>
<el-button @click="data.children_page = false">取 消</el-button>
<el-button type="primary" @click="onSubmit(ruleFormRef)">确 定</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import {
roleInsert,
roleUpdate,
menuAll,
menuRole
} from "../../../request/api.js";
import {
ElMessage,
ElTree
} from "element-plus";
// import type { FormInstance } from 'element-plus'
import {
ref,
reactive,
nextTick,
// defineProps,//defineProps声明props;具备完整的类型推断;<script setup>直接可用
// defineEmits,//defineEmits声明事件;具备完整的类型推断;<script setup>直接可用
// defineExpose//暴露出去;<script setup>直接可用
} from 'vue';
const ruleFormRef = ref();//表单ref
//获取tree选中的值
const treeRef = ref < InstanceType < typeof ElTree >> ();
const emit = defineEmits(["onItemChange"]);//声明事件(父级页面上添加的 @监听事件)
//数据双向绑定;复杂类型数据=>响应式数据
const data = reactive({
titleName: '',
checkAll: false,
children_page: false,
isAdd: false,
systems: [{
name: '集约式直饮水智能售水系统',
id: 'water'
}, {
name: '污染源在线监测平台',
id: 'pollution'
}, {
name: '原位实时水质自动监测系统',
id: 'site'
}, {
name: '地表水数字化监测信息管理系统',
id: 'digitalRiver'
}, {
name: '农村污水处理站运行动态管控系统',
id: 'ruralSewage'
}, {
name: '超标废水应急自动拦截系统',
id: 'interception'
}, {
name: '饮用水安全在线监管系统',
id: 'dwp'
}, {
name: 'DR303C',
id: 'DR303C'
}],
types: [{
name: '系统',
id: 'system'
}, {
name: '运维',
id: 'operational'
}, {
name: '客户',
id: 'customer'
}, {
name: '普通用户',
id: 'common'
}],
nowKeys: [] as any[], // 属性需要做类型断言处理 //树-选中数据
treeDatas: [], //树-总数据
id: '',
});
//ts类型断言
//定义类型
interface User {
name: string
type: string
key: string
id: string
};
const ruleForm = reactive({
system: "",
type: "",
name: "",
key: "",
});
const rules = ref({
name: [{
required: true,
message: '请输入角色名称',
trigger: 'blur'
},
{
min: 1,
max: 50,
message: '长度在 1 到 50 个字符',
trigger: 'blur'
}
],
key: [{
required: true,
message: '请输入角色字符',
trigger: 'blur'
},
{
min: 1,
max: 50,
message: '长度在 1 到 50 个字符',
trigger: 'blur'
}
],
system: [{
required: true,
message: '请选择所属系统',
trigger: 'change'
}],
});
//父调子的子
const addItemShow = (now_name: string) => {
data.titleName = '添加角色';
data.children_page = true;
data.isAdd = true;
ruleForm.system = now_name;
ruleForm.type = '';
data.nowKeys = []; //树-选中数据
getTree();
nextTick(() => {
ruleFormRef.value.resetFields();//重置表单
})
};
//父调子的子
const addItemShow2 = (row: User, now_name: string) => {
data.titleName = '编辑角色';
data.children_page = true;
data.isAdd = false;
nextTick(() => {
ruleFormRef.value.resetFields();//重置表单
ruleForm.name = row.name;
ruleForm.key = row.key;
ruleForm.system = now_name;
ruleForm.type = row.type;
data.id = row.id;
data.nowKeys = [] //树-选中数据
data.treeDatas = [] //树-总数据
menuRoleGet()
})
};
//回显树-选中数据
const menuRoleGet = () => {
let params = {
id: data.id,
}
menuRole(params).then(res => {
if (res.code == 0) {
if (res.data.list.length != 0) {
for (var i in res.data.list) {
data.nowKeys.push(res.data.list[i].id)
}
}
getTree()
} else if (res.code !== 0) {
ElMessage.error(res.msg);
}
})
};
//改变系统时=>获取树数据
const changeSystem = () => {
getTree();
};
//获取树数据
const getTree = () => {
data.treeDatas = [];
let params = {
systemFlag: ruleForm.system,
}
menuAll(params).then(res => {
if (res.code == 0) {
data.treeDatas = res.data.list
} else if (res.code !== 0) {
ElMessage.error(res.msg);
}
})
};
//添加/修改 : FormInstance | undefined
const onSubmit = async (formEl) => {
if (!formEl) return
formEl.validate((valid) => {
if (valid) {
if (data.isAdd) {
addRoles();
} else {
changeRoles();
}
} else {
return false;
}
});
};
//添加接口
const addRoles = () => {
let params = {
systemFlag: ruleForm.system,
name: ruleForm.name,
key: ruleForm.key,
type: ruleForm.type,
menuIds: treeRef.value!.getCheckedKeys(false),
}
roleInsert(params).then(res => {
if (res.code == 0) {
ElMessage({
showClose: true,
message: '操作成功',
type: 'success',
})
data.children_page = false;
emit("onItemChange");
} else if (res.code !== 0) {
ElMessage.error(res.msg);
}
})
};
//修改接口
const changeRoles = () => {
let params = {
id: data.id,
name: ruleForm.name,
key: ruleForm.key,
type: ruleForm.type,
menuIds: treeRef.value!.getCheckedKeys(false),
}
roleUpdate(params).then(res => {
if (res.code == 0) {
ElMessage({
showClose: true,
message: '操作成功',
type: 'success',
})
data.children_page = false;
emit("onItemChange");
} else if (res.code !== 0) {
ElMessage.error(res.msg);
}
})
};
defineExpose({
addItemShow,
addItemShow2
}) //将子组件方法暴露出来,让父组件调用
</script>
<style scoped>
.jurisdiction-border {
width: 500px;
height: 300px;
padding: 10px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
overflow: auto;
}
.jurisdiction-border::-webkit-scrollbar {
width: 7px;
height: 7px;
background-color: rgb(241, 241, 241);
border-radius: 3px;
}
.jurisdiction-border::-webkit-scrollbar-thumb {
background-color: rgb(193, 193, 193);
border-radius: 3px;
}
.tree-name-leave {
margin-leave: 5px;
}
</style>