| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- <?php
- namespace App\Module\Mex\Metrics;
- use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
- use App\Module\Mex\Models\MexDailyPriceTrend;
- use Dcat\Admin\Widgets\Metrics\Line;
- use Illuminate\Http\Request;
- /**
- * 农贸市场价格趋势图表 - 多线图(最低,最高,均价)
- */
- class PriceTrendChart extends Line
- {
- /**
- * 商品ID
- */
- protected $itemId;
- /**
- * 商品名称
- */
- protected $itemName;
- /**
- * 构造函数
- */
- public function __construct($itemId = null, $itemName = null)
- {
- $this->itemId = $itemId;
- $this->itemName = $itemName;
- parent::__construct();
- }
- /**
- * 初始化卡片内容
- *
- * @return void
- */
- protected function init()
- {
- parent::init();
- $title = $this->itemName ? "{$this->itemName} - 价格趋势" : '价格趋势';
- $this->title($title);
- $this->height(400);
- $this->chartHeight(300);
- // 设置下拉选项
- $this->dropdown([
- '7' => '最近 7 天',
- '14' => '最近 14 天',
- '30' => '最近 30 天',
- '90' => '最近 90 天',
- ]);
- }
- /**
- * 处理请求
- *
- * @param Request $request
- * @return mixed|void
- */
- public function handle(Request $request)
- {
- $days = (int) $request->get('option', 7);
- $itemId = $this->itemId ?? $request->get('item_id');
- $currencyType = $request->get('currency_type', FUND_CURRENCY_TYPE::ZUANSHI->value);
- $data = $this->getMultiLinePriceTrendData($days, $itemId, $currencyType);
- // 卡片内容 - 显示最新收盘价
- $latestPrice = $data['latest_close_price'] ?? 0;
- $priceChange = $data['price_change'] ?? 0;
- $changePercent = $data['change_percent'] ?? 0;
- $changeText = $priceChange >= 0 ? "+{$changePercent}%" : "{$changePercent}%";
- $this->withContent(number_format($latestPrice, 5), $changeText);
- // 添加详细信息
- $dataCount = count($data['dates']);
- $this->subTitle("数据点: {$dataCount} | 时间范围: {$days}天");
- // 图表数据 - 多线图
- $this->withMultiLineChart($data);
- }
- /**
- * 获取多线价格趋势数据
- *
- * @param int $days
- * @param int|null $itemId
- * @param int $currencyType
- * @return array
- */
- protected function getMultiLinePriceTrendData(int $days, ?int $itemId = null, int $currencyType = 2): array
- {
- $startDate = now()->subDays($days - 1)->toDateString();
- $endDate = now()->toDateString();
- if ($itemId) {
- // 如果指定了商品ID,显示该商品的价格趋势
- $trends = MexDailyPriceTrend::whereBetween('trade_date', [$startDate, $endDate])
- ->where('currency_type', $currencyType)
- ->where('item_id', $itemId)
- ->orderBy('trade_date')
- ->get();
- } else {
- // 如果没有指定商品ID,显示所有商品的平均价格趋势
- $trends = MexDailyPriceTrend::selectRaw('
- trade_date,
- AVG(open_price) as avg_open_price,
- AVG(close_price) as avg_close_price,
- AVG(high_price) as avg_high_price,
- AVG(low_price) as avg_low_price
- ')
- ->whereBetween('trade_date', [$startDate, $endDate])
- ->where('currency_type', $currencyType)
- ->groupBy('trade_date')
- ->orderBy('trade_date')
- ->get();
- }
- $dates = [];
- $openPrices = [];
- $closePrices = [];
- $highPrices = [];
- $lowPrices = [];
- $latestClosePrice = 0;
- $firstClosePrice = 0;
- foreach ($trends as $trend) {
- // 确保 trade_date 被正确解析为 Carbon 对象
- $tradeDate = $trend->trade_date instanceof \Carbon\Carbon
- ? $trend->trade_date
- : \Carbon\Carbon::parse($trend->trade_date);
- $dates[] = $tradeDate->format('m-d');
- if ($itemId) {
- // 单个商品的数据
- $openPrices[] = (float) $trend->open_price;
- $closePrices[] = (float) $trend->close_price;
- $highPrices[] = (float) $trend->high_price;
- $lowPrices[] = (float) $trend->low_price;
- if (!$firstClosePrice) {
- $firstClosePrice = (float) $trend->close_price;
- }
- $latestClosePrice = (float) $trend->close_price;
- } else {
- // 平均价格数据
- $openPrices[] = (float) $trend->avg_open_price;
- $closePrices[] = (float) $trend->avg_close_price;
- $highPrices[] = (float) $trend->avg_high_price;
- $lowPrices[] = (float) $trend->avg_low_price;
- if (!$firstClosePrice) {
- $firstClosePrice = (float) $trend->avg_close_price;
- }
- $latestClosePrice = (float) $trend->avg_close_price;
- }
- }
- // 计算价格变化
- $priceChange = $latestClosePrice - $firstClosePrice;
- $changePercent = $firstClosePrice > 0 ? round(($priceChange / $firstClosePrice) * 100, 2) : 0;
- return [
- 'dates' => $dates,
- 'open_prices' => $openPrices,
- 'close_prices' => $closePrices,
- 'high_prices' => $highPrices,
- 'low_prices' => $lowPrices,
- 'latest_close_price' => $latestClosePrice,
- 'price_change' => $priceChange,
- 'change_percent' => $changePercent,
- ];
- }
- /**
- * 设置多线图表数据
- *
- * @param array $data
- * @return $this
- */
- public function withMultiLineChart(array $data)
- {
- $series = [
- [
- 'name' => '最低价',
- 'data' => $data['low_prices'],
- ],
- [
- 'name' => '最高价',
- 'data' => $data['high_prices'],
- ],
- [
- 'name' => '收盘价',
- 'data' => $data['close_prices'],
- ],
- ];
- // 定义不同线条的颜色
- $colors = [
- '#52c41a', // 绿色 - 最低价
- '#f5222d', // 红色 - 最高价
- '#1890ff', // 蓝色 - 收盘价
- ];
- return $this->chart([
- 'series' => $series,
- 'colors' => $colors,
- 'xaxis' => [
- 'categories' => $data['dates'],
- 'labels' => [
- 'show' => true,
- ],
- ],
- 'legend' => [
- 'show' => true,
- 'position' => 'bottom',
- 'horizontalAlign' => 'center'
- ],
- 'tooltip' => [
- 'shared' => true,
- 'intersect' => false,
- ],
- ]);
- }
- /**
- * 设置图表数据(兼容旧方法)
- *
- * @param array $data
- * @param array $categories
- * @return $this
- */
- public function withChart(array $data, array $categories)
- {
- return $this->chart([
- 'series' => [
- [
- 'name' => '平均价格',
- 'data' => $data,
- ],
- ],
- 'xaxis' => [
- 'categories' => $categories,
- ],
- ]);
- }
- }
|