Tree.php 5.7 KB

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