Tree.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. namespace Dcat\Admin\Grid\Displayers;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Support\Helper;
  5. use Illuminate\Contracts\Support\Arrayable;
  6. class Tree extends AbstractDisplayer
  7. {
  8. protected $url;
  9. protected $title;
  10. protected $area = ['650px', '600px'];
  11. protected $options = [
  12. 'plugins' => ['checkbox', 'types'],
  13. 'core' => [
  14. 'check_callback' => true,
  15. 'themes' => [
  16. 'name' => 'proton',
  17. 'responsive' => true,
  18. ],
  19. ],
  20. 'checkbox' => [
  21. 'keep_selected_style' => false,
  22. ],
  23. 'types' => [
  24. 'default' => [
  25. 'icon' => false,
  26. ],
  27. ],
  28. ];
  29. /**
  30. * @var array
  31. */
  32. protected $columnNames = [
  33. 'id' => 'id',
  34. 'text' => 'name',
  35. 'parent' => 'parent_id',
  36. ];
  37. protected $nodes = [];
  38. protected $checkedAll;
  39. /**
  40. * @param array $data exp:
  41. * {
  42. * "id": "1",
  43. * "parent": "#",
  44. * "text": "Dashboard",
  45. * // "state": {"selected": true}
  46. * }
  47. *
  48. * @param array $data
  49. * @return $this
  50. */
  51. public function nodes($data)
  52. {
  53. if ($data instanceof Arrayable) {
  54. $data = $data->toArray();
  55. }
  56. $this->nodes = &$data;
  57. return $this;
  58. }
  59. public function url(string $source)
  60. {
  61. if ($source && URL::isValidUrl($source)) {
  62. $this->url = $source;
  63. } else {
  64. $this->url = admin_base_path($source);
  65. }
  66. return $this;
  67. }
  68. public function checkedAll()
  69. {
  70. $this->checkedAll = true;
  71. return $this;
  72. }
  73. /**
  74. *
  75. * @param array $options
  76. * @return $this
  77. */
  78. public function options($options = [])
  79. {
  80. if ($options instanceof Arrayable) {
  81. $options = $options->toArray();
  82. }
  83. $this->options = array_merge($this->options, $options);
  84. return $this;
  85. }
  86. public function title($title)
  87. {
  88. $this->title = $title;
  89. return $this;
  90. }
  91. /**
  92. * @param string $width
  93. * @param string $height
  94. * @return $this
  95. */
  96. public function area(string $width, string $height)
  97. {
  98. $this->area = [$width, $height];
  99. return $this;
  100. }
  101. /**
  102. * @param string $idColumn
  103. * @param string $textColumn
  104. * @param string $parentColumn
  105. * @return $this
  106. */
  107. public function columnNames(string $idColumn = 'id', string $textColumn = 'name', string $parentColumn = 'parent_id')
  108. {
  109. $this->columnNames['id'] = $idColumn;
  110. $this->columnNames['text'] = $textColumn;
  111. $this->columnNames['parent'] = $parentColumn;
  112. return $this;
  113. }
  114. public function display($callbackOrNodes = null)
  115. {
  116. if (is_array($callbackOrNodes) || $callbackOrNodes instanceof Arrayable) {
  117. $this->nodes($callbackOrNodes);
  118. } elseif ($callbackOrNodes instanceof \Closure) {
  119. $callbackOrNodes->call($this->row, $this);
  120. }
  121. $btn = $this->trans('view');
  122. $this->setupScript();
  123. $val = $this->format($this->value);
  124. return <<<EOF
  125. <a href="javascript:void(0)" class="{$this->getSelectorPrefix()}-open-tree" data-checked="{$this->checkedAll}" data-val="{$val}"><i class='ti-layout-list-post'></i> $btn</a>
  126. EOF;
  127. }
  128. protected function format($val)
  129. {
  130. return join(',', Helper::array($val, true));
  131. }
  132. protected function getSelectorPrefix()
  133. {
  134. return $this->grid->getName().'_'.$this->column->getName();
  135. }
  136. protected function setupScript()
  137. {
  138. $title = $this->title ?: $this->column->getLabel();
  139. $area = json_encode($this->area);
  140. $opts = json_encode($this->options);
  141. $nodes = json_encode($this->nodes);
  142. Admin::script(
  143. <<<JS
  144. $('.{$this->getSelectorPrefix()}-open-tree').click(function () {
  145. var tpl = '<div class="jstree-wrapper" style="border:0"><div class="_tree" style="margin-top:10px"></div></div>',
  146. opts = $opts,
  147. url = '{$this->url}',
  148. t = $(this),
  149. val = t.data('val'),
  150. ckall = t.data('checked'),
  151. idx,
  152. requesting;
  153. val = val ? String(val).split(',') : [];
  154. if (url) {
  155. if (requesting) return;
  156. requesting = 1;
  157. t.button('loading');
  158. $.getJSON(url, {_token: LA.token, value: val}, function (resp) {
  159. requesting = 0;
  160. t.button('reset');
  161. if (!resp.status) {
  162. return LA.error(resp.message || '系统繁忙,请稍后再试');
  163. }
  164. build(resp.value);
  165. });
  166. } else {
  167. build(val);
  168. }
  169. function build(val) {
  170. opts.core.data = formatNodes(val, $nodes);
  171. idx = layer.open({
  172. type: 1,
  173. area: $area,
  174. content: tpl,
  175. title: '{$title}',
  176. success: function (a, idx) {
  177. var tree = $('#layui-layer'+idx).find('._tree');
  178. tree.on("loaded.jstree", function () {
  179. tree.jstree('open_all');
  180. }).jstree(opts);
  181. }
  182. });
  183. $(document).one('pjax:complete', function () {
  184. layer.close(idx);
  185. });
  186. }
  187. function formatNodes(value, all) {
  188. var idColumn = '{$this->columnNames['id']}',
  189. textColumn = '{$this->columnNames['text']}',
  190. parentColumn = '{$this->columnNames['parent']}';
  191. var parentIds = [], nodes = [], i, v, parentId;
  192. for (i in all) {
  193. v = all[i];
  194. if (!v[idColumn]) continue;
  195. parentId = v[parentColumn] || '#';
  196. if (!parentId) {
  197. parentId = '#';
  198. } else {
  199. parentIds.push(parentId);
  200. }
  201. v['state'] = {'disabled': true};
  202. if (ckall || (value && LA.arr.in(value, v[idColumn]))) {
  203. v['state']['selected'] = true;
  204. }
  205. nodes.push({
  206. 'id' : v[idColumn],
  207. 'text' : v[textColumn] || null,
  208. 'parent' : parentId,
  209. 'state' : v['state'],
  210. });
  211. }
  212. return nodes;
  213. }
  214. });
  215. JS
  216. );
  217. }
  218. protected function collectAssets()
  219. {
  220. Admin::css('vendor/dcat-admin/jstree-theme/themes/proton/style.min.css');
  221. Admin::collectComponentAssets('jstree');
  222. }
  223. }