Card.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <?php
  2. namespace Dcat\Admin\Widgets\Metrics;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Support\Helper;
  5. use Dcat\Admin\Traits\InteractsWithApi;
  6. use Dcat\Admin\Widgets\ApexCharts\Chart;
  7. use Dcat\Admin\Widgets\Widget;
  8. use Illuminate\Support\Arr;
  9. use Illuminate\Support\Str;
  10. class Card extends Widget
  11. {
  12. use InteractsWithApi;
  13. /**
  14. * @var string
  15. */
  16. protected $view = 'admin::widgets.metrics.card';
  17. /**
  18. * @var array
  19. */
  20. protected $options = [
  21. 'icon' => null,
  22. 'title' => null,
  23. 'subTitle' => null,
  24. 'header' => null,
  25. 'content' => null,
  26. 'dropdown' => [],
  27. ];
  28. /**
  29. * 图标主题色.
  30. *
  31. * @var string
  32. */
  33. protected $style = 'primary';
  34. /**
  35. * 卡片高度.
  36. *
  37. * @var int|string
  38. */
  39. protected $height = null;
  40. /**
  41. * 图表高度.
  42. *
  43. * @var int
  44. */
  45. protected $chartHeight = 70;
  46. /**
  47. * 图表配置.
  48. *
  49. * @var array
  50. */
  51. protected $chartOptions = [];
  52. /**
  53. * @var Chart
  54. */
  55. protected $chart;
  56. /**
  57. * @var \Closure
  58. */
  59. protected $chartCallback;
  60. public function __construct($title = null, $icon = null)
  61. {
  62. $this->title($title);
  63. $this->icon($icon);
  64. if ($options = $this->defaultChartOptions()) {
  65. $this->chartOptions = $options;
  66. }
  67. $this->init();
  68. }
  69. /**
  70. * 初始化.
  71. */
  72. protected function init()
  73. {
  74. $this->id('metric-card-'.Str::random(8));
  75. $this->class('card');
  76. }
  77. /**
  78. * 图表默认配置.
  79. *
  80. * @return array
  81. */
  82. protected function defaultChartOptions()
  83. {
  84. return [];
  85. }
  86. /**
  87. * 启用图表.
  88. *
  89. * @return Chart
  90. */
  91. public function useChart()
  92. {
  93. return $this->chart ?: ($this->chart = Chart::make());
  94. }
  95. /**
  96. * 设置图标.
  97. *
  98. * @param string $icon
  99. *
  100. * @return $this
  101. */
  102. public function icon(?string $icon)
  103. {
  104. $this->options['icon'] = $icon;
  105. return $this;
  106. }
  107. /**
  108. * 设置卡片标题.
  109. *
  110. * @param string $title
  111. *
  112. * @return $this
  113. */
  114. public function title(?string $title)
  115. {
  116. $this->options['title'] = $title;
  117. return $this;
  118. }
  119. /**
  120. * 设置卡片子标题.
  121. *
  122. * @param string $title
  123. *
  124. * @return $this
  125. */
  126. public function subTitle(?string $title)
  127. {
  128. $this->options['subTitle'] = $title;
  129. return $this;
  130. }
  131. /**
  132. * 设置卡片头内容.
  133. *
  134. * @param string $contents
  135. *
  136. * @return $this
  137. */
  138. public function header($contents)
  139. {
  140. $this->options['header'] = $contents;
  141. return $this;
  142. }
  143. /**
  144. * 设置卡片内容.
  145. *
  146. * @param string $contents
  147. *
  148. * @return $this
  149. */
  150. public function content($contents)
  151. {
  152. $this->options['content'] = $contents;
  153. return $this;
  154. }
  155. /**
  156. * 设置主题色.
  157. *
  158. * @param string $style
  159. *
  160. * @return $this
  161. */
  162. public function style(string $style)
  163. {
  164. $this->style = $style;
  165. return $this;
  166. }
  167. /**
  168. * 设置卡片的下拉菜单选项.
  169. *
  170. * @param array $items
  171. *
  172. * @return $this
  173. */
  174. public function dropdown(array $items)
  175. {
  176. $this->options['dropdown'] = $items;
  177. return $this;
  178. }
  179. /**
  180. * 设置最小高度.
  181. *
  182. * @param string|int $value
  183. *
  184. * @return $this
  185. */
  186. public function height($value)
  187. {
  188. $this->height = $value;
  189. return $this;
  190. }
  191. /**
  192. * 设置图表配置.
  193. *
  194. * @param string $key
  195. * @param mixed $value
  196. *
  197. * @return $this
  198. */
  199. public function chartOption($key, $value)
  200. {
  201. Arr::set($this->chartOptions, $key, $value);
  202. $this->useChart();
  203. return $this;
  204. }
  205. /**
  206. * 设置图表高度.
  207. *
  208. * @param int $number
  209. *
  210. * @return $this
  211. */
  212. public function chartHeight(int $number)
  213. {
  214. $this->chartHeight = $number;
  215. $this->useChart();
  216. return $this;
  217. }
  218. /**
  219. * 设置图表label.
  220. *
  221. * @param string|array $label
  222. *
  223. * @return $this
  224. */
  225. public function chartLabels($label)
  226. {
  227. $this->chartOptions['labels'] = (array) $label;
  228. $this->useChart();
  229. return $this;
  230. }
  231. /**
  232. * 设置图表颜色.
  233. *
  234. * @param string|array $colors
  235. *
  236. * @return $this
  237. */
  238. public function chartColors($colors)
  239. {
  240. $this->chartOptions['colors'] = (array) $colors;
  241. $this->useChart();
  242. return $this;
  243. }
  244. /**
  245. * 设置图表.
  246. *
  247. * @param array|\Closure $options
  248. *
  249. * @return $this
  250. */
  251. public function chart($options = [])
  252. {
  253. if ($options instanceof \Closure) {
  254. $this->chartCallback = $options;
  255. } else {
  256. $this->chartOptions = array_merge(
  257. $this->chartOptions,
  258. Helper::array($options)
  259. );
  260. }
  261. $this->useChart();
  262. return $this;
  263. }
  264. /**
  265. * 设置图表.
  266. */
  267. protected function setUpChart()
  268. {
  269. if (! $chart = $this->chart) {
  270. return;
  271. }
  272. // 设置图表高度
  273. $this->chartOptions['chart']['height'] = $this->chartHeight;
  274. // 颜色
  275. if (empty($this->chartOptions['colors'])) {
  276. $this->chartOptions['colors'] = (array) Admin::color()->get($this->style);
  277. }
  278. // 图表配置选项
  279. $chart->options($this->chartOptions);
  280. if ($callback = $this->chartCallback) {
  281. $callback($chart);
  282. }
  283. }
  284. /**
  285. * @return mixed
  286. */
  287. public function script()
  288. {
  289. if (! $this->allowBuildRequest()) {
  290. return;
  291. }
  292. $id = $this->id();
  293. // 开启loading效果
  294. $this->fetching(
  295. <<<JS
  296. var \$card = $('#{$id}');
  297. \$card.loading();
  298. JS
  299. );
  300. $this->fetched(
  301. <<<'JS'
  302. $card.loading(false);
  303. $card.find('.metric-header').html(response.header);
  304. $card.find('.metric-content').html(response.content);
  305. JS
  306. );
  307. $clickable = "#{$id} .dropdown .select-option";
  308. $cardRequestScript = '';
  309. if ($this->chart) {
  310. // 有图表的情况下,直接使用图表的js代码.
  311. $this->chart->merge($this)->click($clickable);
  312. } else {
  313. // 没有图表,需要构建卡片数据请求js代码.
  314. $cardRequestScript = $this->click($clickable)->buildRequestScript();
  315. }
  316. // 按钮显示选中文本
  317. return <<<JS
  318. $('{$clickable}').click(function () {
  319. $(this).parents('.dropdown').find('.btn').html($(this).text());
  320. });
  321. {$cardRequestScript}
  322. JS;
  323. }
  324. /**
  325. * 渲染卡片头部内容.
  326. *
  327. * @return string
  328. */
  329. public function renderHeader()
  330. {
  331. return Helper::render($this->options['header']);
  332. }
  333. /**
  334. * 渲染卡片主体内容.
  335. *
  336. * @return string
  337. */
  338. public function renderContent()
  339. {
  340. return Helper::render($this->options['content']);
  341. }
  342. /**
  343. * 渲染图表.
  344. *
  345. * @return string
  346. */
  347. public function renderChart()
  348. {
  349. return $this->chart ? $this->chart->render() : '';
  350. }
  351. /**
  352. * 设置卡片高度.
  353. */
  354. protected function setUpCardHeight()
  355. {
  356. if (! $height = $this->height) {
  357. return;
  358. }
  359. if (is_numeric($height)) {
  360. $height .= 'px';
  361. }
  362. $this->appendHtmlAttribute('style', "min-height:{$height};");
  363. }
  364. /**
  365. * @return string
  366. */
  367. public function render()
  368. {
  369. $this->setUpChart();
  370. $this->setUpCardHeight();
  371. $this->script = $this->script();
  372. $this->variables['style'] = $this->style;
  373. $this->variables['header'] = $this->renderHeader();
  374. $this->variables['content'] = $this->renderContent();
  375. return parent::render();
  376. }
  377. /**
  378. * 返回API请求结果.
  379. *
  380. * @return array
  381. */
  382. public function valueResult()
  383. {
  384. $this->setUpChart();
  385. return array_merge(
  386. [
  387. 'status' => 1,
  388. 'header' => $this->renderHeader(),
  389. 'content' => $this->renderContent(),
  390. ],
  391. (array) optional($this->chart)->valueResult()
  392. );
  393. }
  394. }