Backend.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. namespace app\admin\library\traits;
  3. use Throwable;
  4. /**
  5. * 后台控制器trait类
  6. * 已导入到 @see \app\common\controller\Backend 中
  7. * 若需修改此类方法:请复制方法至对应控制器后进行重写
  8. */
  9. trait Backend
  10. {
  11. /**
  12. * 排除入库字段
  13. * @param array $params
  14. * @return array
  15. */
  16. protected function excludeFields(array $params): array
  17. {
  18. if (!is_array($this->preExcludeFields)) {
  19. $this->preExcludeFields = explode(',', (string)$this->preExcludeFields);
  20. }
  21. foreach ($this->preExcludeFields as $field) {
  22. if (array_key_exists($field, $params)) {
  23. unset($params[$field]);
  24. }
  25. }
  26. return $params;
  27. }
  28. /**
  29. * 查看
  30. * @throws Throwable
  31. */
  32. public function index(): void
  33. {
  34. if ($this->request->param('select')) {
  35. $this->select();
  36. }
  37. list($where, $alias, $limit, $order) = $this->queryBuilder();
  38. $res = $this->model
  39. ->field($this->indexField)
  40. ->withJoin($this->withJoinTable, $this->withJoinType)
  41. ->alias($alias)
  42. ->where($where)
  43. ->order($order)
  44. ->paginate($limit);
  45. $this->success('', [
  46. 'list' => $res->items(),
  47. 'total' => $res->total(),
  48. 'remark' => get_route_remark(),
  49. ]);
  50. }
  51. /**
  52. * 添加
  53. */
  54. public function add(): void
  55. {
  56. if ($this->request->isPost()) {
  57. $data = $this->request->post();
  58. if (!$data) {
  59. $this->error(__('Parameter %s can not be empty', ['']));
  60. }
  61. $data = $this->excludeFields($data);
  62. if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
  63. $data[$this->dataLimitField] = $this->auth->id;
  64. }
  65. $result = false;
  66. $this->model->startTrans();
  67. try {
  68. // 模型验证
  69. if ($this->modelValidate) {
  70. $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  71. if (class_exists($validate)) {
  72. $validate = new $validate();
  73. if ($this->modelSceneValidate) $validate->scene('add');
  74. $validate->check($data);
  75. }
  76. }
  77. $result = $this->model->save($data);
  78. $this->model->commit();
  79. } catch (Throwable $e) {
  80. $this->model->rollback();
  81. $this->error($e->getMessage());
  82. }
  83. if ($result !== false) {
  84. $this->success(__('Added successfully'));
  85. } else {
  86. $this->error(__('No rows were added'));
  87. }
  88. }
  89. $this->error(__('Parameter error'));
  90. }
  91. /**
  92. * 编辑
  93. * @throws Throwable
  94. */
  95. public function edit(): void
  96. {
  97. $pk = $this->model->getPk();
  98. $id = $this->request->param($pk);
  99. $row = $this->model->find($id);
  100. if (!$row) {
  101. $this->error(__('Record not found'));
  102. }
  103. $dataLimitAdminIds = $this->getDataLimitAdminIds();
  104. if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) {
  105. $this->error(__('You have no permission'));
  106. }
  107. if ($this->request->isPost()) {
  108. $data = $this->request->post();
  109. if (!$data) {
  110. $this->error(__('Parameter %s can not be empty', ['']));
  111. }
  112. $data = $this->excludeFields($data);
  113. $result = false;
  114. $this->model->startTrans();
  115. try {
  116. // 模型验证
  117. if ($this->modelValidate) {
  118. $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  119. if (class_exists($validate)) {
  120. $validate = new $validate();
  121. if ($this->modelSceneValidate) $validate->scene('edit');
  122. $data[$pk] = $row[$pk];
  123. $validate->check($data);
  124. }
  125. }
  126. $result = $row->save($data);
  127. $this->model->commit();
  128. } catch (Throwable $e) {
  129. $this->model->rollback();
  130. $this->error($e->getMessage());
  131. }
  132. if ($result !== false) {
  133. $this->success(__('Update successful'));
  134. } else {
  135. $this->error(__('No rows updated'));
  136. }
  137. }
  138. $this->success('', [
  139. 'row' => $row
  140. ]);
  141. }
  142. /**
  143. * 删除
  144. * @throws Throwable
  145. */
  146. public function del(): void
  147. {
  148. $where = [];
  149. $dataLimitAdminIds = $this->getDataLimitAdminIds();
  150. if ($dataLimitAdminIds) {
  151. $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds];
  152. }
  153. $ids = $this->request->param('ids/a', []);
  154. $where[] = [$this->model->getPk(), 'in', $ids];
  155. $data = $this->model->where($where)->select();
  156. $count = 0;
  157. $this->model->startTrans();
  158. try {
  159. foreach ($data as $v) {
  160. $count += $v->delete();
  161. }
  162. $this->model->commit();
  163. } catch (Throwable $e) {
  164. $this->model->rollback();
  165. $this->error($e->getMessage());
  166. }
  167. if ($count) {
  168. $this->success(__('Deleted successfully'));
  169. } else {
  170. $this->error(__('No rows were deleted'));
  171. }
  172. }
  173. /**
  174. * 排序 - 增量重排法
  175. * @throws Throwable
  176. */
  177. public function sortable(): void
  178. {
  179. $pk = $this->model->getPk();
  180. $move = $this->request->param('move');
  181. $target = $this->request->param('target');
  182. $order = $this->request->param("order/s") ?: $this->defaultSortField;
  183. $direction = $this->request->param('direction');
  184. $dataLimitWhere = [];
  185. $dataLimitAdminIds = $this->getDataLimitAdminIds();
  186. if ($dataLimitAdminIds) {
  187. $dataLimitWhere[] = [$this->dataLimitField, 'in', $dataLimitAdminIds];
  188. }
  189. $moveRow = $this->model->where($dataLimitWhere)->find($move);
  190. $targetRow = $this->model->where($dataLimitWhere)->find($target);
  191. if ($move == $target || !$moveRow || !$targetRow || !$direction) {
  192. $this->error(__('Record not found'));
  193. }
  194. // 当前是否以权重字段排序(只检查当前排序和默认排序字段,不检查有序保证字段)
  195. if ($order && is_string($order)) {
  196. $order = explode(',', $order);
  197. $order = [$order[0] => $order[1] ?? 'asc'];
  198. }
  199. if (!array_key_exists($this->weighField, $order)) {
  200. $this->error(__('Please use the %s field to sort before operating', [$this->weighField]));
  201. }
  202. // 开始增量重排
  203. $order = $this->queryOrderBuilder();
  204. $weigh = $targetRow[$this->weighField];
  205. // 波及行的权重值向上增加还是向下减少
  206. if ($order[$this->weighField] == 'desc') {
  207. $updateMethod = $direction == 'up' ? 'dec' : 'inc';
  208. } else {
  209. $updateMethod = $direction == 'up' ? 'inc' : 'dec';
  210. }
  211. // 与目标行权重相同的行
  212. $weighRowIds = $this->model
  213. ->where($dataLimitWhere)
  214. ->where($this->weighField, $weigh)
  215. ->order($order)
  216. ->column($pk);
  217. $weighRowsCount = count($weighRowIds);
  218. // 单个 SQL 查询中完成大于目标权重行的修改
  219. $this->model->where($dataLimitWhere)
  220. ->where($this->weighField, $updateMethod == 'dec' ? '<' : '>', $weigh)
  221. ->whereNotIn($pk, [$moveRow->$pk])
  222. ->$updateMethod($this->weighField, $weighRowsCount)
  223. ->save();
  224. // 遍历与目标行权重相同的行,每出现一行权重值将额外 +1,保证权重相同行的顺序位置不变
  225. if ($direction == 'down') {
  226. $weighRowIds = array_reverse($weighRowIds);
  227. }
  228. $moveComplete = 0;
  229. $weighRowIds = implode(',', $weighRowIds);
  230. $weighRows = $this->model->where($dataLimitWhere)
  231. ->where($pk, 'in', $weighRowIds)
  232. ->orderRaw("field($pk,$weighRowIds)")
  233. ->select();
  234. // 权重相等行
  235. foreach ($weighRows as $key => $weighRow) {
  236. // 跳过当前拖动行(相等权重数据之间的拖动时,被拖动行会出现在 $weighRows 内)
  237. if ($moveRow[$pk] == $weighRow[$pk]) {
  238. continue;
  239. }
  240. if ($updateMethod == 'dec') {
  241. $rowWeighVal = $weighRow[$this->weighField] - $key;
  242. } else {
  243. $rowWeighVal = $weighRow[$this->weighField] + $key;
  244. }
  245. // 找到了目标行
  246. if ($weighRow[$pk] == $targetRow[$pk]) {
  247. $moveComplete = 1;
  248. $moveRow[$this->weighField] = $rowWeighVal;
  249. $moveRow->save();
  250. }
  251. $rowWeighVal = $updateMethod == 'dec' ? $rowWeighVal - $moveComplete : $rowWeighVal + $moveComplete;
  252. $weighRow[$this->weighField] = $rowWeighVal;
  253. $weighRow->save();
  254. }
  255. $this->success();
  256. }
  257. /**
  258. * 加载为select(远程下拉选择框)数据,默认还是走$this->index()方法
  259. * 必要时请在对应控制器类中重写
  260. */
  261. public function select(): void
  262. {
  263. }
  264. }