# 一、分析权限分配界面并初步实现界面
控制器 app/controller/admin/manager.js
//创建管理员---创建页面表单
async create() {
...
let data = [
{ id: 1, pid: 0, name: '网站', icon: 'fa fa-chrome', url: '' },
{ id: 2, pid: 1, name: '主面板', icon: 'fa fa-pie-chart', url: '/admin' },
{ id: 3, pid: 1, name: '管理员', icon: 'fe fe-user-plus', url: '/admin/manager/index' },
{ id: 4, pid: 1, name: '留言板', icon: 'fe fe-document', url: '/admin/message/index' },
{ id: 5, pid: 1, name: '分类管理', icon: 'fa fa-list', url: '/admin/category/index' },
{ id: 6, pid: 1, name: '新闻内容管理', icon: 'fa fa-file-text-o', url: '/admin/news/index' },
{ id: 7, pid: 1, name: '配置管理', icon: 'fa fa-wrench', url: '/admin/config/index' },
{ id: 8, pid: 0, name: '直播', icon: 'fa fa-video-camera', url: '' },
{ id: 9, pid: 8, name: '直播用户', icon: 'fa fa-venus-mars', url: '/admin/liveuser/index' },
{ id: 10, pid: 8, name: '直播礼物管理', icon: 'fa fa-gift', url: '/admin/livegift/index' },
{ id: 11, pid: 8, name: '直播订单管理', icon: 'fa fa-credit-card', url: '/admin/liveorder/index' },
{ id: 12, pid: 8, name: '直播间管理', icon: 'fa fa-tv', url: '/admin/live-/index' },
];
data = this.app.transformToTree(data);
// console.log('处理之后的data', JSON.stringify(data));
// return;
//渲染公共模版
await ctx.renderTemplate({
...
form: {
...
// 字段
fields: [
...
{
label: '权限分配',
type: 'treeDataSelect', //树形结构数据选择
name: 'auth',
default: JSON.stringify(data),
},
],
},
...
});
}
模版 app/view/admin/layout/_form.html
{# 定义一个可递归调用的子模板 #}
{% macro renderMenu(items,keyname) %}
{% for item in items %}
<span class="dropdown-item" style="margin-left: {{item.level * 20}}px;
cursor: pointer;background:none;"
onmouseover="this.style.color = '#000000';this.style.fontWeight = 800;"
onmouseout="this.style.color = '#002222';this.style.fontWeight = 'normal';"
@click="dropdownItemClick('{{keyname}}','{{item.name}}','{{item.id}}')">
<input type="checkbox" name="{{keyname}}" style="margin-right: 10px;">{{item.name}}</span>
...
{# 如果是树形结构数据选择 #}
{% elif item.type == 'treeDataSelect' %}
{# 使用定义好的子模板递归渲染菜单 #}
<!-- 在上面的代码块之前或之外的合适位置,提前解析item.default为JSON对象 -->
{% set itemDefaultParsed = item.default | safe | fromJson %}
{% call renderMenu(itemDefaultParsed,item.name) %}
{% endcall %}
# 二、权限id集合写进数据库
# 1、迁移文件、模型文件、数据库管理员表新增 权限字段 auth
auth:{
type: STRING(255),
allowNull: true,
defaultValue:'',
comment: '权限id'
},
# 2、控制器 app/controller/admin/manager.js
//创建管理员提交数据
async save() {
...
//1.参数验证
this.ctx.validate({
...
auth: {
type: 'string',
required: false,
defValue: '',
desc: '权限id集合'
},
});
...
}
# 3、 模版 app/view/admin/layout/_form.html
{# 定义一个可递归调用的子模板 #}
{% macro renderMenu(items,keyname,type) %}
{% for item in items %}
<span class="dropdown-item" style="margin-left: {{item.level * 20}}px;
cursor: pointer;background:none;"
onmouseover="this.style.color = '#000000';this.style.fontWeight = 800;"
onmouseout="this.style.color = '#002222';this.style.fontWeight = 'normal';"
@click="dropdownItemClick('{{keyname}}','{{item.name}}','{{item.id}}')">
{% if type == 'treeDataSelect' %}
<input type="checkbox" name="{{keyname}}" style="margin-right: 10px;" class="checkbox-{{keyname}}"
@click.stop="treeDataSelectClick('{{keyname}}','{{item.name}}','{{item.id}}','checkbox-{{keyname}}',$event)"
data="{{item.id}}">
{% endif %}
{{item.name}}
</span>
{# 检查是否存在子菜单项 #}
{% if item.children and item.children.length %}
<div class="dropdown-submenu">
{% call renderMenu(item.children,keyname,type) %}
{# 这里通过调用macro自身实现了递归 #}
{% endcall %}
</div>
{% endif %}
{% endfor %}
{% endmacro %}
...
{# 如果是下拉框类型 #}
<div class="dropdown">
<button type="button" class="btn dropdown-toggle dropdown-{{item.name}}" data-toggle="dropdown" id="dropdownData">
{{item.placeholder if item.placeholder else '一级分类'}}
</button>
<div class="dropdown-menu">
<h5 class="dropdown-header">请选择要放在哪个分类下</h5>
<div class="dropdown-divider"></div>
{# 使用定义好的子模板递归渲染菜单 #}
<!-- 在上面的代码块之前或之外的合适位置,提前解析item.default为JSON对象 -->
{% set itemDefaultParsed = item.default | safe | fromJson %}
{% call renderMenu(itemDefaultParsed,item.name,item.type) %}
{% endcall %}
</div>
</div>
...
{# 如果是树形结构数据选择 #}
{% elif item.type == 'treeDataSelect' %}
{# 使用定义好的子模板递归渲染菜单 #}
<!-- 在上面的代码块之前或之外的合适位置,提前解析item.default为JSON对象 -->
{% set itemDefaultParsed = item.default | safe | fromJson %}
{% call renderMenu(itemDefaultParsed,item.name,item.type) %}
{% endcall %}
{% else %}
...
<script>
Vueapp = new Vue({
...
//树形结构数据点击多选框
treeDataSelectClick(keyname,name,id,classname,e){
// console.log('keyname', keyname);
// console.log('name', name);
// console.log('id', id);
// console.log('classname', classname);
// console.log('e事件对象', e);
// 选中上一级下一级所有都选中
// console.log($(e.target).parent().parent().attr('class'));
if($(e.target).parent().parent().attr('class') != 'dropdown-submenu'){
let checkbox = $(e.target).parent().next().find('input[type="checkbox"]');
if($(e.target).is(':checked')){
checkbox.prop('checked',true);
}else{
checkbox.prop('checked',false);
}
}else{
//下一级全部选中时候,上一级选中
let all = $(e.target).parent().parent().find('input[type="checkbox"]').length;
let len = $(e.target).parent().parent().find('input[type="checkbox"]:checked').length;
console.log('多少input',all);
console.log('选中多少input',len);
if(all == len){
$(e.target).parent().parent().prev().find('input[type="checkbox"]').prop('checked',true);
}else{
$(e.target).parent().parent().prev().find('input[type="checkbox"]').prop('checked',false);
}
}
//读取选中的值
// console.log($(`input[name=${keyname}]:checked`).length);
let arr = [];
$(`input[name=${keyname}]:checked`).each(function(index,ele){
// console.log($(ele).attr('data'));
arr.push(parseInt($(ele).attr('data')));
});
console.log('获取到的id集合',arr);
this.form[keyname] = arr.join(',');
}
});
</script>
# 三、后台根据权限id显示相应管理栏目
# 1. 创建json文件(推荐),也可以写入数据库,展示后台管理栏目
data/root.json
[
{"id":1,"pid":0, "name": "网站", "icon": "fa fa-chrome", "url": ""},
{"id":2,"pid":1, "name": "主面板", "icon": "fa fa-pie-chart", "url": "/admin" },
{"id":3,"pid":1, "name": "管理员", "icon": "fe fe-user-plus", "url": "/admin/manager/index" },
{"id":4,"pid":1, "name": "留言板", "icon": "fe fe-document", "url": "/admin/message/index" },
{"id":5,"pid":1, "name": "分类管理", "icon": "fa fa-list", "url": "/admin/category/index" },
{"id":6,"pid":1, "name": "新闻内容管理", "icon": "fa fa-file-text-o", "url": "/admin/news/index" },
{"id":7,"pid":1, "name": "配置管理", "icon": "fa fa-wrench", "url": "/admin/config/index" },
{"id":8,"pid":0, "name": "直播","icon": "fa fa-video-camera", "url": ""},
{"id":9,"pid":8, "name": "直播用户", "icon": "fa fa-venus-mars", "url": "/admin/liveuser/index" },
{"id":10,"pid":8, "name": "直播礼物管理", "icon": "fa fa-gift", "url": "/admin/livegift/index" },
{"id":11,"pid":8, "name": "直播订单管理", "icon": "fa fa-credit-card", "url": "/admin/liveorder/index" },
{"id":12,"pid":8, "name": "直播间管理", "icon": "fa fa-tv", "url": "/admin/live-/index" },
{"id":13,"pid":1, "name": "网站公告管理", "icon": "fa fa-tv", "url": "xxxx" }
]
# 2.读取json文件栏目菜单
控制器 app/controller/admin/manager.js
const fs = require('node:fs');
//创建管理员---创建页面表单
async create() {
const { ctx } = this;
// await ctx.render('admin/manager/create.html');
// let data = [
// { id: 1, pid: 0, name: '网站', icon: 'fa fa-chrome', url: '' },
// { id: 2, pid: 1, name: '主面板', icon: 'fa fa-pie-chart', url: '/admin' },
// { id: 3, pid: 1, name: '管理员', icon: 'fe fe-user-plus', url: '/admin/manager/index' },
// { id: 4, pid: 1, name: '留言板', icon: 'fe fe-document', url: '/admin/message/index' },
// { id: 5, pid: 1, name: '分类管理', icon: 'fa fa-list', url: '/admin/category/index' },
// { id: 6, pid: 1, name: '新闻内容管理', icon: 'fa fa-file-text-o', url: '/admin/news/index' },
// { id: 7, pid: 1, name: '配置管理', icon: 'fa fa-wrench', url: '/admin/config/index' },
// { id: 8, pid: 0, name: '直播', icon: 'fa fa-video-camera', url: '' },
// { id: 9, pid: 8, name: '直播用户', icon: 'fa fa-venus-mars', url: '/admin/liveuser/index' },
// { id: 10, pid: 8, name: '直播礼物管理', icon: 'fa fa-gift', url: '/admin/livegift/index' },
// { id: 11, pid: 8, name: '直播订单管理', icon: 'fa fa-credit-card', url: '/admin/liveorder/index' },
// { id: 12, pid: 8, name: '直播间管理', icon: 'fa fa-tv', url: '/admin/live-/index' },
// ];
let data = fs.readFileSync('./data/root.json', {
encoding: 'utf-8'
});
data = this.app.transformToTree(JSON.parse(data));
// console.log('处理之后的data', JSON.stringify(data));
// return;
...
}
菜单中间件 app/middleware/admin_menu.js
module.exports = (option, app) => {
return async function adminMenu(ctx, next) {
// let menus = [
// {id:1,pid:0, name: '网站', icon: 'fa fa-chrome', url: '' },
// {id:2,pid:1, name: '主面板', icon: 'fa fa-pie-chart', url: '/admin' },
// {id:3,pid:1, name: '管理员', icon: 'fe fe-user-plus', url: '/admin/manager/index' },
// {id:4,pid:1, name: '留言板', icon: 'fe fe-document', url: '/admin/message/index' },
// {id:5,pid:1, name: '分类管理', icon: 'fa fa-list', url: '/admin/category/index' },
// {id:6,pid:1, name: '新闻内容管理', icon: 'fa fa-file-text-o', url: '/admin/news/index' },
// {id:7,pid:1, name: '配置管理', icon: 'fa fa-wrench', url: '/admin/config/index' },
// {id:8,pid:0, name: '直播', icon: 'fa fa-video-camera', url: '' },
// {id:9,pid:8, name: '直播用户', icon: 'fa fa-venus-mars', url: '/admin/liveuser/index' },
// {id:10,pid:8, name: '直播礼物管理', icon: 'fa fa-gift', url: '/admin/livegift/index' },
// {id:11,pid:8, name: '直播订单管理', icon: 'fa fa-credit-card', url: '/admin/liveorder/index' },
// {id:12,pid:8, name: '直播间管理', icon: 'fa fa-tv', url: '/admin/live-/index' },
// ];
let menus = fs.readFileSync('./data/root.json', {
encoding: 'utf-8'
});
menus = JSON.parse(menus);
//根据权限显示菜单:普通管理员的处理
console.log('管理员信息', ctx.session.auth);
if (ctx.session.auth.super != 1) {
if (!ctx.session.auth.auth) {
menus = [{ id: 2, pid: 1, name: '主面板', icon: 'fa fa-pie-chart', url: '/admin' }];
} else {
// 根据权限分配管理栏目
const ids = ctx.session.auth.auth;
const selectedIds = ids.split(',').map(id => parseInt(id));
let result = [];
for(let i=0;i<selectedIds.length;i++){
let id = selectedIds[i];
for(let j=0;j<menus.length;j++){
if(menus[j].id == id){
result.push(menus[j]);
}
}
}
console.log('最终结果', result);
menus = result;
}
}
// 和我们分页模版类似,通过ctx.locals对象挂载代码
...
}
}
模版 app/view/admin/layout/_form.html方法进一步调整
treeDataSelectClick(keyname,name,id,classname,e){
// console.log('keyname', keyname);
// console.log('name', name);
// console.log('id', id);
// console.log('classname', classname);
// console.log('事件对象', e);
// 选中上一级下一级所有都选中
// console.log('父级class', $(e.target).parent().parent().attr('class'));
if($(e.target).parent().parent().attr('class') != 'dropdown-submenu'){
let checkbox = $(e.target).parent().next().find('input[type="checkbox"]');
if($(e.target).is(':checked')){
checkbox.prop('checked',true).attr('select',1);
}else{
checkbox.prop('checked',false).attr('select',0);
}
// 设置自己的select
if($(e.target).is(':checked')){
$(e.target).attr('select',1);
}else{
$(e.target).attr('select',0);
}
}else{
//每个级别下的所有多选框数量
let all = $(e.target).parent().parent().find('input[type="checkbox"]').length;
//当前这个级别下面选了多少个框了
let len = $(e.target).parent().parent().find('input[type="checkbox"]:checked').length;
// console.log('当前级别总共多少框',all);
// console.log('当前级别选了多少框',len);
if(all == len){
$(e.target).parent().parent().prev().find('input[type="checkbox"]')
.prop('checked',true).attr('select',1);
}else{
$(e.target).parent().parent().prev().find('input[type="checkbox"]')
.prop('checked',false).attr('select',1);
}
// 设置自己的select
if($(e.target).is(':checked')){
$(e.target).attr('select',1);
}else{
$(e.target).attr('select',0);
}
//如果一个没选
if(len == 0){
$(e.target).parent().parent().prev().find('input[type="checkbox"]')
.prop('checked',false).attr('select',0);
}
}
//选取选中的值
// console.log('选取框的长度', $(`input[name=${keyname}]:checked`).length);
let arr = [];
// $(`input[name=${keyname}]:checked`).each(function(index,element){
// console.log($(element).attr('data'));
// arr.push(parseInt($(element).attr('data')));
// });
$(`input[name=${keyname}]`).each(function(index,element){
console.log('select的情况', $(element).attr('select'));
if($(element).attr('select') == 1){
arr.push(parseInt($(element).attr('data')));
}
});
// console.log('获取权限的id值集合数据',arr);
console.log('写进数据库数据',arr.join(','));
this.form[keyname] = arr.join(',');
}
# 四、管理员根据所分配的权限访问对应栏目,否则无权访问
菜单中间件 app/middleware/admin_menu.js
const fs = require('node:fs');
module.exports = (option, app) => {
return async function adminMenu(ctx, next) {
console.log('菜单中间件');
// let menus = [
// {id:1,pid:0, name: '网站', icon: 'fa fa-chrome', url: '' },
// {id:2,pid:1, name: '主面板', icon: 'fa fa-pie-chart', url: '/admin' },
// {id:3,pid:1, name: '管理员', icon: 'fe fe-user-plus', url: '/admin/manager/index' },
// {id:4,pid:1, name: '留言板', icon: 'fe fe-document', url: '/admin/message/index' },
// {id:5,pid:1, name: '分类管理', icon: 'fa fa-list', url: '/admin/category/index' },
// {id:6,pid:1, name: '新闻内容管理', icon: 'fa fa-file-text-o', url: '/admin/news/index' },
// {id:7,pid:1, name: '配置管理', icon: 'fa fa-wrench', url: '/admin/config/index' },
// {id:8,pid:0, name: '直播', icon: 'fa fa-video-camera', url: '' },
// {id:9,pid:8, name: '直播用户', icon: 'fa fa-venus-mars', url: '/admin/liveuser/index' },
// {id:10,pid:8, name: '直播礼物管理', icon: 'fa fa-gift', url: '/admin/livegift/index' },
// {id:11,pid:8, name: '直播订单管理', icon: 'fa fa-credit-card', url: '/admin/liveorder/index' },
// {id:12,pid:8, name: '直播间管理', icon: 'fa fa-tv', url: '/admin/live-/index' },
// ];
let menus = fs.readFileSync('./data/root.json', {
encoding: 'utf-8'
});
menus = JSON.parse(menus);
//根据权限显示菜单:普通管理员的处理
// console.log('管理员信息', ctx.session.auth);
if (ctx.session.auth.super != 1) {
if (!ctx.session.auth.auth) {
// menus = [{id:2,pid:1, name: '主面板', icon: 'fa fa-pie-chart', url: '/admin' }];
// return ctx.pageFail('没有权限访问后台管理',500);
return ctx.apiFail('没有权限访问后台管理', 500);
} else {
const ids = ctx.session.auth.auth;
const selectedIds = ids.split(',').map(id => parseInt(id));
// console.log('selectedIds', selectedIds);
let result = [];
for (let i = 0; i < selectedIds.length; i++) {
let id = selectedIds[i];
for (let j = 0; j < menus.length; j++) {
if (menus[j].id == id) {
result.push(menus[j]);
}
}
}
// console.log('最终结果',result);
menus = result;
// 权限判断
let arr = result.map(item=>item.url && item.url.replace('/index', ''));
arr = arr.filter(item=>item.length);
arr.push('/admin/logout');//任何管理员都可以退出
console.log('arr',arr);
if(ctx.request.url == '/admin'){
if(!arr.includes('/admin')){
return ctx.apiFail('没有权限访问该内容', 500);
}
}else{
arr = arr.filter(item=>item != '/admin');
console.log('新的arr',arr);
let flag = false;
for (let i = 0; i < arr.length; i++) {
if(ctx.request.url.startsWith(arr[i])){
flag = true;
break;
}
}
if(!flag){
return ctx.apiFail('没有权限访问该内容', 500);
}
}
}
}
// 和我们分页模版类似,通过ctx.locals对象挂载代码
ctx.locals.menus = menus.map(item => {
// console.log('当前请求地址', ctx.request.url)
// console.log('遍历项地址', item.url)
let baseURL = item.url.replace('/index', '');
// console.log('处理之后遍历项地址', baseURL);
// console.log('判断',ctx.request.url.startsWith(baseURL));
if ((ctx.request.url == '/admin' && item.url == '/admin') ||
(ctx.request.url != '/admin' && item.url != '/admin' && ctx.request.url.startsWith(baseURL) && item.url)
) {
item.active = 'active';
}
if (item.url) {
item.style = "text-indent:2em";
} else {
item.style = "cursor:default";
}
return item;
});
console.log(ctx.locals.menus);
//转成树形结构数据
ctx.locals.menus = app.transformToTree(ctx.locals.menus);
console.log(ctx.locals.menus);
await next();
}
}
菜单模版 app/view/admin/layout/_slider.html
{# 定义一个可递归调用的子模板 #}
{% macro renderMenu(items) %}
{% for item in items %}
<li class="{{item.active}}" >
<a href="{{item.url}}" style="{{item.style}}"><i class="{{item.icon}}" style="font-size: 18px;"></i> <span>{{item.name}}</span></a>
</li>
{# 检查是否存在子菜单项 #}
{% if item.children and item.children.length %}
{% call renderMenu(item.children) %}
{# 这里通过调用macro自身实现了递归 #}
{% endcall %}
{% endif %}
{% endfor %}
{% endmacro %}
<div class="sidebar" id="sidebar">
<div class="sidebar-inner slimscroll">
<div id="sidebar-menu" class="sidebar-menu">
<ul>
{# {% for item in ctx.locals.menus %}
<li class="{{item.active}}" >
<a href="{{item.url}}" style="{{item.style}}"><i class="{{item.icon}}" style="font-size: 18px;"></i> <span>{{item.name}}</span></a>
</li>
{% endfor %} #}
{# 使用定义好的子模板递归渲染菜单 #}
<!-- 在上面的代码块之前或之外的合适位置,提前解析item.default为JSON对象 -->
{% call renderMenu(ctx.locals.menus) %}
{% endcall %}
</ul>
</div>
</div>
</div>
# 五、超级管理员修改普通管理员权限及,超级管理员可在管理员列表查看各个管理员权限
控制器 app/controller/admin/manager.js
//修改管理员界面
async edit() {
const { ctx, app } = this;
const id = ctx.params.id;
let data = await app.model.Manager.findOne({
where: {
id
}
});
if (!data) {
return ctx.pageFail('该管理员不存在', 404);
}
data = JSON.parse(JSON.stringify(data));
delete data.password;
console.log(data);
//读取所有权限栏目
let fields = [];
if(this.ctx.session.auth.super == 1){
let roots = fs.readFileSync('./data/root.json', {
encoding: 'utf-8'
});
roots = this.app.transformToTree(JSON.parse(roots));
//赋值给表单字段
fields = [
{
label: '权限分配',
type: 'treeDataSelect',//树形结构数据选择
name: 'auth',
default: JSON.stringify(roots),
}
];
}
//渲染公共模版
await ctx.renderTemplate({
id,
title: '修改管理员',//现在网页title,面包屑导航title,页面标题
tempType: 'form', //模板类型:table表格模板 ,form表单模板
form: {
//修改管理员提交地址
action: '/admin/manager/update/' + id,
// 字段
fields: [
{
label: '管理员账号',
type: 'text',
name: 'username',
placeholder: '请输入管理员账号',
},
{
label: '管理员密码',
type: 'password',
name: 'password',
placeholder: '请输入管理员密码',
},
{
label: '管理员头像',
type: 'file',
name: 'avatar',
},
...fields,
],
//修改内容默认值
data,
},
//修改成功之后跳转到哪个页面
successUrl: '/admin/manager/index',
});
}
//修改管理员数据功能
async update() {
if (this.ctx.session.auth.super == 0 && this.ctx.params.id != this.ctx.session.auth.id) {
return this.ctx.apiFail('您无权操作此项功能');
}
const { ctx, app } = this;
//1.参数验证
this.ctx.validate({
id: {
type: 'int',
required: true,
desc: '管理员id'
},
username: {
type: 'string', //参数类型
required: true, //是否必须
// defValue: '',
desc: '管理员账号' //字段含义
},
password: {
type: 'string',
// required: true,
// defValue: '',
desc: '管理员密码'
},
avatar: {
type: 'string',
required: false,
// defValue: '',
desc: '管理员头像'
},
auth: {
type: 'string',
required: false,
// defValue: '',
desc: '权限id'
},
});
// 参数
const id = ctx.params.id;
const { username, password, avatar,auth } = ctx.request.body;
// 先看一下管理员是否存在
const manager = await app.model.Manager.findOne({ where: { id } });
if (!manager) {
return ctx.pageFail('该管理员记录不存在');
}
//存在,由于管理员的账号具有唯一性,你不能修改账号的时候,修改成存在的账号
const Op = this.app.Sequelize.Op;//拿Op,固定写法
if (await app.model.Manager.findOne({
where: {
username,
id: {
[Op.ne]: id
}
}
})) {
// return ctx.pageFail('该管理员账号已经存在,不能修改成该管理员账号', 404);
return ctx.apiFail('该管理员账号已经存在,不能修改成该管理员账号');
}
// 修改数据
manager.username = username;
if (password) {
manager.password = password;
}
if (avatar) {
manager.avatar = avatar;
}
if(auth){
manager.auth = auth;
}
await manager.save();
// 给一个反馈
ctx.apiSuccess('修改成功');
}
//创建管理员列表页面
async index() {
const { ctx, app } = this;
//分页:可以提炼成一个公共方法page(模型名称,where条件,其他参数options)
let data = await ctx.page('Manager');
// await ctx.render('admin/manager/index.html',{
// title: '管理员列表',
// data
// });
//超级管理员的特殊权限
let menus = fs.readFileSync('./data/root.json', {
encoding: 'utf-8'
});
menus = JSON.parse(menus);
console.log(ctx.session.auth);
let btns = null;
let cols = [];
if (ctx.session.auth.super == 1) {
btns = {
buttons: [
{
url: '/admin/manager/create',//新增路径
desc: '新增管理员',//新增 //按钮名称
// icon: 'fa fa-plus fa-lg',//按钮图标
}
],
};
cols = [
{
title: '可用状态',
key: 'status',
width: 200,//可选
class: 'text-center',//可选
hidekeyData: true,//是否隐藏key对应的数据
render(item) {
console.log('可用状态里面每个item', item);
let arr = [
{ value: 1, name: '启用' },
{ value: 0, name: '禁用' },
];
let str = `<div class="btn-group btn-group-${item.id}">`;
for (let i = 0; i < arr.length; i++) {
str += `<button type="button" class="btn btn-light" data="${item.status}"
value="${arr[i].value}"
@click="changeBtnStatus('status','btn-group-${item.id}',${arr[i].value},${i},${item.id},'manager','Manager')">${arr[i].name}</button>`;
}
str += `</div>`;
return str;
}
},
{
title: '权限',
// key: 'auth',
// width: 200,//可选
class: 'text-left',//可选
render(item) {
console.log('每个item',item.auth);
const ids = item.auth;
const selectedIds = ids.split(',').map(id=>parseInt(id));
let result = [];
for(let i=0; i < selectedIds.length; i++){
let id = selectedIds[i];
for(let j=0;j<menus.length;j++){
if(menus[j].id == id ){
result.push(menus[j]);
}
}
}
console.log('最终结果',result);
result = result.map(item=>item.url && item.name);
result = result.filter(item => item.length);
let strhtml = '';
for(let i=0;i<result.length;i++){
strhtml += `<span style="background-color:#eeeeee;padding:5px 10px;margin-right:10px;font-size:12px;margin-top:10px;">${result[i]}</span>`;
if(i>0 && i % 4 == 0){
strhtml += `<div style="height:10px;"></div>`;
}
}
if(item.super == 1){
strhtml = `拥有所有的权限`;
}
return strhtml;
}
},
];
} else {
data = await ctx.page('Manager', {
id: ctx.session.auth.id
});
}
//渲染公共模版
await ctx.renderTemplate({
title: '管理员列表',//现在网页title,面包屑导航title,页面标题
data,
tempType: 'table', //模板类型:table表格模板 ,form表单模板
table: {
//表格上方按钮,没有不要填buttons
// buttons: [
// {
// url: '/admin/manager/create',//新增路径
// desc: '新增管理员',//新增 //按钮名称
// // icon: 'fa fa-plus fa-lg',//按钮图标
// }
// ],
...btns,
//表头
columns: [
{
title: '管理员账号',
// key: 'username',
render(item) {
const type = item.super == 1 ? '超级管理员' : '普通管理员';
return `
<h2 class="table-avatar">
<a href="#" class="avatar avatar-sm mr-2">
<img
class="avatar-img rounded-circle"
src="${item.avatar}"
alt="User Image"></a>
<a href="#"> ${item.username}
<span>${type}</span></a>
</h2>
`;
},
},
...cols,
// {
// title: '创建时间',
// key: 'create_time',
// width: 200,//可选
// class: 'text-center',//可选
// },
{
title: '操作',
class: 'text-right',//可选
action: {
//修改
edit: function (id) {
return `/admin/manager/edit/${id}`;
},
//删除
delete: function (id) {
return `/admin/manager/delete/${id}`;
}
}
},
],
},
});
}
微调一下后台管理员头像和手机模式显示后台标题
app/view/admin/layout/_header.html
...
<a href="/admin" class="logo logo-small">
{# <img src="/public/assets/img/logo-small.png" alt="Logo" width="30" height="30"> #}
<span class="text-white"
style="font-size: 22px;">
后台管理中心
</span>
</a>
...
<span class="user-img"><img class="rounded-circle" src="{{ctx.session.auth.avatar}}" width="31" height="31" alt="Ryan Taylor"></span>
...