Tree.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Administrator
  5. * Date: 2022/11/28
  6. * Time: 9:18
  7. */
  8. namespace app\common\model;
  9. use think\Db;
  10. use think\Model;
  11. /**
  12. * 提供树形数据结构的方法
  13. * 需要 id,pid,tree_path,status,title 等属性
  14. * Class Tree
  15. * @package app\common\model
  16. */
  17. class Tree extends Model
  18. {
  19. const STATUS_OPEN = 1;
  20. const STATUS_CLOSE = 0;
  21. /**
  22. * 获得树形数据结构,递归方式
  23. * 节点多的时候,效率比较慢
  24. * @param $nodelist [节点集合]
  25. * @param int $id [起始id,顶级id]
  26. * @param int $level
  27. * @return array
  28. */
  29. public function treelist($nodelist, $id = 0, $level = 0)
  30. {
  31. static $cates = array();
  32. foreach ($nodelist as $value) {
  33. if ($value['pid'] == $id) {
  34. $value['level'] = $level + 1;
  35. $value['str'] = $level == 0 ? "" : str_repeat('&emsp;', $level) . '└ ';
  36. $cates[] = $value;
  37. $this->treelist($nodelist, $value['id'], $value['level']);
  38. }
  39. }
  40. return $cates;
  41. }
  42. /**
  43. * 获得树形数据结构,sql排序方式
  44. * 通过tree_path排序获得树形结构,速度比递归快,要保证tree_path的正确性
  45. * @param $nodelist [节点集合]
  46. * @return false|\PDOStatement|string|\think\Collection
  47. */
  48. public function treelist2($nodelist = null)
  49. {
  50. if (!$nodelist) {
  51. $nodelist = $this->where("status", self::STATUS_OPEN)->order("tree_path")->select();
  52. }
  53. /** @var Tree $cate */
  54. foreach ($nodelist as $i => $cate) {
  55. $deep = $cate->getDepth();
  56. $nodelist[$i]['str'] = $deep == 1 ? "" : str_repeat('&emsp;', $deep) . '└ ';
  57. }
  58. return $nodelist;
  59. }
  60. /**
  61. * 更新所有节点tree_path属性
  62. * @param int $nodeId [起始id,顶级id]
  63. */
  64. public function updateTreePath($nodeId = 0)
  65. {
  66. $allCates = $this->select();
  67. $cates = $this->treelist($allCates, $nodeId);
  68. //update tree_path
  69. foreach ($cates as $cate) {
  70. $pdoc = null;
  71. //find pdoc
  72. foreach ($cates as $pcate) {
  73. if ($pcate->id == $cate->pid) {
  74. $pdoc = $pcate;
  75. break;
  76. }
  77. }
  78. //set tree_path
  79. $ppath = isset($pdoc) ? $pdoc->tree_path . '-' : "";
  80. $cate->tree_path = $ppath . $cate->id;
  81. $cate->allowField(true)->save();
  82. }
  83. }
  84. /**
  85. * 获取当前是第几层节点
  86. * @return int
  87. */
  88. public function getDepth()
  89. {
  90. $var = explode('-', $this->tree_path);
  91. return count($var);
  92. }
  93. /**
  94. * 获取顶层的节点id
  95. * @return mixed
  96. */
  97. public function getTopId()
  98. {
  99. $var = explode('-', $this->tree_path);
  100. return $var[0];
  101. }
  102. /**
  103. * 判断当前节点是否属于隐藏状态(包括上级节点隐藏)
  104. * @return bool
  105. */
  106. public function isHide()
  107. {
  108. if ($this->status == self::STATUS_CLOSE) {
  109. return true;
  110. }
  111. //上级是否隐藏
  112. $ids = explode('-', $this->tree_path);
  113. $exits = $this->where('id', 'in', $ids)->where('status', self::STATUS_CLOSE)->value('id');
  114. if ($exits) {
  115. return true;
  116. }
  117. return false;
  118. }
  119. //是否只是父级隐藏
  120. public function isParentHide()
  121. {
  122. $path = str_replace($this->id, '', $this->tree_path);
  123. $ids = explode('-', $path);
  124. $exits = $this->where('id', 'in', $ids)->where('status', self::STATUS_CLOSE)->value('id');
  125. if ($exits) {
  126. return true;
  127. }
  128. return false;
  129. }
  130. /**
  131. * 获取所有隐藏的节点id集合(包括上级节点隐藏)
  132. * @return array
  133. */
  134. public function getHideIdsAll()
  135. {
  136. $hidePids = $this->where(['pid' => ['<>', 0], 'status' => self::STATUS_CLOSE])->column('id');
  137. $hideIds = [];
  138. foreach ($hidePids as $pid) {
  139. $hideIds = array_merge($hideIds, $this->getChildsIdByPid($pid));
  140. }
  141. return $hideIds;
  142. }
  143. //获取父节点
  144. public function getDirectParentNode()
  145. {
  146. return self::get($this->pid);
  147. }
  148. /**
  149. * 获取上级节点id集合
  150. * @param $contain [是否包含自己]
  151. * @return array
  152. */
  153. public function getParentsIds($contain = true)
  154. {
  155. $ids = explode('-', $this->tree_path);
  156. if ($contain === false) {
  157. unset($ids[array_search($this->id, $ids, true)]);
  158. }
  159. return $ids;
  160. }
  161. /**
  162. * 获取上级节点名字集合
  163. * @param $contain [是否包含自己]
  164. * @param $field string [指定获取字段]
  165. * @return array
  166. */
  167. public function getParentsNames($contain = true, $field = "title")
  168. {
  169. $ids = $this->getParentsIds($contain);
  170. $names = $this->where('id', 'in', $ids)->order('tree_path')->column($field);
  171. return $names;
  172. }
  173. //获取所有子节点
  174. public function getDirectChildNodes()
  175. {
  176. return self::where('pid', $this->id)->select();
  177. }
  178. //获取一个子节点
  179. public function getDirectChildNode()
  180. {
  181. return self::where('pid', $this->id)->find();
  182. }
  183. /**
  184. * 获取所有子节点id
  185. * @param $id [指定节点id]
  186. * @return array
  187. */
  188. public function getDirectChildIdsByPid($id)
  189. {
  190. return $this->where('pid', $id)->column('id');
  191. }
  192. /**
  193. * 获取所有下级(子孙)节点id
  194. * @param $id [指定节点id]
  195. * @param $contain [是否包含指定节点]
  196. * @return array
  197. */
  198. public function getChildsIdByPid($id, $contain = true)
  199. {
  200. $tablename = $this->getTable();
  201. $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,'-%')";
  202. $cates = Db::query($sql, [$id]);
  203. $ids = [];
  204. foreach ($cates as $cate) {
  205. if ($contain === false && $id == $cate['id']) {
  206. continue;
  207. }
  208. $ids[] = $cate['id'];
  209. }
  210. return $ids;
  211. }
  212. }