Tree.php 5.6 KB

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