Tree.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. namespace Dcat\Admin\Form\Field;
  3. use Dcat\Admin\Form\Field;
  4. use Dcat\Admin\Support\Helper;
  5. use Dcat\Admin\Widgets\Checkbox as WidgetCheckbox;
  6. use Illuminate\Contracts\Support\Arrayable;
  7. class Tree extends Field
  8. {
  9. protected $options = [
  10. 'plugins' => ['checkbox', 'types'],
  11. 'core' => [
  12. 'check_callback' => true,
  13. 'themes' => [
  14. 'name' => 'proton',
  15. 'responsive' => true,
  16. ],
  17. ],
  18. 'checkbox' => [
  19. 'keep_selected_style' => false,
  20. 'three_state' => true,
  21. ],
  22. 'types' => [
  23. 'default' => [
  24. 'icon' => false,
  25. ],
  26. ],
  27. ];
  28. protected $nodes = [];
  29. protected $parents = [];
  30. protected $expand = true;
  31. protected $columnNames = [
  32. 'id' => 'id',
  33. 'text' => 'name',
  34. 'parent' => 'parent_id',
  35. ];
  36. protected $exceptParents = true;
  37. protected $readOnly = false;
  38. protected $rootParentId = 0;
  39. /**
  40. * @param array|Arrayable|\Closure $data exp:
  41. * {
  42. * "id": "1",
  43. * "parent": "#",
  44. * "text": "Dashboard",
  45. * // "state": {"selected": true}
  46. * }
  47. * @return $this
  48. */
  49. public function nodes($data)
  50. {
  51. if ($data instanceof Arrayable) {
  52. $data = $data->toArray();
  53. }
  54. $this->nodes = &$data;
  55. return $this;
  56. }
  57. /**
  58. * 设置父级复选框是否禁止被单独选中.
  59. *
  60. * @param bool $value
  61. * @return $this
  62. */
  63. public function treeState(bool $value = true)
  64. {
  65. $this->options['checkbox']['three_state'] = $value;
  66. return $this->exceptParentNode($value);
  67. }
  68. /**
  69. * 过滤父节点.
  70. *
  71. * @param bool $value
  72. * @return $this
  73. */
  74. public function exceptParentNode(bool $value = true)
  75. {
  76. $this->exceptParents = $value;
  77. return $this;
  78. }
  79. public function rootParentId($id)
  80. {
  81. $this->rootParentId = $id;
  82. return $this;
  83. }
  84. /**
  85. * {@inheritDoc}
  86. */
  87. public function readOnly(bool $value = true)
  88. {
  89. $this->readOnly = true;
  90. return $this;
  91. }
  92. public function setIdColumn(string $name)
  93. {
  94. $this->columnNames['id'] = $name;
  95. return $this;
  96. }
  97. public function setTitleColumn(string $name)
  98. {
  99. $this->columnNames['text'] = $name;
  100. return $this;
  101. }
  102. public function setParentColumn(string $name)
  103. {
  104. $this->columnNames['parent'] = $name;
  105. return $this;
  106. }
  107. protected function formatNodes()
  108. {
  109. $value = Helper::array($this->value());
  110. $this->value = &$value;
  111. if ($this->nodes instanceof \Closure) {
  112. $this->nodes = Helper::array($this->nodes->call($this->values(), $value, $this));
  113. }
  114. if (! $this->nodes) {
  115. return;
  116. }
  117. $idColumn = $this->columnNames['id'];
  118. $textColumn = $this->columnNames['text'];
  119. $parentColumn = $this->columnNames['parent'];
  120. $parentIds = $nodes = [];
  121. foreach ($this->nodes as &$v) {
  122. if (empty($v[$idColumn])) {
  123. continue;
  124. }
  125. $parentId = $v[$parentColumn] ?? '#';
  126. if (empty($parentId) || $parentId == $this->rootParentId) {
  127. $parentId = '#';
  128. } else {
  129. $parentIds[] = $parentId;
  130. }
  131. $v['state'] = [];
  132. if ($value && in_array($v[$idColumn], $value)) {
  133. $v['state']['selected'] = true;
  134. }
  135. if ($this->readOnly) {
  136. $v['state']['disabled'] = true;
  137. }
  138. $nodes[] = [
  139. 'id' => $v[$idColumn],
  140. 'text' => $v[$textColumn] ?? null,
  141. 'parent' => $parentId,
  142. 'state' => $v['state'],
  143. ];
  144. }
  145. if ($this->exceptParents) {
  146. // 筛选出所有父节点,最终点击树节点时过滤掉父节点
  147. $this->parents = array_unique($parentIds);
  148. }
  149. $this->nodes = &$nodes;
  150. }
  151. /**
  152. * Set type.
  153. *
  154. * @param array $value
  155. * @return $this
  156. */
  157. public function type(array $value)
  158. {
  159. $this->options['types'] = array_merge($this->options['types'], $value);
  160. return $this;
  161. }
  162. /**
  163. * Set plugins.
  164. *
  165. * @param array $value
  166. * @return $this
  167. */
  168. public function plugins(array $value)
  169. {
  170. $this->options['plugins'] = $value;
  171. return $this;
  172. }
  173. /**
  174. * @param bool $value
  175. * @return $this
  176. */
  177. public function expand(bool $value = true)
  178. {
  179. $this->expand = $value;
  180. return $this;
  181. }
  182. protected function formatFieldData($data)
  183. {
  184. return Helper::array($this->getValueFromData($data), true);
  185. }
  186. protected function prepareInputValue($value)
  187. {
  188. return Helper::array($value, true);
  189. }
  190. public function render()
  191. {
  192. $checkboxes = new WidgetCheckbox();
  193. $checkboxes->style('primary');
  194. $checkboxes->inline();
  195. $checkboxes->options([
  196. 1 => trans('admin.selectall'),
  197. 2 => trans('admin.expand'),
  198. ]);
  199. $this->readOnly && $checkboxes->disable(1);
  200. $this->expand && $checkboxes->check(2);
  201. $this->formatNodes();
  202. if ($v = $this->value()) {
  203. $this->attribute('value', implode(',', $v));
  204. }
  205. $this->addVariables([
  206. 'checkboxes' => $checkboxes,
  207. 'nodes' => $this->nodes,
  208. 'expand' => $this->expand,
  209. 'disabled' => empty($this->attributes['disabled']) ? '' : 'disabled',
  210. 'parents' => $this->parents,
  211. ]);
  212. return parent::render();
  213. }
  214. }