builder = $this->repository->newQuery(); if ($this->trashed() && $this->grid->isTrashed()) { $this->builder->onlyTrashed(); } $this->setPk($this->repository->getKeyName()); } /** * 是否有回收站 * @return bool */ public function trashed(): bool { return in_array(SoftDeletes::class, class_uses_recursive($this->repository)); } /** * 恢复数据 * @param array $ids 恢复id * @return Message */ public function restore(array $ids): Message { $this->repository->whereIn($this->getPk(), $ids)->restore(); return message_success(admin_trans('grid.restore_success')); } /** * 删除 * @param array $ids 删除id * @param bool $all 是否删除全部 * @return Message */ public function delete(array $ids, bool $all = false): Message { $arg = $all ?: $ids; $result = $this->dispatchEvent('deling', [$arg]); if ($result instanceof Message) { return $result; } if ($this->grid->isTrashed()) { $result = $this->builder->when($all, function ($query) { $query->onlyTrashed(); }, function ($query) use ($ids) { $query->whereIn($this->getPk(), $ids); })->forceDelete(); } else { $result = $this->builder->when($all, function ($query) { $query->whereRaw('1=1'); }, function ($query) use ($ids) { $query->whereIn($this->getPk(), $ids); })->delete(); } $deletedResult = $this->dispatchEvent('deleted', [$arg]); if ($deletedResult instanceof Message) { return $deletedResult; } if ($result) { return message_success(admin_trans('grid.delete_success')); } return message_error(admin_trans('grid.delete_error')); } /** * 拖拽排序 * @param int $id 排序id * @param int $sort 排序位置 * @param string $field 字段 * @return Message */ public function dragSort($id, int $sort, string $field): Message { $result = $this->dispatchEvent('sorting', [$id, $sort, $field]); if ($result instanceof Message) { return $result; } $pk = $this->getPk(); $selectRaw = "{$pk},(@rownum := @rownum+1),case when @rownum = {$sort} then @rownum := @rownum+1 else @rownum := @rownum end AS rownum"; $sortSql = $this->builder->from(Db::raw("(SELECT @rownum := -1) r," . $this->repository->getTable())) ->selectRaw($selectRaw) ->reorder($field) ->where($pk, '<>', $id) ->toSql(); $this->repository->where($pk, $id)->update([$field => $sort]); Db::connection($this->repository->getConnectionName())->statement("update {$this->repository->getTable()} inner join ({$sortSql}) a on a.{$pk}={$this->repository->getTable()}.{$pk} set `{$field}`=a.rownum", $this->builder->getBindings()); return message_success(admin_trans('grid.sort_success')); } /** * 输入框排序 * @param int $id 排序id * @param int $sort 排序位置 * @param string $field 字段 * @return Message */ public function inputSort($id, int $sort, string $field): Message { $result = $this->dispatchEvent('sorting', [$id, $sort, $field]); if ($result instanceof Message) { return $result; } $this->repository->where($this->getPk(), $id)->update([$field => $sort]); return message_success(admin_trans('grid.sort_success')); } /** * 更新 * @param array $ids 更新条件id集合 * @param array $data 更新数据 * @return Message */ public function update(array $ids, array $data): Message { $result = $this->dispatchEvent('updateing', [$ids, $data]); if ($result instanceof Message) { return $result; } foreach ($ids as $id) { $model = $this->repository->find($id); foreach ($data as $field => $value) { $model->$field = $value; } $model->save(); } $result = $this->dispatchEvent('updated', [$ids, $data]); if ($result instanceof Message) { return $result; } return message_success(admin_trans('grid.update_success')); } /** * 表格列触发排序 * @param string $field 字段 * @param string $sort 排序 asc desc * @return mixed */ public function tableSort($field, $sort) { $this->builder->reorder($field, $sort); } /** * 筛选 * @param array $rule */ public function filter(array $rule) { new Filter($this->builder, $rule); } /** * 快捷搜索 * @param string $keyword 关键词 * @param string|array|\Closure $search 搜索设置 * @return mixed */ public function quickSearch($keyword, $search) { if ($keyword === '' || $keyword === null) { return; } if ($search instanceof \Closure) { $this->builder->where(function ($query) use ($search, $keyword) { call_user_func_array($search, [$query, $keyword]); }); } if (is_string($search)) { $search = [$search]; } if (is_array($search)) { $this->builder->where(function ($query) use ($search, $keyword) { foreach ($search as $field) { $query->orWhere($field, "LIKE", "%$keyword%"); } }); } elseif (is_null($search)) { $this->builder->where(function ($query) use ($keyword) { $tableField[$this->repository->getTable()] = $this->getTableField(); $table = $this->repository->getTable(); $wheres = []; foreach ($this->grid->getColumns() as $column) { $field = $column->attr('dataIndex'); $using = $column->using; $fields = explode('.', $field); if (count($fields) > 1) { $field = array_pop($fields); $model = $this->repository; foreach ($fields as $relation) { $model = $model->$relation()->getRelated(); } if (!array_key_exists($model->getTable(), $tableField)) { $tableField[$model->getTable()] = $this->getTableFieldInfo($model->getTable()); } $relation = implode('.', $fields); $relationTableField = $tableField[$model->getTable()]; $where = $this->buildOrWhere($field, $relationTableField, $using, $keyword); } else { $relation = $table; $where = $this->buildOrWhere($field, $tableField[$table], $using, $keyword); } if (count($where) > 0) { if (isset($wheres[$relation])) { $wheres[$relation] = array_merge($wheres[$relation], $where); } else { $wheres[$relation] = $where; } } } foreach ($wheres as $relation => $where) { if ($relation == $table) { $this->addOrWhereBinding($query, $where); } else { $query->orWhereHas($relation, function ($q) use ($where) { $q->where(function ($query) use ($where) { $this->addOrWhereBinding($query, $where); }); }); } } }); } } protected function addOrWhereBinding($query, $wheres) { foreach ($wheres as $where) { $query->orWhere(...$where); } } protected function parseDateTime($type, $originValue) { if (in_array($type, ['datetime', 'timestamp', 'date'])) { $value = strtotime($originValue); if ($value === false) { return $value; } if ('date' == $type) { $value = date('Y-m-d', $value); } else { $value = date('Y-m-d H:i:s', $value); } } else { $value = $originValue; } return $value; } protected function buildOrWhere($field, $tableField, $using, $keyword) { $where = []; if (array_key_exists($field, $tableField)) { if (count($using) > 0) { foreach ($using as $key => $value) { if (strpos($value, $keyword) !== false) { $where[] = [$field, "=", $key]; } } } else { $value = $this->parseDateTime($tableField[$field]['type'], $keyword); if ($value !== false) { if ($keyword == $value) { $where[] = [$field, "LIKE", "%$keyword%"]; } else { $where[] = [$field, "=", $value]; } } } } return $where; } /** * 预关联加载 */ protected function with() { $eagerLoad = $this->builder->getEagerLoads(); $relations = []; foreach ($this->grid->getColumns() as $column) { $field = $column->attr('dataIndex'); $fields = explode('.', $field); if (count($fields) > 1) { array_pop($fields); $relation = implode('.', $fields); if (method_exists($this->repository, $relation)) { $relations[] = $relation; } } } $relations = array_merge($relations, $eagerLoad); $this->builder->setEagerLoads([]); $this->builder->with($relations); } /** * 数据源 * @param int $page 第几页 * @param int $size 分页大小 * @param bool $hidePage 是否分页 * @return mixed */ public function data(int $page, int $size, bool $hidePage) { $totalBuilder = clone $this->builder; $totalBuilder = $totalBuilder->select(DB::raw('count(*) as total'))->get(); if (count($totalBuilder) > 1) { $total = $totalBuilder->count(); } else { $total = $totalBuilder->sum('total'); } $this->setTotal($total); $this->with(); if ($hidePage) { return $this->builder->get(); } else { return $this->builder->forPage($page, $size)->get(); } } /** * 返回总条数 * @return int */ public function total(): int { return $this->total; } /** * 导出数据 * @param array $selectIds 导出选中id * @param array $columns 导出列 * @param bool $all 是否导出全部 * @return Response */ public function export(array $selectIds, array $columns, bool $all): Response { $progressKey = Request::input('ex_admin_progress_key', uniqid()); $export = $this->grid->getExport(); $export->setProgressKey($progressKey); try { if (Request::input('ex_admin_queue')) { $request = (new Request())->getRequest(); $data = Request::input() + ['ex_admin_progress_key' => $progressKey, 'ex_admin_request' => [ 'method' => Request::getMethod(), 'server' => $request->server->all(), 'header' => $request->headers->all(), ]]; Client::send('ex-admin-grid-export', $data); } else { $arr = []; foreach ($columns as $column) { if (isset($column['title']) && !empty($column['title'])) { $arr[$column['dataIndex']] = $column['title']; } if (isset($column['children']) && !empty($column['children'])) { foreach ($column['children'] as $children) { if (isset($children['title']) && !empty($children['title'])) { $arr[$children['dataIndex']] = $children['title']; } } } } $columns = $arr; $this->builder->when(!$all, function (Builder $builder) use ($selectIds) { $builder->whereKey($selectIds); }); $count = $this->builder->count(); $export->columns($columns)->count($count); $this->builder->chunk(500, function ($data) use ($export) { $data = $this->grid->parseColumn($data, true); $export->write($data, function ($export) { $export->save(Filesystem::path('')); return Filesystem::url($export->getFilename() . '.' . $export->getExtension()); }); }); } } catch (\Throwable $exception) { $export->exportError(); } return $export->export(); } protected function getTableFieldInfo($table) { $tableFields = Db::connection($this->repository->getConnectionName())->select('SHOW FULL COLUMNS FROM ' . $table); $fields = []; foreach ($tableFields as $tableField) { $tableField = json_decode(json_encode($tableField), true); $tableField = array_change_key_case($tableField); $fields[$tableField['field']] = $tableField; } return $fields; } protected function getTableField() { if (count($this->tableField) == 0) { $this->tableField = $this->getTableFieldInfo($this->repository->getTable()); } return $this->tableField; } /** * @return Builder|mixed */ public function model() { return $this->builder; } }