model = new CategoryModel(); } public function index() { if ($this->request->isAjax()) { $title = $this->request->param('title', ''); $all = $this->model->order('sort', 'desc')->order('id', 'asc')->select()->toArray(); //$tree = CategoryModel::toNestedTree($all); // 关键字过滤:命中节点保留,并保留其祖先链 // if ($title) { // $tree = $this->filterTree($tree, $title); // } $this->result->success($all); } return $this->view->fetch('category/index'); } /** * 按标题关键字过滤树,保留命中节点及其祖先链 */ protected function filterTree(array $tree, string $keyword): array { $result = []; foreach ($tree as $node) { $children = !empty($node['children']) ? $this->filterTree($node['children'], $keyword) : []; $hit = stripos($node['title'], $keyword) !== false; if ($hit || !empty($children)) { $node['children'] = $children; $result[] = $node; } } return $result; } public function create() { if ($this->request->isAjax()) { $data = CategoryModel::cateTree($this->model->select()->toArray()); $this->result->success(['data' => $data]); } } public function save() { if ($this->request->isPost()) { $params = $this->request->post(); $this->validateSave($params); Db::startTrans(); try { $this->model->save($params); Db::commit(); $this->result->success($this->model, '保存成功'); } catch (\Exception $e) { Db::rollback(); $this->result->error('保存失败: ' . $e->getMessage()); } } } public function edit($id = null) { $id = $this->request->param('id'); $model = $this->model->find($id); if (!$model) { $this->result->error('数据不存在'); } if ($this->request->isAjax()) { $tree = CategoryModel::cateTree($this->model->select()->toArray()); $this->result->success(['power' => $tree, 'info' => $model]); } } public function update() { $id = $this->request->param('id'); if ($this->request->isAjax() && $this->request->isPut()) { $params = $this->request->param(); $this->validateSave($params); Db::startTrans(); try { $model = $this->model->find($id); if (!$model) { throw new ValidateException('数据不存在'); } $model->save($params); Db::commit(); $this->result->success($model, '更新成功'); } catch (\Exception $e) { Db::rollback(); $this->result->error('更新失败: ' . $e->getMessage()); } } } public function delete() { if ($this->request->isAjax() && $this->request->isDelete()) { $ids = $this->request->param('ids', ''); $force = $this->request->param('force/d', 0); if (empty($ids)) { $this->result->error('请选择要删除的数据'); } $idArr = array_filter(array_map('intval', explode(',', $ids))); try { Db::transaction(function () use ($idArr, $force) { foreach ($idArr as $id) { $this->deleteCascade($id, (bool) $force); } }); $this->result->success(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Throwable $th) { $this->result->error('删除失败: ' . $th->getMessage()); } } } /** * 递归级联删除:force=true 时先删子分类下的资源与子分类,再删自身 */ protected function deleteCascade($id, bool $force): void { $model = $this->model->find($id); if (!$model) { return; } if ($force) { Resource::where('cid', $id)->delete(); $children = $this->model->where('pid', $id)->select(); foreach ($children as $child) { $this->deleteCascade($child['id'], true); } } // 非 force 时若仍有子分类/资源,onBeforeDelete 会抛出异常阻止删除 $model->delete(); } protected function validateSave(array $params): void { if (empty($params['title'])) { throw new ValidateException('分类名称不能为空'); } } }