SysMenuService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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. $tree_type = $data['tree_type'] ?? SysMenu::tree_type_zero;
  124. $sysList = SysMenu::where('del_time',0)
  125. ->where('type', SysMenu::type_zero)
  126. ->where('tree_type', $tree_type)
  127. ->select('title','icon','uri','parent_id','sort','id','is_authority', 'state')
  128. ->orderBy('sort','desc')
  129. ->get()
  130. ->toArray();
  131. $button = SysMenuButton::where('del_time',0)
  132. ->select('id','title','sort','func','menu_id')
  133. ->get()->toArray();
  134. if(empty($type)){
  135. $return = $this->fillMenuButton($button,$sysList, $user);
  136. }elseif($type == "all"){
  137. $return_one = $this->fillMenuButton($button, $sysList, $user);
  138. $return_two = $this->returnTwo($sysList, $user);
  139. $return_three = $this->fillMenuButton($button, $sysList, $user,2);
  140. $return = [
  141. 'one' => $return_one,
  142. 'two' => $return_two,
  143. 'three' => $return_three,
  144. ];
  145. }
  146. return [true, $return];
  147. }
  148. public function menuRule($data, $is_check = true){
  149. if($this->isEmpty($data,'title')) return [false,'名称不能为空!'];
  150. if($this->isEmpty($data,'parent_id')) return [false,'父级不存在!'];
  151. //菜单
  152. if($is_check){
  153. $bool = SysMenu::where('title',$data['title'])
  154. ->where('del_time',0)
  155. ->exists();
  156. }else{
  157. if($this->isEmpty($data,'id')) return [false,'ID不能为空!'];
  158. $bool = SysMenu::where('title',$data['title'])
  159. ->where('id','<>',$data['id'])
  160. ->where('del_time',0)
  161. ->exists();
  162. $menu_button = SysMenuButton::where('del_time',0)
  163. ->where('menu_id',$data['id'])
  164. ->pluck('id')->all();
  165. }
  166. if($bool) return [false,'菜单名称已经存在'];
  167. //按钮
  168. if(! empty($data['button'])){
  169. $title = array_column($data['button'],'title');
  170. $title = array_map(function($val) {
  171. return $val !== null ? $val : "";
  172. }, $title);
  173. $title_count = array_count_values($title);
  174. foreach ($title as $value){
  175. if(empty($value)) return [false,'按钮名称不能为空!'];
  176. if($title_count[$value] > 1) return [false,'按钮名称不能重复'];
  177. }
  178. }
  179. $del = [];
  180. if(! empty($menu_button)){
  181. $submit = array_column($data['button'],'id');
  182. foreach ($menu_button as $value){
  183. if(! in_array($value, $submit)) $del[] = $value;
  184. }
  185. }
  186. return [true, $del];
  187. }
  188. public function menuMove($data){
  189. if($this->isEmpty($data,'id')) return [false,'ID不能为空!'];
  190. if($this->isEmpty($data,'move')) return [false,'移动不能能为空!'];
  191. //移动项
  192. $model = new SysMenu();
  193. $res = $model->where('id', $data['id'])->first();
  194. if($data['move'] == 1 || $data['move'] == -1){
  195. //替项目
  196. $moveModel = $model->where('del_time',0)->where('parent_id',$res->parent_id);
  197. //下移-1 上移1
  198. $data['move'] == 1 ? $moveModel->orderby('sort','desc')->where('sort','<', $res['sort']) : $moveModel->orderby('sort','asc')->where('sort','>', $res['sort']);
  199. $moveRes = $moveModel->first();
  200. if(! $moveRes) return [false, '移动失败'];
  201. $weightOne = $res->sort;
  202. $weightTwo = $moveRes->sort;
  203. $res->sort = $weightTwo;
  204. $res->save();
  205. $moveRes->sort = $weightOne;
  206. $moveRes->save();
  207. }elseif($data['move'] == 'top' || $data['move'] == 'bottom'){
  208. if($data['move'] == 'top'){
  209. $sort = $model->where('del_time',0)->where('parent_id',$res->parent_id)->max('sort');
  210. if($sort == $res->sort) return [false,'已经置顶,移动失败!'];
  211. $res->sort = $sort + 1;
  212. }elseif($data['move'] == 'bottom'){
  213. $sort = $model->where('del_time',0)->where('parent_id',$res->parent_id)->min('sort');
  214. if($sort == $res->sort) return [false,'已经置底部,移动失败!'];
  215. $res->sort = $sort - 1;
  216. }
  217. $res->save();
  218. }else{
  219. return [false, '异常参数'];
  220. }
  221. return [true,''];
  222. }
  223. public function fillMenuButton1($button, $menu, $user, $type = 1)
  224. {
  225. // 1. 预处理所有按钮池(合并配置中的特殊按钮)
  226. $allButtons = collect($button)->concat(config('specialButton') ?? [])->groupBy('menu_id');
  227. // 2. 获取权限基础数据
  228. $isSuper = ($user['is_admin'] == Employee::IS_ADMIN_TWO);
  229. $roleButtons = $isSuper ? [] : (new EmployeeService())->fillRoleButton($user['role_ids'] ?? []);
  230. $allowedMenuIds = $isSuper ? [] : $this->getMenuIDByRoleInList($user);
  231. $result = [];
  232. foreach ($menu as $m) {
  233. $menuId = $m['id'];
  234. // 权限过滤:非超管且不在权限内,跳过
  235. if (!$isSuper && !in_array($menuId, $allowedMenuIds)) continue;
  236. // 计算当前菜单拥有的按钮
  237. if ($isSuper) {
  238. $btns = $allButtons->get($menuId) ?? [];
  239. } else {
  240. // 取交集:只返回该角色拥有的按钮数据
  241. $myBtnIds = $roleButtons[$menuId] ?? [];
  242. $btnPool = collect($allButtons->get($menuId))->keyBy('id');
  243. $btns = collect($myBtnIds)->map(fn($id) => $btnPool->get($id))->filter()->values();
  244. }
  245. // 3. 根据 type 返回不同的数据结构
  246. if ($type == 1) {
  247. // 完整模式:保留原菜单所有字段
  248. $m['button'] = $btns;
  249. $result[] = $m;
  250. } else {
  251. // 精简模式:只给前端路由用的字段
  252. $result[] = [
  253. 'id' => $menuId,
  254. 'uri' => $m['uri'] ?? '',
  255. 'button' => $btns,
  256. ];
  257. }
  258. }
  259. return $result;
  260. }
  261. public function fillMenuButton($button, $menu, $user, $type = 1)
  262. {
  263. // 1. 预处理所有按钮池(合并配置中的特殊按钮)
  264. $allButtons = collect($button)->concat(config('specialButton') ?? [])->groupBy('menu_id');
  265. // 2. 获取权限基础数据
  266. $roleButtons = (new EmployeeService())->fillRoleButton($user['role_ids'] ?? []);
  267. $allowedMenuIds = $this->getMenuIDByRoleInList($user);
  268. $result = [];
  269. foreach ($menu as $m) {
  270. $menuId = $m['id'];
  271. // 权限过滤:不在权限内,跳过
  272. if (!in_array($menuId, $allowedMenuIds)) continue;
  273. // 计算当前菜单拥有的按钮
  274. // 只返回该角色拥有的按钮数据
  275. $myBtnIds = $roleButtons[$menuId] ?? [];
  276. $btnPool = collect($allButtons->get($menuId))->keyBy('id');
  277. $btns = collect($myBtnIds)->map(fn($id) => $btnPool->get($id))->filter()->values();
  278. // 3. 根据 type 返回不同的数据结构
  279. if ($type == 1) {
  280. // 完整模式:保留原菜单所有字段
  281. $m['button'] = $btns;
  282. $result[] = $m;
  283. } else {
  284. // 精简模式:只给前端路由用的字段
  285. $result[] = [
  286. 'id' => $menuId,
  287. 'uri' => $m['uri'] ?? '',
  288. 'button' => $btns,
  289. ];
  290. }
  291. }
  292. return $result;
  293. }
  294. private function returnTwo1($sysList, $user){
  295. //人员所拥有的菜单
  296. $menu = $this->getMenuIDByRoleInList($user);
  297. foreach ($sysList as $key => $value){
  298. if($value['state'] <= 0) unset($sysList[$key]);
  299. if($user['is_admin'] != Employee::IS_ADMIN_TWO && ! in_array($value['id'], $menu)) unset($sysList[$key]);
  300. }
  301. $list = array_values($sysList);
  302. $return = $this->makeTree(0,$list);
  303. return $this->set_sort_circle($return);;
  304. }
  305. private function returnTwo($sysList, $user){
  306. //人员所拥有的菜单
  307. $menu = $this->getMenuIDByRoleInList($user);
  308. foreach ($sysList as $key => $value){
  309. if($value['state'] <= 0) unset($sysList[$key]);
  310. if(! in_array($value['id'], $menu)) unset($sysList[$key]);
  311. }
  312. $list = array_values($sysList);
  313. $return = $this->makeTree(0,$list);
  314. return $this->set_sort_circle($return);;
  315. }
  316. //通过角色获取菜单ID
  317. public function getMenuIDByRoleInList($user){
  318. $role_id = $user['role_ids'] ?? [];
  319. if(empty($role_id)) return [];
  320. return RoleMenu::whereIn('role_id', $role_id)
  321. ->where('del_time',0)
  322. ->pluck('menu_id')
  323. ->all();
  324. }
  325. public function getMenuDataByRoleInList($user){
  326. $role_id = $user['role_ids'] ?? [];
  327. if(empty($role_id)) return [];
  328. return RoleMenu::whereIn('role_id',$role_id)
  329. ->where('del_time',0)
  330. ->select('menu_id','type')
  331. ->get()->toArray();
  332. }
  333. public function getMap($menu_id){
  334. $menu_id = array_filter((array)$menu_id);
  335. if (empty($menu_id)) return [];
  336. return SysMenu::whereIn('id', $menu_id)
  337. ->pluck('title', 'id')
  338. ->toArray();
  339. }
  340. }