treelist($nodelist, $value['id'], $value['level']); } } return $cates; } /** * 获得树形数据结构,sql排序方式 * 通过tree_path排序获得树形结构,速度比递归快,要保证tree_path的正确性 * @param $nodelist [节点集合] * @return false|\PDOStatement|string|\think\Collection */ public function treelist2($nodelist = null) { if (!$nodelist) { $nodelist = $this->where("status", self::STATUS_OPEN)->order("tree_path")->select(); } /** @var Tree $cate */ foreach ($nodelist as $i => $cate) { $deep = $cate->getDepth(); $nodelist[$i]['str'] = $deep == 1 ? "" : str_repeat(' ', $deep) . '└ '; } return $nodelist; } /** * 更新所有节点tree_path属性 * @param int $nodeId [起始id,顶级id] */ public function updateTreePath($nodeId = 0) { $allCates = $this->select(); $cates = $this->treelist($allCates, $nodeId); //update tree_path foreach ($cates as $cate) { $pdoc = null; //find pdoc foreach ($cates as $pcate) { if ($pcate->id == $cate->pid) { $pdoc = $pcate; break; } } //set tree_path $ppath = isset($pdoc) ? $pdoc->tree_path . '-' : ""; $cate->tree_path = $ppath . $cate->id; $cate->allowField(true)->save(); } } /** * 获取当前是第几层节点 * @return int */ public function getDepth() { $var = explode('-', $this->tree_path); return count($var); } /** * 获取顶层的节点id * @return mixed */ public function getTopId() { $var = explode('-', $this->tree_path); return $var[0]; } /** * 判断当前节点是否属于隐藏状态(包括上级节点隐藏) * @return bool */ public function isHide() { if ($this->status == self::STATUS_CLOSE) { return true; } //上级是否隐藏 $ids = explode('-', $this->tree_path); $exits = $this->where('id', 'in', $ids)->where('status', self::STATUS_CLOSE)->value('id'); if ($exits) { return true; } return false; } //是否只是父级隐藏 public function isParentHide() { $path = str_replace($this->id, '', $this->tree_path); $ids = explode('-', $path); $exits = $this->where('id', 'in', $ids)->where('status', self::STATUS_CLOSE)->value('id'); if ($exits) { return true; } return false; } /** * 获取所有隐藏的节点id集合(包括上级节点隐藏) * @return array */ public function getHideIdsAll() { $hidePids = $this->where(['pid' => ['<>', 0], 'status' => self::STATUS_CLOSE])->column('id'); $hideIds = []; foreach ($hidePids as $pid) { $hideIds = array_merge($hideIds, $this->getChildsIdByPid($pid)); } return $hideIds; } //获取父节点 public function getDirectParentNode() { return self::get($this->pid); } /** * 获取上级节点id集合 * @param $contain [是否包含自己] * @return array */ public function getParentsIds($contain = true) { $ids = explode('-', $this->tree_path); if ($contain === false) { unset($ids[array_search($this->id, $ids, true)]); } return $ids; } /** * 获取上级节点名字集合 * @param $contain [是否包含自己] * @param $field string [指定获取字段] * @return array */ public function getParentsNames($contain = true, $field = "title") { $ids = $this->getParentsIds($contain); $names = $this->where('id', 'in', $ids)->order('tree_path')->column($field); return $names; } //获取所有子节点 public function getDirectChildNodes() { return self::where('pid', $this->id)->select(); } //获取一个子节点 public function getDirectChildNode() { return self::where('pid', $this->id)->find(); } /** * 获取所有子节点id * @param $id [指定节点id] * @return array */ public function getDirectChildIdsByPid($id) { return $this->where('pid', $id)->column('id'); } /** * 获取所有下级(子孙)节点id * @param $id [指定节点id] * @param $contain [是否包含指定节点] * @return array */ public function getChildsIdByPid($id, $contain = true) { $tablename = $this->getTable(); $sql = "select a.id from {$tablename} a,(select id,tree_path p from {$tablename} where id=?) b where a.id = b.id or a.tree_path like concat(b.p,'-%')"; $cates = Db::query($sql, [$id]); $ids = []; foreach ($cates as $cate) { if ($contain === false && $id == $cate['id']) { continue; } $ids[] = $cate['id']; } return $ids; } }