Menu.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 海豚PHP框架 [ DolphinPHP ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2016~2017 河源市卓锐科技有限公司 [ http://www.zrthink.com ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://dolphinphp.com
  8. // +----------------------------------------------------------------------
  9. // | 开源协议 ( http://www.apache.org/licenses/LICENSE-2.0 )
  10. // +----------------------------------------------------------------------
  11. namespace app\admin\model;
  12. use app\user\model\Role as RoleModel;
  13. use think\Model;
  14. use think\Exception;
  15. use util\Tree;
  16. /**
  17. * 节点模型
  18. * @package app\admin\model
  19. */
  20. class Menu extends Model
  21. {
  22. // 设置当前模型对应的完整数据表名称
  23. protected $table = '__ADMIN_MENU__';
  24. // 自动写入时间戳
  25. protected $autoWriteTimestamp = true;
  26. // 将节点url转为小写
  27. public function setUrlValueAttr($value)
  28. {
  29. return strtolower(trim($value));
  30. }
  31. /**
  32. * 递归修改所属模型
  33. * @param int $id 父级节点id
  34. * @param string $module 模型名称
  35. * @author 蔡伟明 <314013107@qq.com>
  36. * @return bool
  37. */
  38. public static function changeModule($id = 0, $module = '')
  39. {
  40. if ($id > 0) {
  41. $ids = self::where('pid', $id)->column('id');
  42. if ($ids) {
  43. foreach ($ids as $id) {
  44. self::where('id', $id)->setField('module', $module);
  45. self::changeModule($id, $module);
  46. }
  47. }
  48. }
  49. return true;
  50. }
  51. /**
  52. * 获取树形节点
  53. * @param int $id 需要隐藏的节点id
  54. * @param string $default 默认第一个节点项,默认为“顶级节点”,如果为false则不显示,也可传入其他名称
  55. * @param string $module 模型名
  56. * @author 蔡伟明 <314013107@qq.com>
  57. * @return mixed
  58. */
  59. public static function getMenuTree($id = 0, $default = '', $module = '')
  60. {
  61. $result[0] = '顶级节点';
  62. $where['status'] = ['egt', 0];
  63. if ($module != '') {
  64. $where['module'] = $module;
  65. }
  66. // 排除指定节点及其子节点
  67. if ($id !== 0) {
  68. $hide_ids = array_merge([$id], self::getChildsId($id));
  69. $where['id'] = ['notin', $hide_ids];
  70. }
  71. // 获取节点
  72. $menus = Tree::toList(self::where($where)->order('pid,id')->column('id,pid,title'));
  73. foreach ($menus as $menu) {
  74. $result[$menu['id']] = $menu['title_display'];
  75. }
  76. // 设置默认节点项标题
  77. if ($default != '') {
  78. $result[0] = $default;
  79. }
  80. // 隐藏默认节点项
  81. if ($default === false) {
  82. unset($result[0]);
  83. }
  84. return $result;
  85. }
  86. /**
  87. * 获取顶部节点
  88. * @param string $max 最多返回多少个
  89. * @param string $cache_tag 缓存标签
  90. * @author 蔡伟明 <314013107@qq.com>
  91. * @return array
  92. */
  93. public static function getTopMenu($max = '', $cache_tag = '')
  94. {
  95. $cache_tag .= '_role_'.session('user_auth.role');
  96. $menus = cache($cache_tag);
  97. if (!$menus) {
  98. // 非开发模式,只显示可以显示的菜单
  99. if (config('develop_mode') == 0) {
  100. $map['online_hide'] = 0;
  101. }
  102. $map['status'] = 1;
  103. $map['pid'] = 0;
  104. $menus = self::where($map)->order('sort,id')->limit($max)->column('id,pid,module,title,url_value,url_type,url_target,icon,params');
  105. foreach ($menus as $key => &$menu) {
  106. // 没有访问权限的节点不显示
  107. if (!RoleModel::checkAuth($menu['id'])) {
  108. unset($menus[$key]);
  109. continue;
  110. }
  111. if ($menu['url_value'] != '' && ($menu['url_type'] == 'module_admin' || $menu['url_type'] == 'module_home')) {
  112. $url = explode('/', $menu['url_value']);
  113. $menu['controller'] = $url[1];
  114. $menu['action'] = $url[2];
  115. $menu['url_value'] = $menu['url_type'] == 'module_admin' ? admin_url($menu['url_value'], $menu['params']) : home_url($menu['url_value'], $menu['params']);
  116. }
  117. }
  118. // 非开发模式,缓存菜单
  119. if (config('develop_mode') == 0) {
  120. cache($cache_tag, $menus);
  121. }
  122. }
  123. return $menus;
  124. }
  125. /**
  126. * 获取侧栏节点
  127. * @param string $id 模块id
  128. * @param string $module 模块名
  129. * @param string $controller 控制器名
  130. * @author 蔡伟明 <314013107@qq.com>
  131. * @return array|mixed
  132. */
  133. public static function getSidebarMenu($id = '', $module = '', $controller = '')
  134. {
  135. $module = $module == '' ? request()->module() : $module;
  136. $controller = $controller == '' ? request()->controller() : $controller;
  137. $cache_tag = strtolower('_sidebar_menus_' . $module . '_' . $controller).'_role_'.session('user_auth.role');
  138. $menus = cache($cache_tag);
  139. if (!$menus) {
  140. // 获取当前节点地址
  141. $location = self::getLocation($id);
  142. // 当前顶级节点id
  143. $top_id = $location[0]['id'];
  144. // 获取顶级节点下的所有节点
  145. $map = [
  146. 'status' => 1,
  147. 'module' => $module
  148. ];
  149. // 非开发模式,只显示可以显示的菜单
  150. if (config('develop_mode') == 0) {
  151. $map['online_hide'] = 0;
  152. }
  153. $menus = self::where($map)->order('sort,id')->column('id,pid,module,title,url_value,url_type,url_target,icon,params');
  154. // 解析模块链接
  155. foreach ($menus as $key => &$menu) {
  156. // 没有访问权限的节点不显示
  157. if (!RoleModel::checkAuth($menu['id'])) {
  158. unset($menus[$key]);
  159. continue;
  160. }
  161. if ($menu['url_value'] != '' && ($menu['url_type'] == 'module_admin' || $menu['url_type'] == 'module_home')) {
  162. $menu['url_value'] = $menu['url_type'] == 'module_admin' ? admin_url($menu['url_value'], $menu['params']) : home_url($menu['url_value'], $menu['params']);
  163. }
  164. }
  165. $menus = Tree::toLayer($menus, $top_id, 2);
  166. // 非开发模式,缓存菜单
  167. if (config('develop_mode') == 0) {
  168. cache($cache_tag, $menus);
  169. }
  170. }
  171. return $menus;
  172. }
  173. /**
  174. * 获取指定节点ID的位置
  175. * @param string $id 节点id,如果没有指定,则取当前节点id
  176. * @param bool $del_last_url 是否删除最后一个节点的url地址
  177. * @param bool $check 检查节点是否存在,不存在则抛出错误
  178. * @author 蔡伟明 <314013107@qq.com>
  179. * @return array
  180. * @throws \think\Exception
  181. */
  182. public static function getLocation($id = '', $del_last_url = false, $check = true)
  183. {
  184. $model = request()->module();
  185. $controller = request()->controller();
  186. $action = request()->action();
  187. if ($id != '') {
  188. $cache_name = 'location_menu_'.$id;
  189. } else {
  190. $cache_name = 'location_'.$model.'_'.$controller.'_'.$action;
  191. }
  192. $location = cache($cache_name);
  193. if (!$location) {
  194. $map['pid'] = ['<>', 0];
  195. $map['url_value'] = strtolower($model.'/'.trim(preg_replace("/[A-Z]/", "_\\0", $controller), "_").'/'.$action);
  196. // 当前操作对应的节点ID
  197. $curr_id = $id == '' ? self::where($map)->value('id') : $id;
  198. // 获取节点ID是所有父级节点
  199. $location = Tree::getParents(self::column('id,pid,title,url_value'), $curr_id);
  200. if ($check && empty($location)) {
  201. throw new Exception('获取不到当前节点地址,可能未添加节点', 9001);
  202. }
  203. // 剔除最后一个节点url
  204. if ($del_last_url) {
  205. $location[count($location) - 1]['url_value'] = '';
  206. }
  207. // 非开发模式,缓存菜单
  208. if (config('develop_mode') == 0) {
  209. cache($cache_name, $location);
  210. }
  211. }
  212. return $location;
  213. }
  214. /**
  215. * 根据分组获取节点
  216. * @param string $group 分组名称
  217. * @param bool|string $fields 要返回的字段
  218. * @param array $map 查找条件
  219. * @author 蔡伟明 <314013107@qq.com>
  220. * @return array
  221. */
  222. public static function getMenusByGroup($group = '', $fields = true, $map = [])
  223. {
  224. $map['module'] = $group;
  225. return self::where($map)->order('sort,id')->column($fields, 'id');
  226. }
  227. /**
  228. * 获取节点分组
  229. * @author 蔡伟明 <314013107@qq.com>
  230. * @return array
  231. */
  232. public static function getGroup()
  233. {
  234. $map['status'] = 1;
  235. $map['pid'] = 0;
  236. $menus = self::where($map)->order('id,sort')->column('module,title');
  237. return $menus;
  238. }
  239. /**
  240. * 获取所有子节点id
  241. * @param int $pid 父级id
  242. * @author 蔡伟明 <314013107@qq.com>
  243. * @return array
  244. */
  245. public static function getChildsId($pid = 0)
  246. {
  247. $ids = self::where('pid', $pid)->column('id');
  248. foreach ($ids as $value) {
  249. $ids = array_merge($ids, self::getChildsId($value));
  250. }
  251. return $ids;
  252. }
  253. /**
  254. * 获取所有父节点id
  255. * @param int $id 节点id
  256. * @author 蔡伟明 <314013107@qq.com>
  257. * @return array
  258. */
  259. public static function getParentsId($id = 0)
  260. {
  261. $pid = self::where('id', $id)->value('pid');
  262. $pids = [];
  263. if ($pid != 0) {
  264. $pids[] = $pid;
  265. $pids = array_merge($pids, self::getParentsId($pid));
  266. }
  267. return $pids;
  268. }
  269. /**
  270. * 根据节点id获取上下级的所有id
  271. * @param int $id 节点id
  272. * @author 蔡伟明 <314013107@qq.com>
  273. * @return array
  274. */
  275. public static function getLinkIds($id = 0)
  276. {
  277. $childs = self::getChildsId($id);
  278. $parents = self::getParentsId($id);
  279. return array_merge((array)(int)$id, $childs, $parents);
  280. }
  281. }