SysMenuService.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <?php
  2. namespace App\Service;
  3. use App\Model\Employee;
  4. use App\Model\RoleMenu;
  5. use App\Model\RoleMenuButton;
  6. use App\Model\SysMenu;
  7. use App\Model\SysMenuButton;
  8. use Illuminate\Support\Facades\DB;
  9. class SysMenuService extends Service
  10. {
  11. public function edit($data){
  12. list($status,$msg) = $this->menuRule($data,false);
  13. if(! $status) return [$status, $msg];
  14. $del_button_id = $msg;
  15. DB::beginTransaction();
  16. try{
  17. $model = SysMenu::where('id',$data['id'])->first();
  18. $model->title = $data['title'];
  19. $model->icon = $data['icon'] ?? '';
  20. $model->uri = $data['uri'];
  21. $model->parent_id = $data['parent_id'];
  22. $model->sort = $data['sort'] ?? 0;
  23. $model->save();
  24. $time = time();
  25. //按钮
  26. $this->saveDetail($model->id, time(), $data);
  27. if(! empty($del_button_id)){
  28. SysMenuButton::where('del_time',0)
  29. ->whereIn('id',$del_button_id)
  30. ->update(['del_time' => $time]);
  31. RoleMenuButton::where('del_time',0)
  32. ->whereIn('button_id', $del_button_id)
  33. ->update(['del_time' => $time]);
  34. }
  35. DB::commit();
  36. }catch (\Exception $exception){
  37. DB::rollBack();
  38. return [false,$exception->getMessage()];
  39. }
  40. return [true,''];
  41. }
  42. public function add($data,$user){
  43. list($status,$msg) = $this->menuRule($data);
  44. if(! $status) return [$status,$msg];
  45. DB::beginTransaction();
  46. try{
  47. $model = new SysMenu();
  48. $sort = $model->where('parent_id',$data['parent_id'])->max('sort');
  49. $model->title = $data['title'];
  50. $model->icon = $data['icon'] ?? '';
  51. $model->uri = $data['uri'];
  52. $model->parent_id = $data['parent_id'];
  53. $model->sort = $sort ? $sort + 1 : 1;
  54. $model->crt_id = $user['id'];
  55. $model->save();
  56. //按钮
  57. $this->saveDetail($model->id, time(), $data);
  58. DB::commit();
  59. }catch (\Exception $exception){
  60. DB::rollBack();
  61. return [false,$exception->getMessage()];
  62. }
  63. return [true,''];
  64. }
  65. private function saveDetail($id, $time, $data){
  66. if (! empty($data['button'])) {
  67. $toUpdate = [];
  68. $toInsert = [];
  69. foreach ($data['button'] as $key => $value) {
  70. $row = [
  71. 'menu_id' => $id,
  72. 'title' => $value['title'],
  73. 'sort' => $key,
  74. 'func' => $value['func'],
  75. ];
  76. if (!empty($value['id'])) {
  77. $row['id'] = $value['id'];
  78. $toUpdate[] = $row;
  79. } else {
  80. $row['crt_time'] = $time;
  81. $toInsert[] = $row;
  82. }
  83. }
  84. // 1. 批量插入
  85. if (! empty($toInsert)) SysMenuButton::insert($toInsert);
  86. // 2. 批量更新
  87. if(! empty($toUpdate)){
  88. foreach ($toUpdate as $updateRow) {
  89. $id = $updateRow['id'];
  90. unset($updateRow['id']);
  91. SysMenuButton::where('id', $id)->update($updateRow);
  92. }
  93. }
  94. }
  95. }
  96. public function del($data){
  97. if($this->isEmpty($data,'id')) return [false,'菜单ID不能为空'];
  98. DB::beginTransaction();
  99. try {
  100. $time = time();
  101. SysMenu::where('id',$data['id'])->update([
  102. 'del_time' => $time
  103. ]);
  104. SysMenuButton::where('del_time',0)->where('menu_id',$data['id'])->update([
  105. 'del_time' => $time
  106. ]);
  107. RoleMenu::where('del_time',0)->where('menu_id',$data['id'])->update([
  108. 'del_time' => $time
  109. ]);
  110. RoleMenuButton::where('del_time',0)->where('menu_id',$data['id'])->update([
  111. 'del_time' => $time
  112. ]);
  113. DB::commit();
  114. }catch (\Exception $exception){
  115. DB::rollBack();
  116. return [false,$exception->getMessage()];
  117. }
  118. return [true,''];
  119. }
  120. public function menuList($data, $user){
  121. $return = [];
  122. $type = $data['type'] ?? "";
  123. $sysList = SysMenu::where('del_time',0)
  124. ->select('title','icon','uri','parent_id','sort','id','is_authority', 'state')
  125. ->orderBy('sort','desc')
  126. ->get()
  127. ->toArray();
  128. $button = SysMenuButton::where('del_time',0)
  129. ->select('id','title','sort','func','menu_id')
  130. ->get()->toArray();
  131. if(empty($type)){
  132. $return = $this->fillMenuButton($button,$sysList, $user);
  133. }elseif($type == "all"){
  134. $return_one = $this->fillMenuButton($button, $sysList, $user);
  135. $return_two = $this->returnTwo($sysList, $user);
  136. $return_three = $this->fillMenuButton($button, $sysList, $user,2);
  137. $return = [
  138. 'one' => $return_one,
  139. 'two' => $return_two,
  140. 'three' => $return_three,
  141. ];
  142. }
  143. return [true, $return];
  144. }
  145. public function menuRule($data, $is_check = true){
  146. if($this->isEmpty($data,'title')) return [false,'名称不能为空!'];
  147. if($this->isEmpty($data,'parent_id')) return [false,'父级不存在!'];
  148. //菜单
  149. if($is_check){
  150. $bool = SysMenu::where('title',$data['title'])
  151. ->where('del_time',0)
  152. ->exists();
  153. }else{
  154. if($this->isEmpty($data,'id')) return [false,'ID不能为空!'];
  155. $bool = SysMenu::where('title',$data['title'])
  156. ->where('id','<>',$data['id'])
  157. ->where('del_time',0)
  158. ->exists();
  159. $menu_button = SysMenuButton::where('del_time',0)
  160. ->where('menu_id',$data['id'])
  161. ->pluck('id')->all();
  162. }
  163. if($bool) return [false,'菜单名称已经存在'];
  164. //按钮
  165. if(! empty($data['button'])){
  166. $title = array_column($data['button'],'title');
  167. $title = array_map(function($val) {
  168. return $val !== null ? $val : "";
  169. }, $title);
  170. $title_count = array_count_values($title);
  171. foreach ($title as $value){
  172. if(empty($value)) return [false,'按钮名称不能为空!'];
  173. if($title_count[$value] > 1) return [false,'按钮名称不能重复'];
  174. }
  175. }
  176. $del = [];
  177. if(! empty($menu_button)){
  178. $submit = array_column($data['button'],'id');
  179. foreach ($menu_button as $value){
  180. if(! in_array($value, $submit)) $del[] = $value;
  181. }
  182. }
  183. return [true, $del];
  184. }
  185. public function menuMove($data){
  186. if($this->isEmpty($data,'id')) return [false,'ID不能为空!'];
  187. if($this->isEmpty($data,'move')) return [false,'移动不能能为空!'];
  188. //移动项
  189. $model = new SysMenu();
  190. $res = $model->where('id', $data['id'])->first();
  191. if($data['move'] == 1 || $data['move'] == -1){
  192. //替项目
  193. $moveModel = $model->where('del_time',0)->where('parent_id',$res->parent_id);
  194. //下移-1 上移1
  195. $data['move'] == 1 ? $moveModel->orderby('sort','desc')->where('sort','<', $res['sort']) : $moveModel->orderby('sort','asc')->where('sort','>', $res['sort']);
  196. $moveRes = $moveModel->first();
  197. if(! $moveRes) return [false, '移动失败'];
  198. $weightOne = $res->sort;
  199. $weightTwo = $moveRes->sort;
  200. $res->sort = $weightTwo;
  201. $res->save();
  202. $moveRes->sort = $weightOne;
  203. $moveRes->save();
  204. }elseif($data['move'] == 'top' || $data['move'] == 'bottom'){
  205. if($data['move'] == 'top'){
  206. $sort = $model->where('del_time',0)->where('parent_id',$res->parent_id)->max('sort');
  207. if($sort == $res->sort) return [false,'已经置顶,移动失败!'];
  208. $res->sort = $sort + 1;
  209. }elseif($data['move'] == 'bottom'){
  210. $sort = $model->where('del_time',0)->where('parent_id',$res->parent_id)->min('sort');
  211. if($sort == $res->sort) return [false,'已经置底部,移动失败!'];
  212. $res->sort = $sort - 1;
  213. }
  214. $res->save();
  215. }else{
  216. return [false, '异常参数'];
  217. }
  218. return [true,''];
  219. }
  220. public function fillMenuButton($button, $menu, $user, $type = 1)
  221. {
  222. // 1. 预处理所有按钮池(合并配置中的特殊按钮)
  223. $allButtons = collect($button)->concat(config('specialButton') ?? [])->groupBy('menu_id');
  224. // 2. 获取权限基础数据(如果是超管,这两个值为空,逻辑依然兼容)
  225. $isSuper = ($user['is_admin'] == Employee::IS_ADMIN_TWO);
  226. $roleButtons = $isSuper ? [] : (new EmployeeService())->fillRoleButton($user['role_ids'] ?? []);
  227. $allowedMenuIds = $isSuper ? [] : $this->getMenuIDByRoleInList($user);
  228. $result = [];
  229. foreach ($menu as $m) {
  230. $menuId = $m['id'];
  231. // 权限过滤:非超管且不在权限内,跳过
  232. if (!$isSuper && !in_array($menuId, $allowedMenuIds)) continue;
  233. // 计算当前菜单拥有的按钮
  234. if ($isSuper) {
  235. $btns = $allButtons->get($menuId) ?? [];
  236. } else {
  237. // 取交集:只返回该角色拥有的按钮数据
  238. $myBtnIds = $roleButtons[$menuId] ?? [];
  239. $btnPool = collect($allButtons->get($menuId))->keyBy('id');
  240. $btns = collect($myBtnIds)->map(fn($id) => $btnPool->get($id))->filter()->values();
  241. }
  242. // 3. 根据 type 返回不同的数据结构
  243. if ($type == 1) {
  244. // 完整模式:保留原菜单所有字段
  245. $m['button'] = $btns;
  246. $result[] = $m;
  247. } else {
  248. // 精简模式:只给前端路由用的字段
  249. $result[] = [
  250. 'id' => $menuId,
  251. 'uri' => $m['uri'] ?? '',
  252. 'button' => $btns,
  253. ];
  254. }
  255. }
  256. return $result;
  257. }
  258. public function fillMenuButton1($button, $menu, $user, $type = 1){
  259. $button_map = [];
  260. $special_button = config('specialButton') ?? [];
  261. foreach ($special_button as $value){
  262. $button[] = $value;
  263. }
  264. foreach ($button as $value){
  265. $button_map[$value['menu_id']][] = $value;
  266. }
  267. if($type == 1){
  268. if($user['is_admin'] == Employee::IS_ADMIN_TWO){
  269. //管理员
  270. foreach ($menu as $key => $value){
  271. $menu[$key]['button'] = $button_map[$value['id']] ?? [];
  272. }
  273. return $menu;
  274. }else{
  275. //人员所拥有的菜单ID
  276. $menu_id = $this->getMenuIDByRoleInList($user);
  277. //角色
  278. $role_id = $user['role_ids'] ?? [];
  279. //角色下拥有的菜单里按钮
  280. $role_button = (new EmployeeService())->fillRoleButton($role_id);
  281. foreach ($menu as $key => $value){
  282. $result = [];
  283. if(! in_array($value['id'], $menu_id)) {
  284. unset($menu[$key]);
  285. continue;
  286. }
  287. $bt = $role_button[$value['id']] ?? [];
  288. $button_tmp = $button_map[$value['id']] ?? [];
  289. foreach ($bt as $b){
  290. if(isset($button_tmp[$b])) $result[] = $button_tmp[$b];
  291. }
  292. $menu[$key]['button'] = $result;
  293. }
  294. return array_values($menu);
  295. }
  296. }else{
  297. $object = [];
  298. if($user['is_admin'] == Employee::IS_ADMIN_TWO){
  299. //管理员
  300. foreach ($menu as $value){
  301. $object[] = [
  302. 'id' => $value['id'],
  303. 'uri' => $value['uri'],
  304. 'button' => $button_map[$value['id']] ?? [],
  305. ];
  306. }
  307. }else{
  308. //人员所拥有的菜单数据
  309. $role_menu = $this->getMenuDataByRoleInList($user);
  310. if(empty($role_menu)) return $object;
  311. $menu_map = array_column($menu,'uri','id');
  312. //角色
  313. $role_id = $user['role_ids'] ?? [];
  314. //角色下拥有的菜单里按钮
  315. $role_button = (new EmployeeService())->fillRoleButton($role_id);
  316. foreach ($role_menu as $value){
  317. $result = [];
  318. $bt = $role_button[$value['menu_id']] ?? [];
  319. $button_tmp = $button_map[$value['menu_id']] ?? [];
  320. $button_tmp = array_column($button_tmp,null,'id');
  321. foreach ($bt as $b){
  322. if(isset($button_tmp[$b])) $result[] = $button_tmp[$b];
  323. }
  324. $object[] = [
  325. 'id' => $value['menu_id'],
  326. 'uri' => $menu_map[$value['menu_id']] ?? '',
  327. 'button' => $result,
  328. ];
  329. }
  330. }
  331. return $object;
  332. }
  333. }
  334. private function returnTwo($sysList, $user){
  335. //人员所拥有的菜单
  336. $menu = $this->getMenuIDByRoleInList($user);
  337. foreach ($sysList as $key => $value){
  338. if($value['state'] <= 0) unset($sysList[$key]);
  339. if($user['is_admin'] != Employee::IS_ADMIN_TWO && ! in_array($value['id'], $menu)) unset($sysList[$key]);
  340. }
  341. $list = array_values($sysList);
  342. $return = $this->makeTree(0,$list);
  343. return $this->set_sort_circle($return);;
  344. }
  345. //通过角色获取菜单ID
  346. public function getMenuIDByRoleInList($user){
  347. $role_id = $user['role_ids'] ?? [];
  348. if(empty($role_id)) return [];
  349. return RoleMenu::whereIn('role_id', $role_id)
  350. ->where('del_time',0)
  351. ->pluck('menu_id')
  352. ->all();
  353. }
  354. public function getMenuDataByRoleInList($user){
  355. $role_id = $user['role_ids'] ?? [];
  356. if(empty($role_id)) return [];
  357. return RoleMenu::whereIn('role_id',$role_id)
  358. ->where('del_time',0)
  359. ->select('menu_id','type')
  360. ->get()->toArray();
  361. }
  362. public function getMap($menu_id){
  363. $menu_id = array_filter((array)$menu_id);
  364. if (empty($menu_id)) return [];
  365. return SysMenu::whereIn('id', $menu_id)
  366. ->pluck('title', 'id')
  367. ->toArray();
  368. }
  369. }