Rule.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. namespace app\admin\controller\auth;
  3. use ba\Tree;
  4. use Throwable;
  5. use app\admin\model\AdminRule;
  6. use app\admin\model\AdminGroup;
  7. use app\common\controller\Backend;
  8. class Rule extends Backend
  9. {
  10. protected string|array $preExcludeFields = ['create_time', 'update_time'];
  11. protected string|array $defaultSortField = ['weigh' => 'desc'];
  12. protected string|array $quickSearchField = 'title';
  13. /**
  14. * @var object
  15. * @phpstan-var AdminRule
  16. */
  17. protected object $model;
  18. /**
  19. * @var Tree
  20. */
  21. protected Tree $tree;
  22. /**
  23. * 远程select初始化传值
  24. * @var array
  25. */
  26. protected array $initValue;
  27. /**
  28. * 搜索关键词
  29. * @var string
  30. */
  31. protected string $keyword;
  32. /**
  33. * 是否组装Tree
  34. * @var bool
  35. */
  36. protected bool $assembleTree;
  37. /**
  38. * 开启模型验证
  39. * @var bool
  40. */
  41. protected bool $modelValidate = false;
  42. public function initialize(): void
  43. {
  44. parent::initialize();
  45. // 防止 URL 中的特殊符号被默认的 filter 函数转义
  46. $this->request->filter('clean_xss');
  47. $this->model = new AdminRule();
  48. $this->tree = Tree::instance();
  49. $isTree = $this->request->param('isTree', true);
  50. $this->initValue = $this->request->get('initValue/a', []);
  51. $this->initValue = array_filter($this->initValue);
  52. $this->keyword = $this->request->request('quickSearch', '');
  53. $this->assembleTree = $isTree && !$this->initValue; // 有初始化值时不组装树状(初始化出来的值更好看)
  54. }
  55. public function index(): void
  56. {
  57. if ($this->request->param('select')) {
  58. $this->select();
  59. }
  60. $this->success('', [
  61. 'list' => $this->getMenus(),
  62. 'remark' => get_route_remark(),
  63. ]);
  64. }
  65. /**
  66. * 添加
  67. */
  68. public function add(): void
  69. {
  70. if ($this->request->isPost()) {
  71. $data = $this->request->post();
  72. if (!$data) {
  73. $this->error(__('Parameter %s can not be empty', ['']));
  74. }
  75. $data = $this->excludeFields($data);
  76. if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
  77. $data[$this->dataLimitField] = $this->auth->id;
  78. }
  79. $result = false;
  80. $this->model->startTrans();
  81. try {
  82. // 模型验证
  83. if ($this->modelValidate) {
  84. $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  85. if (class_exists($validate)) {
  86. $validate = new $validate();
  87. if ($this->modelSceneValidate) $validate->scene('add');
  88. $validate->check($data);
  89. }
  90. }
  91. $result = $this->model->save($data);
  92. // 检查所有非超管的分组是否应该拥有此权限
  93. if (!empty($data['pid'])) {
  94. $groups = AdminGroup::where('rules', '<>', '*')->select();
  95. foreach ($groups as $group) {
  96. $rules = explode(',', $group->rules);
  97. if (in_array($data['pid'], $rules) && !in_array($this->model->id, $rules)) {
  98. $rules[] = $this->model->id;
  99. $group->rules = implode(',', $rules);
  100. $group->save();
  101. }
  102. }
  103. }
  104. $this->model->commit();
  105. } catch (Throwable $e) {
  106. $this->model->rollback();
  107. $this->error($e->getMessage());
  108. }
  109. if ($result !== false) {
  110. $this->success(__('Added successfully'));
  111. } else {
  112. $this->error(__('No rows were added'));
  113. }
  114. }
  115. $this->error(__('Parameter error'));
  116. }
  117. /**
  118. * 编辑
  119. * @throws Throwable
  120. */
  121. public function edit(): void
  122. {
  123. $id = $this->request->param($this->model->getPk());
  124. $row = $this->model->find($id);
  125. if (!$row) {
  126. $this->error(__('Record not found'));
  127. }
  128. $dataLimitAdminIds = $this->getDataLimitAdminIds();
  129. if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) {
  130. $this->error(__('You have no permission'));
  131. }
  132. if ($this->request->isPost()) {
  133. $data = $this->request->post();
  134. if (!$data) {
  135. $this->error(__('Parameter %s can not be empty', ['']));
  136. }
  137. $data = $this->excludeFields($data);
  138. $result = false;
  139. $this->model->startTrans();
  140. try {
  141. // 模型验证
  142. if ($this->modelValidate) {
  143. $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  144. if (class_exists($validate)) {
  145. $validate = new $validate();
  146. if ($this->modelSceneValidate) $validate->scene('edit');
  147. $validate->check($data);
  148. }
  149. }
  150. if (isset($data['pid']) && $data['pid'] > 0) {
  151. // 满足意图并消除副作用
  152. $parent = $this->model->where('id', $data['pid'])->find();
  153. if ($parent['pid'] == $row['id']) {
  154. $parent->pid = 0;
  155. $parent->save();
  156. }
  157. }
  158. $result = $row->save($data);
  159. $this->model->commit();
  160. } catch (Throwable $e) {
  161. $this->model->rollback();
  162. $this->error($e->getMessage());
  163. }
  164. if ($result !== false) {
  165. $this->success(__('Update successful'));
  166. } else {
  167. $this->error(__('No rows updated'));
  168. }
  169. }
  170. $this->success('', [
  171. 'row' => $row
  172. ]);
  173. }
  174. /**
  175. * 删除
  176. * @throws Throwable
  177. */
  178. public function del(): void
  179. {
  180. $ids = $this->request->param('ids/a', []);
  181. // 子级元素检查
  182. $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id');
  183. foreach ($subData as $key => $subDatum) {
  184. if (!in_array($key, $ids)) {
  185. $this->error(__('Please delete the child element first, or use batch deletion'));
  186. }
  187. }
  188. parent::del();
  189. }
  190. /**
  191. * 重写select方法
  192. * @throws Throwable
  193. */
  194. public function select(): void
  195. {
  196. $data = $this->getMenus([['type', 'in', ['menu_dir', 'menu']], ['status', '=', 1]]);
  197. if ($this->assembleTree) {
  198. $data = $this->tree->assembleTree($this->tree->getTreeArray($data, 'title'));
  199. }
  200. $this->success('', [
  201. 'options' => $data
  202. ]);
  203. }
  204. /**
  205. * 获取菜单列表
  206. * @throws Throwable
  207. */
  208. protected function getMenus($where = []): array
  209. {
  210. $pk = $this->model->getPk();
  211. $initKey = $this->request->get("initKey/s", $pk);
  212. $ids = $this->auth->getRuleIds();
  213. // 如果没有 * 则只获取用户拥有的规则
  214. if (!in_array('*', $ids)) {
  215. $where[] = ['id', 'in', $ids];
  216. }
  217. if ($this->keyword) {
  218. $keyword = explode(' ', $this->keyword);
  219. foreach ($keyword as $item) {
  220. $where[] = [$this->quickSearchField, 'like', '%' . $item . '%'];
  221. }
  222. }
  223. if ($this->initValue) {
  224. $where[] = [$initKey, 'in', $this->initValue];
  225. }
  226. // 读取用户组所有权限规则
  227. $rules = $this->model
  228. ->where($where)
  229. ->order($this->queryOrderBuilder())
  230. ->select()
  231. ->toArray();
  232. // 如果要求树状,此处先组装好 children
  233. return $this->assembleTree ? $this->tree->assembleChild($rules) : $rules;
  234. }
  235. }