// +---------------------------------------------------------------------- // +---------------------------------------------------------------------- // | CRMEB [ CRMEB赋能开发者,助力企业发展 ] // +---------------------------------------------------------------------- // | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. // +---------------------------------------------------------------------- // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 // +---------------------------------------------------------------------- // | Author: CRMEB Team // +---------------------------------------------------------------------- namespace app\common\repositories\system\auth; //附件 use app\common\dao\BaseDao; use app\common\dao\system\menu\MenuDao; use app\common\repositories\BaseRepository; use app\common\repositories\system\config\ConfigRepository; use crmeb\traits\SpecialConfig; use FormBuilder\Exception\FormBuilderException; use FormBuilder\Factory\Elm; use FormBuilder\Form; use think\db\exception\DataNotFoundException; use think\db\exception\DbException; use think\db\exception\ModelNotFoundException; use think\Exception; use think\facade\Db; use think\facade\Route; use think\Model; /** * 菜单 */ class MenuRepository extends BaseRepository { use SpecialConfig; /** * MenuRepository constructor. * @param MenuDao $dao */ protected $styles = array( 'success' => "\033[0;32m%s\033[0m", 'error' => "\033[31;31m%s\033[0m", 'info' => "\033[33;33m%s\033[0m" ); public $prompt = 'all'; public function __construct(MenuDao $dao) { /** * @var MenuDao */ $this->dao = $dao; } /** * @param array $where * @param int $merId * @return array * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @author xaboy * @day 2020-04-16 */ public function getList(array $where, $merId = 0) { $query = $this->dao->search($where, $merId); $count = $query->count(); $list = $query->hidden(['update_time', 'path'])->select()->toArray(); return compact('count', 'list'); } /** * @param array $data * @return BaseDao|Model * @author xaboy * @day 2020-04-09 */ public function create(array $data) { $data['path'] = '/'; if ($data['pid']) { $data['path'] = $this->getPath($data['pid']) . $data['pid'] . '/'; } return $this->dao->create($data); } /** * @param int $id * @param array $data * @return int * @throws DbException * @author xaboy * @day 2020-04-09 */ public function update(int $id, array $data) { $menu = $this->dao->get($id); if ($menu->pid != $data['pid']) { Db::transaction(function () use ($menu, $data) { $data['path'] = '/'; if ($data['pid']) { $data['path'] = $this->getPath($data['pid']) . $data['pid'] . '/'; } $this->dao->updatePath($menu->path . $menu->menu_id . '/', $data['path'] . $menu->menu_id . '/'); $menu->save($data); }); } else { unset($data['path']); $this->dao->update($id, $data); } } /** * @param bool $is_mer * @return array * @author xaboy * @day 2020-04-18 */ public function getTree($merType = 0) { if (!$merType) { $options = $this->dao->getAllOptions(); } else { $options = $this->dao->merchantTypeByOptions($merType); } return formatTree($options, 'menu_name'); } /** * @param int $isMer * @param int|null $id * @param array $formData * @return Form * @throws FormBuilderException * @author xaboy * @day 2020-04-16 */ public function menuForm(int $isMer = 0, ?int $id = null, array $formData = []): Form { $action = $isMer == 0 ? (is_null($id) ? Route::buildUrl('systemMenuCreate')->build() : Route::buildUrl('systemMenuUpdate', ['id' => $id])->build()) : (is_null($id) ? Route::buildUrl('systemMerchantMenuCreate')->build() : Route::buildUrl('systemMerchantMenuUpdate', ['id' => $id])->build()); $form = Elm::createForm($action); $form->setRule([ Elm::cascader('pid', '父级分类:')->options(function () use ($id, $isMer) { $menus = $this->dao->getAllOptions($isMer, true); if ($id && isset($menus[$id])) unset($menus[$id]); $menus = formatCascaderData($menus, 'menu_name'); array_unshift($menus, ['label' => '顶级分类:', 'value' => 0]); return $menus; })->placeholder('请选择分级分类')->props(['props' => ['checkStrictly' => true, 'emitPath' => false]]), Elm::select('is_menu', '权限类型:', 1)->options([ ['value' => 1, 'label' => '菜单'], ['value' => 0, 'label' => '权限'], ])->control([ [ 'value' => 0, 'rule' => [ Elm::input('menu_name', '路由名称:')->placeholder('请输入路由名称')->required(), Elm::textarea('params', '参数:')->placeholder("路由参数:\r\nkey1:value1\r\nkey2:value2"), ] ], [ 'value' => 1, 'rule' => [ Elm::switches('is_show', '是否显示:', 1)->inactiveValue(0)->activeValue(1)->inactiveText('关')->activeText('开'), Elm::frameInput('icon', '菜单图标:', '/' . config('admin.admin_prefix') . '/setting/icons?field=icon')->icon('el-icon-circle-plus-outline')->height('338px')->width('700px')->modal(['modal' => false]), Elm::input('menu_name', '菜单名称:')->placeholder('请输入菜单名称')->required(), ] ] ]), Elm::input('route', '路由:')->placeholder('请输入路由'), Elm::number('sort', '排序:', 0)->precision(0)->max(99999) ]); return $form->setTitle(is_null($id) ? '添加菜单' : '编辑菜单')->formData($formData); } /** * @param int $id * @param int $merId * @return Form * @throws DataNotFoundException * @throws DbException * @throws FormBuilderException * @throws ModelNotFoundException * @author xaboy * @day 2020-04-16 */ public function updateMenuForm(int $id, $merId = 0) { return $this->menuForm($merId, $id, $this->dao->get($id)->toArray()); } /** * @param string $params * @return array * @author xaboy * @day 2020-04-22 */ public function tidyParams(?string $params) { return $params ? array_reduce(explode('|', $params), function ($initial, $val) { $data = explode(':', $val, 2); if (count($data) != 2) return $initial; $initial[$data[0]] = $data[1]; return $initial; }, []) : []; } /** * @param array $params * @param array $routeParams * @return bool * @author xaboy * @day 2020-04-23 */ public function checkParams(array $params, array $routeParams) { foreach ($routeParams as $k => $param) { if (isset($params[$k]) && $params[$k] != $param) return false; } return true; } public function formatPath($is_mer = 0) { $options = $this->getAll($is_mer); $options = formatCategory($options, 'menu_id'); Db::transaction(function () use ($options) { foreach ($options as $option) { $this->_formatPath($option); } }); } protected function _formatPath($parent, $path = '/') { $this->dao->update($parent['menu_id'], ['path' => $path]); foreach ($parent['children'] ?? [] as $item) { $itemPath = $path . $item['pid'] . '/'; $this->_formatPath($item, $itemPath); } } public function commandMenu($type, $data, $prompt) { $res = []; if ($prompt) $this->prompt = $prompt; $isMer = ($type == 'sys') ? 0 : 1; foreach ($data as $key => $value) { try { $result = $this->dao->getMenuPid($key, $isMer, 0); if (!$result) { $route = $key; $isAppend = 0; if (substr($key, 0, 7) === 'append_') { $isAppend = 1; $route = substr($key, 7); } $result = $this->dao->getMenuPid($route, $isMer, 1); if (!$result && $key !== 'self') { printf($this->styles['info'], '未找到菜单: ' . $key); echo PHP_EOL; continue; } else { $result = $this->dao->create([ 'pid' => $key == 'self' ? 0 : $result['menu_id'], 'path' => $key == 'self' ? '/' : $result['path'] . $result['menu_id'] . '/', 'menu_name' => $isAppend ? '附加权限' : '权限', 'route' => $key, 'is_mer' => $isMer, 'is_menu' => 0 ]); } } $res = array_merge($res, $this->createSlit($isMer, $result['menu_id'], $result['path'], $value)); } catch (\Exception $exception) { throw new Exception($key); } } $count = count($res); if (!empty($res)) $this->dao->insertAll($res); return $count; } /** * TODO 新增权限数据整理 * @param int $isMer * @param int $menuId * @param string $path * @param array $data * @return array * @author Qinii * @day 3/18/22 */ public function createSlit(int $isMer, int $menuId, string $path, array $data) { $arr = []; try { foreach ($data as $k => $v) { $result = $this->dao->getWhere(['route' => $v['route'], 'pid' => $menuId]); if (!$result) { $arr[] = [ 'pid' => $menuId, 'path' => $path . $menuId . '/', 'menu_name' => $v['menu_name'], 'route' => $v['route'], 'is_mer' => $isMer, 'is_menu' => 0, 'params' => $v['params'] ?? [], ]; if ($this->prompt == 's') { printf($this->styles['success'], '新增权限: ' . $v['menu_name'] . ' [' . $v['route'] . ']'); echo PHP_EOL; } } } return $arr; } catch (\Exception $exception) { halt($isMer, $menuId, $path, $data); } } /** * 快捷搜索 * @param int $isMer 是否商户 * @param string $keyWord 关键词 * @return array * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * FerryZhao 2024/4/3 */ public function getMenusList($isMer, $keyWord) { $pre = '/' . config('admin.' . ($isMer ? 'merchant' : 'admin') . '_prefix'); $configRepository = app()->make(ConfigRepository::class); $configData = $configRepository->getSearch([]) ->where('user_type', $isMer) ->whereLike('config_name', '%' . $keyWord . '%') ->field('config_id,config_name,config_classify_id') ->with(['classConfig.parent'])->select()->toArray(); $configMenus = []; $configMenusPath = []; $param = []; if ($configData) { foreach ($configData as $configDatum) { if ($_p = $this->valSpecial($isMer, $configDatum['config_name'])) { $configMenus[$_p] = [ 'title' => $configDatum['config_name'], 'path' => $_p, ]; } else if ($classConfig = $configDatum['classConfig']) { $classConfigId = !empty($classConfig['parent']) ? $classConfig['parent']['config_classify_id'] : $classConfig['config_classify_id']; $classifyKey = !empty($classConfig['parent']) ? $classConfig['parent']['classify_key'] : $classConfig['classify_key']; $title = !empty($classConfig['parent']) ? $classConfig['parent']['classify_name'] : $classConfig['classify_name']; $path = '/systemForm/Basics/' . $classifyKey; $configMenus[$classConfigId] = [ 'title' => $title, 'path' => $path, ]; $param[$path] = '?tab_id=' . $classConfig['config_classify_id']; } } $configMenus = array_values($configMenus); $configMenusPath = array_column($configMenus, 'path'); } $menuData = $this->dao->getSearch([]) ->where('is_mer', $isMer) ->where('is_menu', 1) ->where(function ($query) use ($keyWord, $configMenusPath) { $query->whereLike('menu_name', '%' . $keyWord . '%')->whereOr('route', 'in', $configMenusPath); })->select()->append(['parents', 'child'])->toArray(); $menus = []; foreach ($menuData as $datum) { if (in_array($datum['route'], $this->unsetConfigArray)) { continue; } if (!empty($datum['child'])) { continue; } $title = ''; if ($parents = $datum['parents']) { $path = explode('/', trim($datum['path'], '/')); $parents = array_combine(array_column($parents, 'pid'), $parents); $menu = $parents[0]['menu_name'] ?? ''; foreach ($path as $item) { if (isset($parents[$item])) { $menu .= ' - ' . $parents[$item]['menu_name']; } } $menu .= ' - ' . $datum['menu_name']; $title = trim($menu, '-'); } $menus[] = [ 'path' => $pre . $datum['route'] . ($param[$datum['route']] ?? ''), 'title' => $title ?: $datum['menu_name'], ]; } return compact('menus'); } }