From 82386cc9d8d1c91bd9916ca5a68f0a318a741135 Mon Sep 17 00:00:00 2001 From: Karson Date: Thu, 11 Sep 2025 14:24:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E8=A7=84=E5=88=99=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/admin/controller/auth/Rule.php | 67 +++++++++++++------- application/admin/view/auth/rule/index.html | 1 + extend/fast/Tree.php | 69 ++++++++++++++++++--- public/assets/js/backend/auth/rule.js | 18 ++++-- 4 files changed, 117 insertions(+), 38 deletions(-) diff --git a/application/admin/controller/auth/Rule.php b/application/admin/controller/auth/Rule.php index fc706fa7..63aca234 100644 --- a/application/admin/controller/auth/Rule.php +++ b/application/admin/controller/auth/Rule.php @@ -2,12 +2,10 @@ namespace app\admin\controller\auth; -use app\admin\model\AuthRule; use app\common\controller\Backend; use fast\Tree; use think\Cache; -use think\db\Query; -use think\exception\HttpResponseException; +use think\Db; /** * 规则管理 @@ -32,24 +30,45 @@ class Rule extends Backend $this->error(__('Access is allowed only to the super management group')); } $this->model = model('AuthRule'); - // 必须将结果集转换为数组 - $ruleList = \think\Db::name("auth_rule")->field('type,condition,remark,menutype,extend,pinyin,py,createtime,updatetime', true)->order('weigh DESC,id ASC')->select(); - foreach ($ruleList as $k => &$v) { - $v['title'] = __($v['title']); - } - unset($v); - Tree::instance()->init($ruleList)->icon = ['    ', '    ', '    ']; - $this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title'); - $ruledata = [0 => __('None')]; - foreach ($this->rulelist as $k => &$v) { - if (!$v['ismenu']) { - continue; + $actionName = $this->request->action(); + + $isAddEdit = in_array($actionName, ['add', 'edit']); + + // 优化加载 + if ($isAddEdit || ($actionName == 'index' && $this->request->isAjax())) { + + // 必须将结果集转换为数组 + $ruleList = Db::name("auth_rule") + ->where(function ($query) use ($isAddEdit) { + if ($isAddEdit) { + $query->where('ismenu', 1); + } + })->field('id,pid,name,title,icon,ismenu,status,weigh') + ->order('weigh DESC,id ASC') + ->select(); + + array_walk($ruleList, function (&$v) { + $v['title'] = __($v['title']); + }); + + // 读取规则菜单 + $this->rulelist = Tree::instance()->init($ruleList)->getTreeArrayList(0); + + // 只有编辑页才需要渲染 + if ($isAddEdit) { + $ruledata = [0 => __('None')]; + foreach ($this->rulelist as $k => &$v) { + if (!$v['ismenu']) { + continue; + } + $ruledata[$v['id']] = str_repeat(' ', $v['level'] * 4) . $v['title']; + } + unset($v); + + $this->view->assign('ruledata', $ruledata); } - $ruledata[$v['id']] = $v['title']; - unset($v['spacer']); } - unset($v); - $this->view->assign('ruledata', $ruledata); + $this->view->assign("menutypeList", $this->model->getMenutypeList()); } @@ -111,7 +130,8 @@ class Rule extends Backend $this->error(__('Can not change the parent to self')); } if ($params['pid'] != $row['pid']) { - $childrenIds = Tree::instance()->init(collection(AuthRule::select())->toArray())->getChildrenIds($row['id']); + $tree = Tree::instance()->init(Db::name('auth_rule')->select()); + $childrenIds = $tree->getChildrenIds($row['id']); if (in_array($params['pid'], $childrenIds)) { $this->error(__('Can not change the parent to child')); } @@ -141,11 +161,12 @@ class Rule extends Backend if (!$this->request->isPost()) { $this->error(__("Invalid parameters")); } - $ids = $ids ? $ids : $this->request->post("ids"); + $ids = $ids ?: $this->request->post("ids"); if ($ids) { $delIds = []; + $tree = Tree::instance()->init(Db::name('auth_rule')->select()); foreach (explode(',', $ids) as $k => $v) { - $delIds = array_merge($delIds, Tree::instance()->getChildrenIds($v, true)); + $delIds = array_merge($delIds, $tree->getChildrenIds($v, true)); } $delIds = array_unique($delIds); $count = $this->model->where('id', 'in', $delIds)->delete(); @@ -170,4 +191,4 @@ class Rule extends Backend parent::dragsort(); } -} +} \ No newline at end of file diff --git a/application/admin/view/auth/rule/index.html b/application/admin/view/auth/rule/index.html index 3d6b04e7..7cccea61 100644 --- a/application/admin/view/auth/rule/index.html +++ b/application/admin/view/auth/rule/index.html @@ -1,5 +1,6 @@
{:build_heading()} diff --git a/extend/fast/Tree.php b/extend/fast/Tree.php index 0e63a77d..656c87c3 100644 --- a/extend/fast/Tree.php +++ b/extend/fast/Tree.php @@ -55,15 +55,15 @@ class Tree /** * 初始化方法 * @param array $arr 2维数组,例如: - * array( - * 1 => array('id'=>'1','pid'=>0,'name'=>'一级栏目一'), - * 2 => array('id'=>'2','pid'=>0,'name'=>'一级栏目二'), - * 3 => array('id'=>'3','pid'=>1,'name'=>'二级栏目一'), - * 4 => array('id'=>'4','pid'=>1,'name'=>'二级栏目二'), - * 5 => array('id'=>'5','pid'=>2,'name'=>'二级栏目三'), - * 6 => array('id'=>'6','pid'=>3,'name'=>'三级栏目一'), - * 7 => array('id'=>'7','pid'=>3,'name'=>'三级栏目二') - * ) + * array( + * 1 => array('id'=>'1','pid'=>0,'name'=>'一级栏目一'), + * 2 => array('id'=>'2','pid'=>0,'name'=>'一级栏目二'), + * 3 => array('id'=>'3','pid'=>1,'name'=>'二级栏目一'), + * 4 => array('id'=>'4','pid'=>1,'name'=>'二级栏目二'), + * 5 => array('id'=>'5','pid'=>2,'name'=>'二级栏目三'), + * 6 => array('id'=>'6','pid'=>3,'name'=>'三级栏目一'), + * 7 => array('id'=>'7','pid'=>3,'name'=>'三级栏目二') + * ) * @param string $pidname 父字段名称 * @param string $nbsp 空格占位符 * @return Tree @@ -435,4 +435,55 @@ class Tree } return $arr; } + + public function getTreeArrayList($pid = 0) + { + $map = []; + $data = []; + + $items = $this->arr; + + foreach ($items as &$item) { + $item['children'] = []; // 初始化子节点 + $map[$item['id']] = &$item; + } + unset($item); + + foreach ($items as &$item) { + if ($item[$this->pidname] == $pid) { + $data[] = &$item; + } else { + if (isset($map[$item[$this->pidname]])) { + $map[$item[$this->pidname]]['children'][] = &$item; + } + } + } + unset($item); + + return $this->getFlattenTree($data); + } + + /** + * 将多维树形结构数据扁平化处理 + * + * 该函数递归遍历树形结构,将嵌套的节点展开为一维数组, + * 并为每个节点添加层级标识 + * + * @param array $data 树形结构数据,每个节点可能包含children子节点 + * @param int $level 当前节点的层级深度,默认为0(根节点) + * @param array &$result 引用传递的结果数组,用于存储扁平化后的所有节点 + * + * @return array 扁平化后的节点数组,每个节点包含原始数据和level层级信息 + */ + public function getFlattenTree($data, $level = 0, &$result = []) + { + foreach ($data as $node) { + $node['level'] = $level; + $result[] = $node; + if (!empty($node['children'])) { + $this->getFlattenTree($node['children'], $level + 1, $result); + } + } + return $result; + } } diff --git a/public/assets/js/backend/auth/rule.js b/public/assets/js/backend/auth/rule.js index 6020ab72..7713b0c4 100755 --- a/public/assets/js/backend/auth/rule.js +++ b/public/assets/js/backend/auth/rule.js @@ -14,6 +14,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function } }); + var isExpanded = false; + var table = $("#table"); // 初始化表格 @@ -29,7 +31,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function {field: 'icon', title: __('Icon'), formatter: Controller.api.formatter.icon}, {field: 'name', title: __('Name'), align: 'left', formatter: Controller.api.formatter.name}, {field: 'weigh', title: __('Weigh')}, - {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status, operate: false}, { field: 'ismenu', title: __('Ismenu'), @@ -50,8 +52,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function search: false, commonSearch: false, rowAttributes: function (row, index) { - var expanded = $(".btn-toggle-all i").hasClass("fa-minus"); - return row.pid == 0 || expanded ? {} : {style: "display:none"}; + return row.pid == 0 || isExpanded ? {} : {style: "display:none"}; + } + }); + + table.on('post-body.bs.table', function (e, data) { + if (data.length > 2000) { + $(".btn-dragsort").addClass("disabled"); } }); @@ -142,6 +149,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function $(".btn-node-sub:not([data-pid=0])").closest("tr").toggle(show); $(".btn-node-sub").data("shown", show); $(".btn-node-sub > i").toggleClass("fa-caret-down", show).toggleClass("fa-caret-right", !show); + isExpanded = show; }); }, add: function () { @@ -153,13 +161,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function api: { formatter: { title: function (value, row, index) { - value = value.toString().replace(/(&|&)nbsp;/g, ' '); var caret = row.haschild == 1 || row.ismenu == 1 ? '' : ''; - value = value.indexOf(" ") > -1 ? value.replace(/(.*) /, "$1" + caret) : caret + value; value = !row.ismenu || row.status == 'hidden' ? "" + value + "" : value; return '' + value + ''; + + (row.haschild == 1 || row.ismenu == 1 ? 'text-primary' : 'disabled') + ' btn-node-sub">' + (' '.repeat(row.level)) + (' '.repeat(parseInt(row.level) * 4)) + caret + ' ' + value + ''; }, name: function (value, row, index) { return !row.ismenu || row.status == 'hidden' ? "" + value + "" : value;