MiddleGroundService.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. <?php
  2. namespace App\Service;
  3. use App\Model\Depart;
  4. use App\Model\Employee;
  5. use App\Model\EmployeeDepartPermission;
  6. use App\Model\EmployeeRole;
  7. use App\Model\Role;
  8. use App\Model\RoleMenu;
  9. use App\Model\RoleMenuButton;
  10. use App\Model\SysMenu;
  11. use App\Model\SysMenuButton;
  12. use App\Model\UseRangeDetails;
  13. use App\Model\WorkRangeDetails;
  14. use Illuminate\Support\Facades\DB;
  15. use Illuminate\Support\Facades\Hash;
  16. class MiddleGroundService extends Service
  17. {
  18. // 角色 ---------------------------------------
  19. public function roleEdit($data,$user){
  20. list($status,$msg) = $this->roleRule($data,$user, false);
  21. if(!$status) return [$status,$msg];
  22. $model = new Role();
  23. $model = $model->where('id',$data['id'])->first();
  24. $model->title = $data['title'];
  25. $model->tree_type = 2;
  26. $model->save();
  27. return [true,''];
  28. }
  29. public function roleAdd($data,$user){
  30. list($status,$msg) = $this->roleRule($data,$user);
  31. if(!$status) return [$status,$msg];
  32. $model = new Role();
  33. $model->title = $data['title'] ;
  34. $model->top_depart_id = $user['top_depart_id'];
  35. $model->tree_type = 2;
  36. $model->save();
  37. return [true,''];
  38. }
  39. public function roleDel($data, $user){
  40. if($this->isEmpty($data,'id')) return [false,'ID必须!'];
  41. $bool = EmployeeRole::where('del_time',0)
  42. ->whereIn('role_id',$data['id'])
  43. ->exists();
  44. if($bool) return [false,'角色已绑定人员'];
  45. try {
  46. DB::beginTransaction();
  47. $time = time();
  48. Role::where('id',$data['id'])->update([
  49. 'del_time' => $time
  50. ]);
  51. RoleMenu::where('del_time',0)->where('role_id',$data['id'])->update([
  52. 'del_time' => $time
  53. ]);
  54. RoleMenuButton::where('del_time',0)->where('role_id',$data['id'])->update([
  55. 'del_time' => $time
  56. ]);
  57. DB::commit();
  58. }catch (\Exception $exception){
  59. DB::rollBack();
  60. return [false,$exception->getMessage()];
  61. }
  62. return [true, ''];
  63. }
  64. public function roleList($data,$user){
  65. $model = Role::TopClear($user,$data);
  66. $model = $model->where('del_time',0)
  67. ->select('title','crt_time','id','upd_time')
  68. ->orderBy('id','desc');
  69. if(! empty($data['title'])) $model->where('title', 'LIKE', '%' . $data['title'] . '%');
  70. $list = $this->limit($model,'',$data);
  71. return [true, $list];
  72. }
  73. public function roleRule(&$data,$user, $is_check = true){
  74. if($this->isEmpty($data,'title')) return [false,'名称不能为空'];
  75. if($is_check){
  76. $bool = Role::where('title',$data['title'])
  77. ->where('top_depart_id', $user['top_depart_id'])
  78. ->where('del_time',0)
  79. ->exists();
  80. if($bool) return [false,'角色名称已存在'];
  81. }else{
  82. if($this->isEmpty($data,'id')) return [false,'ID不能为空'];
  83. $top_depart_id = Role::where('id',$data['id'])->value('top_depart_id');
  84. $bool = Role::where('title',$data['title'])
  85. ->where('top_depart_id',$top_depart_id)
  86. ->where('id','<>',$data['id'])
  87. ->where('del_time',0)
  88. ->exists();
  89. if($bool) return [false,'角色名称已存在'];
  90. }
  91. return [true, ''];
  92. }
  93. public function roleMenu($data){
  94. if(empty($data['role_id'])) return [false,'角色不能为空!'];
  95. if(empty($data['menu'])) return [false,'菜单数据不能为空!'];
  96. DB::beginTransaction();
  97. try {
  98. RoleMenu::where('del_time',0)->where('role_id',$data['role_id'])->update(['del_time' => time()]);
  99. RoleMenuButton::where('del_time',0)->where('role_id',$data['role_id'])->update(['del_time' => time()]);
  100. $insert = $insert2 = [];
  101. foreach ($data['menu'] as $t){
  102. $insert[] = [
  103. 'role_id' => $data['role_id'],
  104. 'menu_id' => $t['menu_id'],
  105. 'type' => $t['type'],
  106. 'crt_time' => time()
  107. ];
  108. if(! empty($t['button'])){
  109. foreach ($t['button'] as $b){
  110. $insert2[] = [
  111. 'role_id' => $data['role_id'],
  112. 'menu_id' => $t['menu_id'],
  113. 'button_id' => $b,
  114. 'crt_time' => time()
  115. ];
  116. }
  117. RoleMenuButton::insert($insert2);
  118. }
  119. }
  120. RoleMenu::insert($insert);
  121. DB::commit();
  122. }catch (\Throwable $exception){
  123. DB::rollBack();
  124. return [false,$exception->getMessage()];
  125. }
  126. return [true, ''];
  127. }
  128. public function roleDetail($data){
  129. if(empty($data['role_id'])) return [false,'请选择角色'];
  130. $role = Role::where('id',$data['role_id'])
  131. ->where('del_time',0)
  132. ->select('id','title')
  133. ->first();
  134. if(empty($role)) return [false,'角色不存在或已被删除'];
  135. $role = $role->toArray();
  136. $menu = RoleMenu::where('role_id',$data['role_id'])
  137. ->where('del_time',0)
  138. ->select('menu_id','type')
  139. ->get()->toArray();
  140. $button = $this->fillRoleButton([$data['role_id']]);
  141. foreach ($menu as $key => $value){
  142. $menu[$key]['button'] = $button[$value['menu_id']] ?? [];
  143. }
  144. $role['menu'] = $menu;
  145. return [true, $role];
  146. }
  147. public function fillRoleButton($role_id){
  148. $button = RoleMenuButton::whereIn('role_id',$role_id)
  149. ->where('del_time',0)
  150. ->select('menu_id','button_id')
  151. ->get()->toArray();
  152. $button_map = [];
  153. foreach ($button as $value){
  154. if(! isset($button_map[$value['menu_id']])){
  155. $button_map[$value['menu_id']][] = $value['button_id'];
  156. }else{
  157. if(! in_array($value['button_id'], $button_map[$value['menu_id']])) $button_map[$value['menu_id']][] = $value['button_id'];
  158. }
  159. }
  160. return $button_map;
  161. }
  162. public function initializationCompanyList($data, $user){
  163. $model = Depart::where('del_time',0)
  164. ->where('parent_id', 0)
  165. ->select('*')
  166. ->orderby('id', 'desc');
  167. if(! empty($data['title'])) $model->where('title', 'LIKE', '%'.$data['title'].'%');
  168. if(! empty($data['code'])) $model->where('code', 'LIKE', '%'.$data['code'].'%');
  169. $list = $this->limit($model,'',$data);
  170. return [true, $list];
  171. }
  172. // 公司初始化 返回 公司后台管理员账户 密码
  173. public function initializationCompany($data, $user){
  174. if(empty($data['title'])) return [false, '公司名称不能为空'];
  175. if(empty($data['code'])) return [false, '公司代码不能为空'];
  176. // ^[A-Za-z]+$ 表示从头到尾只能是英文字母(不区分大小写)
  177. if (! preg_match('/^[A-Za-z]+$/', $data['code']) || mb_strlen($data['code']) < 4) return [false, "公司代码必须全为英文且长度需大于等于 4 位"];
  178. $exists = Depart::where('parent_id', 0)
  179. ->where('del_time', 0)
  180. ->where(function($query) use ($data) {
  181. $query->where('title', $data['title'])
  182. ->orWhere('code', $data['code']);
  183. })
  184. ->exists();
  185. if($exists) return [false, '公司名称或公司代码已存在,新增失败'];
  186. $account = $data['code'] . "_" . 'admin';
  187. $exists = Employee::where('del_time', 0)
  188. ->where('account', $account)
  189. ->exists();
  190. if($exists) return [false, '创建账号已存在,新增失败'];
  191. try {
  192. DB::beginTransaction();
  193. //创建公司
  194. $model = new Depart();
  195. $model->parent_id = 0;
  196. $model->title = $data['title'];
  197. $model->code = $data['code'];
  198. $model->top_depart_id = 0;
  199. $model->save();
  200. //公司ID
  201. $top_depart_id = $model->id;
  202. $password = $this->generateAt8CharPassword();
  203. //创建账号
  204. $model_2 = new Employee();
  205. $model_2->title = $data['title'];
  206. $model_2->account = $account;
  207. $model_2->password = Hash::make($password);
  208. $model_2->is_admin = Employee::IS_ADMIN_TWO;
  209. $model_2->top_depart_id = $top_depart_id;
  210. $model_2->state = Employee::TYPE_ONE;
  211. $model_2->save();
  212. $employee_id = $model_2->id;
  213. //关联人员的部门初始信息
  214. $model_3 = new EmployeeDepartPermission();
  215. $model_3->employee_id = $employee_id;
  216. $model_3->depart_id = 0;
  217. $model_3->top_depart_id = $top_depart_id;
  218. $model_3->save();
  219. //公司上班时段
  220. $work_range[] = [
  221. 'top_depart_id' => $top_depart_id,
  222. 'start_time_hour' => 9,
  223. 'start_time_min' => 0,
  224. 'end_time_hour' => 12,
  225. 'end_time_min' => 0,
  226. 'total_work_min' => 180,
  227. ];
  228. $work_range[] = [
  229. 'top_depart_id' => $top_depart_id,
  230. 'start_time_hour' => 13,
  231. 'start_time_min' => 0,
  232. 'end_time_hour' => 18,
  233. 'end_time_min' => 0,
  234. 'total_work_min' => 300,
  235. ];
  236. WorkRangeDetails::insert($work_range);
  237. DB::commit();
  238. }catch (\Throwable $exception){
  239. DB::rollBack();
  240. return [false, $exception->getMessage()];
  241. }
  242. return [true, ['account' => $account, 'password' => $password]];
  243. }
  244. public function setUseRange($data, $user){
  245. if(empty($data['id'])) return [false, 'ID不能为空'];
  246. if(empty($data['use_range'])) return [false, '授权时段不能为空'];
  247. $validRanges = []; // 用来存放已经校验过格式的合规时段
  248. $insert = [];
  249. foreach ($data['use_range'] as $index => $range) {
  250. $num = $index + 1;
  251. // 1. 基础非空与格式校验
  252. if (empty($range['start_time']) || empty($range['end_time'])) {
  253. return [false, "第 {$num} 行时段的开始或结束时间不能为空"];
  254. }
  255. if (!preg_match('/^\d{4}-\d{2}$/', $range['start_time']) || !preg_match('/^\d{4}-\d{2}$/', $range['end_time'])) {
  256. return [false, "第 {$num} 行时段格式错误,必须为 YYYY-MM"];
  257. }
  258. if ($range['start_time'] > $range['end_time']) {
  259. return [false, "第 {$num} 行时段有误:开始时间不能大于结束时间"];
  260. }
  261. // 2. 核心:直接拿当前组,去和之前已经验证合法的数组做“两两相交”比对
  262. foreach ($validRanges as $passed) {
  263. if ($range['start_time'] <= $passed['end_time'] && $range['end_time'] >= $passed['start_time']) {
  264. return [false, "时间段存在冲突:[{$range['start_time']}~{$range['end_time']}] 与 [{$passed['start_time']}~{$passed['end_time']}] 相交重复"];
  265. }
  266. }
  267. // 3. 没冲突,说明当前组安全,存入蓄水池,供下一轮循环比对
  268. $validRanges[] = $range;
  269. $insert[] = [
  270. 'top_depart_id' => $data['id'],
  271. 'start_time' => $range['start_time'],
  272. 'start_time_stamp' => strtotime($range['start_time']),
  273. 'end_time' => $range['end_time'],
  274. 'end_time_stamp' => strtotime("last day of " . $range['end_time'] . " 23:59:59"),
  275. ];
  276. }
  277. try {
  278. DB::beginTransaction();
  279. $time = time();
  280. UseRangeDetails::where('del_time',0)
  281. ->where('top_depart_id', $data['id'])
  282. ->update(['del_time' => $time]);
  283. UseRangeDetails::insert($insert);
  284. DB::commit();
  285. }catch (\Throwable $exception){
  286. DB::rollBack();
  287. return [false, $exception->getMessage()];
  288. }
  289. return [true, ''];
  290. }
  291. function generateAt8CharPassword() {
  292. $lettersNumbers = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
  293. $password = '@'; // 1. 先把固定的 @ 放进去
  294. // 2. 随机抽取 6 位英文或数字
  295. for ($i = 0; $i < 6; $i++) {
  296. $password .= $lettersNumbers[random_int(0, strlen($lettersNumbers) - 1)];
  297. }
  298. // 3. 打乱顺序,让 @ 的位置不固定
  299. return str_shuffle($password);
  300. }
  301. // 菜单
  302. public function menuList($data, $user){
  303. $type = $data['type'] ?? "";
  304. if(empty($type)){
  305. //权限
  306. $sysList = SysMenu::where('del_time',0)
  307. ->where('type', SysMenu::type_zero)
  308. ->select('title','icon','uri','parent_id','sort','id', 'state')
  309. ->orderBy('sort','desc')
  310. ->get()
  311. ->toArray();
  312. $button = SysMenuButton::where('del_time',0)
  313. ->select('id','title','sort','func','menu_id')
  314. ->get()->toArray();
  315. $return = $this->fillMenuButton($button,$sysList, $user);
  316. }elseif($type == "all"){
  317. $sysList = SysMenu::where('del_time',0)
  318. ->where('type', SysMenu::type_one)
  319. ->select('title','icon','uri','parent_id','sort','id', 'state')
  320. ->orderBy('sort','desc')
  321. ->get()
  322. ->toArray();
  323. //侧边栏
  324. $return = $this->returnTwo($sysList, $user);
  325. $return = [
  326. 'one' => $sysList,
  327. 'two' => $return,
  328. ];
  329. }
  330. return [true, $return];
  331. }
  332. private function returnTwo($sysList, $user){
  333. foreach ($sysList as $key => $value){
  334. if($value['state'] <= 0) unset($sysList[$key]);
  335. }
  336. $list = array_values($sysList);
  337. $return = $this->makeTree(0,$list);
  338. return $this->set_sort_circle($return);;
  339. }
  340. public function fillMenuButton($button, $menu, $user)
  341. {
  342. // 1. 预处理所有按钮池(合并配置中的特殊按钮)
  343. $allButtons = collect($button)->concat(config('specialButton') ?? [])->groupBy('menu_id');
  344. // 2. 获取权限基础数据
  345. $isSuper = ($user['is_admin'] == Employee::IS_ADMIN_THREE);
  346. $result = [];
  347. foreach ($menu as $m) {
  348. $menuId = $m['id'];
  349. // 权限过滤:非超管
  350. if (!$isSuper) continue;
  351. // 计算当前菜单拥有的按钮
  352. $btns = $allButtons->get($menuId) ?? [];
  353. $m['button'] = $btns;
  354. $result[] = $m;
  355. }
  356. return $result;
  357. }
  358. // 管理员
  359. public function employeeCommon($data,$user){
  360. $model = Employee::where('del_time',0)
  361. ->where('is_admin', Employee::IS_ADMIN_TWO)
  362. ->select('id', 'account', 'crt_time', 'top_depart_id','title')
  363. ->orderBy('id','desc');
  364. if(! empty($data['id'])) $model->whereIn('id', $data['id']);
  365. if(! empty($data['title'])) $model->where('title', 'LIKE', '%'.$data['title'].'%');
  366. if(! empty($data['mobile'])) $model->where('mobile', 'LIKE', '%'.$data['mobile'].'%');
  367. if(! empty($data['role'])) {
  368. $emp = EmployeeRole::where('role_id',$data['role'])
  369. ->where('del_time',0)
  370. ->select('employee_id')->get()->toArray();
  371. $model->whereIn('id',array_column($emp,'employee_id'));
  372. }
  373. return $model;
  374. }
  375. public function employeeList($data,$user){
  376. $model = $this->employeeCommon($data, $user);
  377. $list = $this->limit($model,'',$data);
  378. $list = $this->organizationEmployeeData($list, $data, $user);
  379. return [true, $list];
  380. }
  381. public function organizationEmployeeData($data, $ergs, $user)
  382. {
  383. if (empty($data['data'])) return $data;
  384. // 获取员工ID并查询扩展数据
  385. $employee_ids = array_column($data['data'], 'id');
  386. list($status, $extraMap) = $this->getEmployee($employee_ids);
  387. $depart_map = Depart::whereIn('id', array_unique(array_column($data['data'],'top_depart_id')))
  388. ->pluck('title', 'id')
  389. ->toArray();
  390. foreach ($data['data'] as &$item) {
  391. $id = $item['id'];
  392. $extra = $extraMap[$id] ?? null;
  393. $item['role'] = $extra['role_ids'] ?? [];
  394. $item['role_name'] = isset($extra['role_names']) ? implode(',', $extra['role_names']) : '';
  395. $item['top_depart_title'] = $depart_map[$item['top_depart_id']];
  396. $item['crt_time'] = !empty($item['crt_time']) ? date("Y-m-d", $item['crt_time']) : "";
  397. }
  398. return $data;
  399. }
  400. public function getEmployee(array $employee_ids)
  401. {
  402. if (empty($employee_ids)) return [false, []];
  403. // 1. 一次性获取所有角色
  404. $roles = DB::table('employee_role as a')
  405. ->join('role as b', 'a.role_id', '=', 'b.id')
  406. ->where('a.del_time', 0)
  407. ->where('b.del_time', 0)
  408. ->whereIn("a.employee_id", $employee_ids)
  409. ->select('a.employee_id', 'b.title', 'b.id')
  410. ->get();
  411. $resultMap = [];
  412. foreach ($roles as $r) {
  413. $resultMap[$r->employee_id]['role_ids'][] = $r->id;
  414. $resultMap[$r->employee_id]['role_names'][] = $r->title;
  415. }
  416. return [true, $resultMap];
  417. }
  418. public function employeeEdit($data,$user){
  419. list($status,$msg) = $this->employeeRule($data,$user,false);
  420. if(!$status) return [$status,$msg];
  421. try {
  422. DB::beginTransaction();
  423. $model = new Employee();
  424. $model = $model->where('id',$data['id'])->first();
  425. if($model->is_admin && $data['password'] !== '******') {
  426. $model->password = Hash::make($data['password']);
  427. $model->p_version = $model->p_version + 1;
  428. }
  429. $model->save();
  430. $time = time();
  431. EmployeeRole::where('employee_id',$data['id'])->update([
  432. 'del_time' => $time
  433. ]);
  434. if(! empty($data['role'])){
  435. $insert = [];
  436. foreach ($data['role'] as $value){
  437. $insert[] = [
  438. 'employee_id' => $model->id,
  439. 'role_id' => $value,
  440. 'crt_time' => $time,
  441. ];
  442. }
  443. EmployeeRole::insert($insert);
  444. }
  445. DB::commit();
  446. }catch (\Exception $exception){
  447. DB::rollBack();
  448. return [false, $exception->getMessage()];
  449. }
  450. return [true, ''];
  451. }
  452. public function employeeRule(&$data, $user, $is_add = true){
  453. if(empty($data['id'])) return [false, '管理员ID不能为空'];
  454. $bool = Employee::where('del_time',0)
  455. ->where('id', $data['id'])
  456. ->exists();
  457. if(! $bool) return [false, '管理员账户不存在或已被删除'];
  458. if(empty($data['password'])) return [false, '密码不能为空'];
  459. if(mb_strlen($data['password']) < 6) return [false, '密码长度不得小于6位长度'];
  460. return [true, ''];
  461. }
  462. public static function checkCenterUser($employee){
  463. if(empty($employee['employee_id'])) return [false, 'token错误'];
  464. if(! isset($employee['p_version'])) return [false, 'token错误'];
  465. $result = Employee::where('id', $employee['employee_id'])
  466. ->where('del_time',0)
  467. ->first();
  468. if(empty($result)) return [false, '账号不存在或已被删除'];
  469. $result = $result->toArray();
  470. if($result['is_admin'] != Employee::IS_ADMIN_THREE) return [false, '账号限制登录'];
  471. if($result['p_version'] != $employee['p_version']) return [false, '请重新登录'];
  472. return [true, $result];
  473. }
  474. }