Files

461 lines
14 KiB
PHP
Raw Permalink Normal View History

2025-11-07 09:56:20 +08:00
<?php
namespace plugin\admin\app\controller;
use Cache;
use Exception;
use Illuminate\Support\Facades\Date;
use plugin\admin\app\common\Auth;
use plugin\admin\app\common\Tree;
use plugin\admin\app\common\Util;
use plugin\admin\app\model\AdminRole;
use plugin\admin\app\model\AdminRule;
use support\exception\BusinessException;
use support\Request;
use support\Response;
use Throwable;
/**
* 权限菜单
*/
class AdminRuleController extends Crud
{
/**
* 不需要权限的方法
*
* @var string[]
*/
protected $noNeedAuth = ['get', 'permission'];
/**
* @var AdminRule
*/
protected $model = null;
/**
* 构造函数
*/
function __construct()
{
$this->model = new AdminRule;
}
/**
* 浏览
* @return Response
* @throws Throwable
*/
public function index(Request $request): Response
{
return view('admin_rule/index');
}
/**
* 格式化树
* @param $items
* @return Response
*/
protected function formatTree($items): Response
{
$format_items = [];
//$primary_key = $this->model->getPk();
$primary_key = $this->model->getPk();
foreach ($items as $item) {
$item->text = $item->title;
//$item->value = (string)$item->$primary_key;
$item->id = $item->$primary_key;
$item->parent = $item->pid;
if($item->pid == 0){
$item->parent = '#';
}
unset($item->pid);
$format_items[] = $item;
}
$tree = new Tree($format_items);
return $this->success("操作成功", $tree->getTree());
}
/**
* 权限树形
* @param Request $request
* @return Response
* @throws BusinessException
*/
public function roletree(Request $request): Response
{
[$where, $format, $limit, $field, $order] = $this->selectInput($request);
$query = $this->doSelect($where, $field, $order);
$methods = [
'select' => 'formatSelect',
'tree' => 'formatTree',
'table_tree' => 'formatTableTree',
'normal' => 'formatNormal',
];
$format = 'normal';
$items = $query->field('id,title as text,pid as parent,"menu" as type')->select();
/**
* @var AdminRule $item
*/
foreach ($items as $key => $item) {
$items[$key]->state = [
"selected" => false,
];
if($items[$key]->parent == 0){
$items[$key]->parent = '#';
}
};
if (method_exists($this, "afterQuery")) {
$items = call_user_func([$this, "afterQuery"], $items);
}
$format_function = $methods[$format] ?? 'formatNormal';
return call_user_func([$this, $format_function], $items, 0);
}
/**
* 查询
* @param Request $request
* @return Response
* @throws BusinessException
*/
public function select(Request $request): Response
{
[$where, $format, $limit, $field, $order] = $this->selectInput($request);
$query = $this->doSelect($where, $field, $order);
return $this->doFormat($query, $format, 'all');
}
/**
* 刷新缓存
* @param \support\Request $request
* @return Response
*/
public function buildcache(Request $request){
//缓存
$list = $this->get($request)->rawBody();
$list = json_decode($list,true);
$fn = base_path() . '/plugin/admin/config/menu.php';
file_put_contents($fn, "<?php \n return ".var_export($list['data'],true).';');
return $this->success('ok');
}
/**
* 获取菜单
* @param Request $request
* @return Response
* @throws Exception
*/
function get(Request $request): Response
{
$is_supper_admin = Auth::isSuperAdmin();
if($is_supper_admin){
$rules = ['*'];
}else{
$rules = $this->getRules(admin('roles'));
}
//return $this->success("操作成功", admin('roles'));
$types = $request->get('type', '0,1');
$types = is_string($types) ? explode(',', $types) : [0, 1];
$items = AdminRule::order('weight', 'desc')->select();
$formatted_items = [];
/**
* @var AdminRule $item
*/
foreach ($items as $item) {
$item['pid'] = (int)$item['pid'];
$item['name'] = $item['title'];
$item['value'] = $item['id'];
$item['icon'] = $item->icon ? "{$item->icon}" : '';
$formatted_items[] = $item;
}
$tree = new Tree($formatted_items);
$tree_items = $tree->getTree();
// 超级管理员权限为 *
if (!in_array('*', $rules)) {
$this->removeNotContain($tree_items, 'id', $rules);
}
$this->removeNotContain($tree_items, 'type', $types);
$menus = $this->empty_filter(Tree::arrayValues($tree_items));
return $this->success("操作成功", $menus);
}
private function empty_filter($menus)
{
return array_map(
function ($menu) {
if (isset($menu['children'])) {
$menu['children'] = $this->empty_filter($menu['children']);
}
return $menu;
},
array_values(array_filter(
$menus,
function ($menu) {
return $menu['type'] != 0 || isset($menu['children']) && count($this->empty_filter($menu['children'])) > 0;
}
))
);
}
/**
* 获取权限
* @param Request $request
* @return Response
* @throws Exception
*/
public function permission(Request $request): Response
{
$rules = $this->getRules(admin('roles'));
// 超级管理员
if (in_array('*', $rules)) {
return $this->success("操作成功", ['*']);
}
$keys = AdminRule::whereIn('id', $rules)->column('key');
$permissions = [];
foreach ($keys as $key) {
if (!$key = Util::controllerToUrlPath($key)) {
continue;
}
$code = str_replace('/', '.', trim($key, '/'));
$permissions[] = $code;
}
return $this->success("操作成功", $permissions);
}
/**
* 同步规则
* @return void
*/
public function syncRules(): Response
{
//$items = $this->model->where('key', 'like', '%\\\\%')->get()->keyBy('key');
$items = $this->model->whereLike('key', '%\\\\%')->select();
$methods_in_db = [];
$methods_in_files = [];
/**
* @var AdminRule $item
*/
foreach ($items as $item) {
$class = $item->key;
if (strpos($class, '@')) {
$methods_in_db[$class] = $class;
continue;
}
if (class_exists('\\plugin\\admin\\'.$class)) {
$reflection = new \ReflectionClass('\\plugin\\admin\\'.$class);
$properties = $reflection->getDefaultProperties();
$no_need_auth = array_merge($properties['noNeedLogin'] ?? [], $properties['noNeedAuth'] ?? []);
$class = str_replace('plugin\admin\\','',$reflection->getName());
$pid = $item->id;
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) {
$method_name = $method->getName();
if (strtolower($method_name) === 'index' || strpos($method_name, '__') === 0 || in_array($method_name, $no_need_auth)) {
continue;
}
$name = "$class@$method_name";
$methods_in_files[$name] = $name;
$title = Util::getCommentFirstLine($method->getDocComment()) ?: $method_name;
/**
* @var AdminRule $menu
*/
$menu = $items[$name] ?? [];
if ($menu) {
if ($menu->title != $title) {
AdminRule::where('key', $name)->update(['title' => $title]);
}
continue;
}
if(!AdminRule::where('key', $name)->count('id')) {
$menu = new AdminRule;
$menu->pid = $pid;
$menu->key = $name;
$menu->title = $title;
$menu->type = 2;
$menu->save();
}
}
}
}
// 从数据库中删除已经不存在的方法
$menu_names_to_del = array_diff($methods_in_db, $methods_in_files);
if ($menu_names_to_del) {
AdminRule::whereIn('key', $menu_names_to_del)->delete();
}
return $this->success("操作成功");
}
/**
* 查询前置方法
* @param Request $request
* @return array
* @throws BusinessException
*/
protected function selectInput(Request $request): array
{
[$where, $format, $limit, $field, $order] = parent::selectInput($request);
// 允许通过type=0,1格式传递菜单类型
$types = $request->get('type');
if ($types && is_string($types)) {
$where['type'] = ['symbol'=>'in', 'value1'=>explode(',', $types)];
}
// 默认weight排序
if (!$field) {
$field = 'weight';
$order = 'desc';
}
return [$where, $format, $limit, $field, $order];
}
/**
* 添加
* @param Request $request
* @return Response
* @throws BusinessException|Throwable
*/
public function insert(Request $request): Response
{
if ($request->method() === 'GET') {
$RuleList = $this->model->where('status',1)->order('id asc')->select();
$tree = new Tree($RuleList);
return view('admin_rule/update',[
'RuleList' => $tree->getTree()
]);
}
$data = $this->insertInput($request);
if (empty($data['type'])) {
$data['type'] = strpos($data['key'], '\\') ? 1 : 0;
}
$data['key'] = str_replace('\\\\', '\\', $data['key']);
$key = $data['key'] ?? '';
if ($this->model->where('key', $key)->count('id')) {
return $this->fail("菜单标识 $key 已经存在");
}
$data['pid'] = empty($data['pid']) ? 0 : $data['pid'];
$this->doInsert($data);
return $this->success("操作成功");
}
/**
* 更新
* @param Request $request
* @return Response
* @throws BusinessException|Throwable
*/
public function update(Request $request): Response
{
if ($request->method() === 'GET') {
$RuleList = $this->model->order('id asc')->select();
$ids = Request()->get('ids');
$tree = new Tree($RuleList);
return view('admin_rule/update',[
'RuleList' => $tree->getTree(),
'row' => $this->model->where('id',$ids)->find()
]);
}
[$id, $data] = $this->updateInput($request);
if (!$row = $this->model->find($id)) {
return $this->json(2, '记录不存在');
}
if (isset($data['pid'])) {
$data['pid'] = $data['pid'] ?: 0;
if ($data['pid'] == $row['id']) {
return $this->json(2, '不能将自己设置为上级菜单');
}
}
if (isset($data['key'])) {
$data['key'] = str_replace('\\\\', '\\', $data['key']);
}
$this->doUpdate($id, $data);
return $this->success("操作成功");
}
/**
* 删除
* @param Request $request
* @return Response
*/
public function delete(Request $request): Response
{
$ids = $this->deleteInput($request);
// 子规则一起删除
$delete_ids = $children_ids = $ids;
while($children_ids) {
$children_ids = $this->model->whereIn('pid', $children_ids)->column('id');
$delete_ids = array_merge($delete_ids, $children_ids);
}
$this->doDelete($delete_ids);
return $this->success("操作成功");
}
/**
* 移除不包含某些数据的数组
* @param $array
* @param $key
* @param $values
* @return void
*/
protected function removeNotContain(&$array, $key, $values)
{
foreach ($array as $k => &$item) {
if (!is_array($item)) {
continue;
}
if (!$this->arrayContain($item, $key, $values)) {
unset($array[$k]);
} else {
if (!isset($item['children'])) {
continue;
}
$this->removeNotContain($item['children'], $key, $values);
}
}
}
/**
* 判断数组是否包含某些数据
* @param $array
* @param $key
* @param $values
* @return bool
*/
protected function arrayContain(&$array, $key, $values): bool
{
if (!is_array($array)) {
return false;
}
if (isset($array[$key]) && in_array($array[$key], $values)) {
return true;
}
if (!isset($array['children'])) {
return false;
}
foreach ($array['children'] as $item) {
if ($this->arrayContain($item, $key, $values)) {
return true;
}
}
return false;
}
/**
* 获取权限规则
* @param $roles
* @return array
*/
protected function getRules($roles): array
{
$rules_strings = $roles ? AdminRole::whereIn('id', $roles)->column('rules') : [];
$rules = [];
foreach ($rules_strings as $rule_string) {
if (!$rule_string) {
continue;
}
$rules = array_merge($rules, explode(',', $rule_string));
}
return $rules;
}
}