FarmUserSummaryController.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. <?php
  2. namespace App\Module\Game\AdminControllers;
  3. use App\Module\Farm\Enums\GROWTH_STAGE;
  4. use App\Module\Farm\Models\FarmCrop;
  5. use App\Module\Farm\Models\FarmGodBuff;
  6. use App\Module\Farm\Models\FarmHouseConfig;
  7. use App\Module\Farm\Models\FarmLand;
  8. use App\Module\Farm\Models\FarmUser;
  9. use App\Module\Fund\Models\FundModel;
  10. use App\Module\Fund\Services\AccountService;
  11. use App\Module\GameItems\Enums\ITEM_TYPE;
  12. use App\Module\GameItems\Models\ItemUser;
  13. use App\Module\User\Models\User;
  14. use Dcat\Admin\Grid;
  15. use Dcat\Admin\Layout\Content;
  16. use Dcat\Admin\Layout\Row;
  17. use Dcat\Admin\Widgets\Card;
  18. use Dcat\Admin\Widgets\Table;
  19. use Dcat\Admin\Widgets\Alert;
  20. use Spatie\RouteAttributes\Attributes\Get;
  21. use Spatie\RouteAttributes\Attributes\Resource;
  22. use UCore\DcatAdmin\AdminController;
  23. /**
  24. * 农场用户信息汇总控制器
  25. *
  26. * 用于展示用户的农场信息汇总,包括房屋、土地、作物、物品和代币信息
  27. */
  28. #[Resource('farm-user-summary', names: 'dcat.admin.farm-user-summary')]
  29. class FarmUserSummaryController extends AdminController
  30. {
  31. /**
  32. * 页面标题
  33. *
  34. * @var string
  35. */
  36. protected $title = '农场用户信息汇总';
  37. /**
  38. * 用户列表页面
  39. *
  40. * @param Content $content
  41. * @return Content
  42. */
  43. public function index(Content $content)
  44. {
  45. return $content
  46. ->title($this->title)
  47. ->description('查看用户的农场信息汇总')
  48. ->body($this->grid());
  49. }
  50. /**
  51. * 查看指定用户的农场信息汇总
  52. *
  53. * @param int $userId 用户ID
  54. * @param Content $content
  55. * @return Content
  56. */
  57. #[Get('farm-user-summary/{userId}', name: 'dcat.admin.farm-user-summary.show')]
  58. public function show($userId, Content $content)
  59. {
  60. // 查找用户
  61. $user = User::find($userId);
  62. if (!$user) {
  63. admin_error('错误', '用户不存在');
  64. return redirect()->route('dcat.admin.farm-user-summarys');
  65. }
  66. return $content
  67. ->title($this->title)
  68. ->description("用户 {$user->username}(ID: {$user->id})的农场信息汇总")
  69. ->body(function (Row $row) use ($user) {
  70. // 第一行:用户基本信息和房屋信息
  71. $row->column(6, $this->userInfoCard($user));
  72. $row->column(6, $this->houseInfoCard($user->id));
  73. // 第二行:土地信息和作物信息
  74. $row->column(12, $this->landInfoCard($user->id));
  75. // 第三行:物品信息
  76. $row->column(12, $this->itemInfoCard($user->id));
  77. // 第四行:代币信息
  78. $row->column(12, $this->fundInfoCard($user->id));
  79. // 第五行:神像buff信息
  80. $row->column(12, $this->buffInfoCard($user->id));
  81. });
  82. }
  83. /**
  84. * 用户基本信息卡片
  85. *
  86. * @param User $user 用户对象
  87. * @return Card
  88. */
  89. protected function userInfoCard(User $user)
  90. {
  91. $userInfo = $user->info;
  92. $avatar = $userInfo ? $userInfo->avatar : '';
  93. $nickname = $userInfo ? $userInfo->nickname : '';
  94. $content = <<<HTML
  95. <div class="row">
  96. <div class="col-md-4">
  97. <img src="{$avatar}" class="img-fluid rounded" style="max-width: 100px;" onerror="this.src='https://via.placeholder.com/100'">
  98. </div>
  99. <div class="col-md-8">
  100. <p><strong>用户ID:</strong>{$user->id}</p>
  101. <p><strong>用户名:</strong>{$user->username}</p>
  102. <p><strong>昵称:</strong>{$nickname}</p>
  103. <p><strong>注册时间:</strong>{$user->created_at}</p>
  104. </div>
  105. </div>
  106. HTML;
  107. return new Card('用户基本信息', $content);
  108. }
  109. /**
  110. * 房屋信息卡片
  111. *
  112. * @param int $userId 用户ID
  113. * @return Card
  114. */
  115. protected function houseInfoCard($userId)
  116. {
  117. // 获取用户的农场信息
  118. $farmUser = FarmUser::where('user_id', $userId)->first();
  119. if (!$farmUser) {
  120. return new Card('房屋信息', new Alert('warning', '该用户没有农场信息'));
  121. }
  122. // 获取房屋配置信息
  123. $houseConfig = FarmHouseConfig::where('level', $farmUser->house_level)->first();
  124. $content = <<<HTML
  125. <div class="row">
  126. <div class="col-md-12">
  127. <p><strong>房屋等级:</strong>{$farmUser->house_level}</p>
  128. <p><strong>最后升级时间:</strong>{$farmUser->last_upgrade_time}</p>
  129. <p><strong>产出加成:</strong>{$houseConfig->output_bonus}</p>
  130. <p><strong>特殊土地上限:</strong>{$houseConfig->special_land_limit}</p>
  131. <p><strong>可用土地数量:</strong>{$houseConfig->available_lands}</p>
  132. HTML;
  133. // 如果有降级天数,显示降级信息
  134. if ($houseConfig->downgrade_days) {
  135. $content .= "<p><strong>降级天数:</strong>{$houseConfig->downgrade_days}</p>";
  136. }
  137. $content .= <<<HTML
  138. </div>
  139. </div>
  140. <div class="row mt-2">
  141. <div class="col-md-12">
  142. <a href="javascript:void(0);" class="btn btn-sm btn-primary" onclick="window.open('/admin/farm-house-configs', '_blank')">查看房屋配置</a>
  143. </div>
  144. </div>
  145. HTML;
  146. return new Card('房屋信息', $content);
  147. }
  148. /**
  149. * 土地信息卡片
  150. *
  151. * @param int $userId 用户ID
  152. * @return Card
  153. */
  154. protected function landInfoCard($userId)
  155. {
  156. // 获取用户的土地信息
  157. /**
  158. * @var FarmLand $land
  159. */
  160. $lands = FarmLand::with([ 'landType', 'crop.seed' ])
  161. ->where('user_id', $userId)
  162. ->get();
  163. if ($lands->isEmpty()) {
  164. return new Card('土地信息', new Alert('warning', '该用户没有土地信息'));
  165. }
  166. // 土地类型统计
  167. $landTypeStats = $lands->groupBy('land_type')->map->count();
  168. // 土地状态统计
  169. $landStatusStats = $lands->groupBy('status')->map->count();
  170. // 创建土地类型和状态的统计表格
  171. $statsContent = '<div class="row">';
  172. // 土地类型统计
  173. $statsContent .= '<div class="col-md-6">';
  174. $statsContent .= '<h5>土地类型统计</h5>';
  175. $statsContent .= '<table class="table table-sm table-bordered">';
  176. $statsContent .= '<thead><tr><th>土地类型</th><th>数量</th></tr></thead>';
  177. $statsContent .= '<tbody>';
  178. $landTypeNames = [
  179. 1 => '普通土地',
  180. 2 => '红土地',
  181. 3 => '黑土地',
  182. 4 => '金土地',
  183. 5 => '蓝土地',
  184. 6 => '紫土地',
  185. ];
  186. foreach ($landTypeStats as $typeId => $count) {
  187. $typeName = $landTypeNames[$typeId] ?? "类型{$typeId}";
  188. $statsContent .= "<tr><td>{$typeName}</td><td>{$count}</td></tr>";
  189. }
  190. $statsContent .= '</tbody></table></div>';
  191. // 土地状态统计
  192. $statsContent .= '<div class="col-md-6">';
  193. $statsContent .= '<h5>土地状态统计</h5>';
  194. $statsContent .= '<table class="table table-sm table-bordered">';
  195. $statsContent .= '<thead><tr><th>土地状态</th><th>数量</th></tr></thead>';
  196. $statsContent .= '<tbody>';
  197. $landStatusNames = [
  198. 0 => '空闲',
  199. 1 => '种植中',
  200. 2 => '灾害',
  201. 3 => '可收获',
  202. 4 => '枯萎',
  203. ];
  204. foreach ($landStatusStats as $statusId => $count) {
  205. $statusName = $landStatusNames[$statusId] ?? "状态{$statusId}";
  206. $statsContent .= "<tr><td>{$statusName}</td><td>{$count}</td></tr>";
  207. }
  208. $statsContent .= '</tbody></table></div>';
  209. $statsContent .= '</div>';
  210. // 创建土地详情表格
  211. $headers = [ 'ID','位置', '土地类型', '状态', '种植作物', '种植时间', '生长阶段', '本阶段开始时间', '本阶段结束时间' ];
  212. $rows = [];
  213. foreach ($lands as $land) {
  214. $landType = $land->landType ? $land->landType->name : "类型{$land->land_type}";
  215. $status = $landStatusNames[$land->status] ?? "状态{$land->status}";
  216. $crop = $land->crop;
  217. $cropInfo = '无';
  218. $plantTime = '';
  219. $growthStage = '';
  220. $stageStartTime = '';
  221. $stageEndTime = '';
  222. if ($crop) {
  223. $seedName = $crop->seed ? $crop->seed->name : "种子{$crop->seed_id}";
  224. $cropInfo = $seedName;
  225. $plantTime = $crop->plant_time;
  226. $growthStage = $this->getGrowthStageName($crop->growth_stage);
  227. $stageStartTime = $crop->stage_start_time;
  228. $stageEndTime = $crop->stage_end_time;
  229. }
  230. $rows[] = [
  231. $land->id,
  232. $land->position,
  233. $landType,
  234. $status,
  235. $cropInfo,
  236. $plantTime,
  237. $growthStage,
  238. $stageStartTime,
  239. $stageEndTime,
  240. ];
  241. }
  242. $table = new Table($headers, $rows);
  243. $content = $statsContent . '<div class="mt-3">' . $table->render() . '</div>';
  244. $content .= <<<HTML
  245. <div class="row mt-2">
  246. <div class="col-md-12">
  247. <a href="javascript:void(0);" class="btn btn-sm btn-primary"
  248. onclick="window.open('/admin/farm-lands?user_id={$userId}', '_blank')">查看土地详情</a>
  249. <a href="javascript:void(0);" class="btn btn-sm btn-primary"
  250. onclick="window.open('/admin/farm-crops?user_id={$userId}', '_blank')">查看作物详情</a>
  251. </div>
  252. </div>
  253. HTML;
  254. return new Card('土地信息', $content);
  255. }
  256. /**
  257. * 获取生长阶段名称
  258. *
  259. * @param GROWTH_STAGE $stage 生长阶段枚举
  260. * @return string 生长阶段名称
  261. */
  262. protected function getGrowthStageName(GROWTH_STAGE $stage)
  263. {
  264. $stageNames = GROWTH_STAGE::getValueDescription();
  265. $stageValue = $stage->value;
  266. return $stageNames[$stageValue] ?? "阶段{$stageValue}";
  267. }
  268. /**
  269. * 物品信息卡片
  270. *
  271. * @param int $userId 用户ID
  272. * @return Card
  273. */
  274. protected function itemInfoCard($userId)
  275. {
  276. // 获取用户的物品信息
  277. $items = ItemUser::with('item')
  278. ->where('user_id', $userId)
  279. ->orderBy('quantity', 'desc')
  280. ->limit(20)
  281. ->get();
  282. if ($items->isEmpty()) {
  283. return new Card('物品信息', new Alert('warning', '该用户没有物品信息'));
  284. }
  285. // 创建物品表格
  286. $headers = [ '物品ID', '物品名称', '数量', '物品类型', '过期时间' ];
  287. $rows = [];
  288. foreach ($items as $item) {
  289. $itemName = $item->item ? $item->item->name : "物品{$item->item_id}";
  290. $itemType = $item->item ? $this->getItemTypeName($item->item->type) : '';
  291. $rows[] = [
  292. $item->item_id,
  293. $itemName,
  294. $item->quantity,
  295. $itemType,
  296. $item->expire_at ?: '永久',
  297. ];
  298. }
  299. $table = new Table($headers, $rows);
  300. // 获取用户物品总数
  301. $totalCount = ItemUser::where('user_id', $userId)->count();
  302. $content = <<<HTML
  303. <div class="alert alert-info">
  304. 用户共有 {$totalCount} 种物品,下表显示数量最多的前20种物品
  305. </div>
  306. {$table->render()}
  307. <div class="row mt-2">
  308. <div class="col-md-12">
  309. <a href="javascript:void(0);" class="btn btn-sm btn-primary" onclick="window.open('/admin/game-items-users?user_id={$userId}', '_blank')">查看物品详情</a>
  310. </div>
  311. </div>
  312. HTML;
  313. return new Card('物品信息', $content);
  314. }
  315. /**
  316. * 获取物品类型名称
  317. *
  318. * @param ITEM_TYPE $type 物品类型枚举
  319. * @return string 物品类型名称
  320. */
  321. protected function getItemTypeName(ITEM_TYPE $type)
  322. {
  323. $typeNames = ITEM_TYPE::getValueDescription();
  324. $typeValue = $type->value;
  325. return $typeNames[$typeValue] ?? "类型{$typeValue}";
  326. }
  327. /**
  328. * 代币信息卡片
  329. *
  330. * @param int $userId 用户ID
  331. * @return Card
  332. */
  333. protected function fundInfoCard($userId)
  334. {
  335. // 获取用户的代币信息
  336. $funds = FundModel::where('user_id', $userId)->get();
  337. if ($funds->isEmpty()) {
  338. return new Card('代币信息', new Alert('warning', '该用户没有代币信息'));
  339. }
  340. // 获取资金类型名称映射
  341. $fundNames = AccountService::getFundsDesc();
  342. // 创建代币表格
  343. $headers = [ '账户ID', '账户名称', '余额', '更新时间' ];
  344. $rows = [];
  345. foreach ($funds as $fund) {
  346. $fundName = $fundNames[$fund->fund_id->value()] ?? "账户{$fund->fund_id->value()}";
  347. $balance = $fund->balance;
  348. $rows[] = [
  349. $fund->fund_id->value(),
  350. $fundName,
  351. $balance,
  352. $fund->update_time ? date('Y-m-d H:i:s', $fund->update_time) : '',
  353. ];
  354. }
  355. $table = new Table($headers, $rows);
  356. $content = <<<HTML
  357. {$table->render()}
  358. <div class="row mt-2">
  359. <div class="col-md-12">
  360. <a href="javascript:void(0);" class="btn btn-sm btn-primary" onclick="window.open('/admin/fund-accounts?user_id={$userId}', '_blank')">查看账户详情</a>
  361. </div>
  362. </div>
  363. HTML;
  364. return new Card('代币信息', $content);
  365. }
  366. /**
  367. * 神像buff信息卡片
  368. *
  369. * @param int $userId 用户ID
  370. * @return Card
  371. */
  372. protected function buffInfoCard($userId)
  373. {
  374. // 获取用户的神像buff信息
  375. $buffs = FarmGodBuff::where('user_id', $userId)
  376. ->orderBy('expire_time', 'desc')
  377. ->get();
  378. if ($buffs->isEmpty()) {
  379. return new Card('神像加持信息', new Alert('warning', '该用户没有神像加持信息'));
  380. }
  381. // 创建buff表格
  382. $headers = [ '加持类型', '过期时间', '状态' ];
  383. $rows = [];
  384. $buffTypeNames = [
  385. 1 => '丰收之神',
  386. 2 => '雨露之神',
  387. 3 => '屠草之神',
  388. 4 => '拭虫之神',
  389. ];
  390. foreach ($buffs as $buff) {
  391. $buffType = $buffTypeNames[$buff->buff_type] ?? "类型{$buff->buff_type}";
  392. $isActive = now()->lt($buff->expire_time);
  393. $status = $isActive ? '<span class="badge badge-success">生效中</span>' : '<span class="badge badge-secondary">已过期</span>';
  394. $rows[] = [
  395. $buffType,
  396. $buff->expire_time,
  397. $status,
  398. ];
  399. }
  400. $table = new Table($headers, $rows);
  401. $content = $table->render();
  402. return new Card('神像加持信息', $content);
  403. }
  404. /**
  405. * 用户列表网格
  406. *
  407. * @return Grid
  408. */
  409. protected function grid()
  410. {
  411. return Grid::make(User::with([ 'info', 'farmUser' ]), function (Grid $grid) {
  412. $grid->column('id', 'ID')->sortable();
  413. // 用户基本信息
  414. $grid->column('username', '用户名');
  415. $grid->column('info.nickname', '昵称');
  416. // 农场信息
  417. $grid->column('farmUser.house_level', '房屋等级')->sortable();
  418. // 土地统计
  419. $grid->column('id', '土地统计')->display(function ($userId) {
  420. $lands = FarmLand::where('user_id', $userId)->get();
  421. if ($lands->isEmpty()) {
  422. return '<span class="text-muted">无土地</span>';
  423. }
  424. $landTypeStats = $lands->groupBy('land_type')->map->count();
  425. $totalLands = $lands->count();
  426. $html = "<div>总计: {$totalLands}块土地</div>";
  427. $landTypeNames = [
  428. 1 => '普通土地',
  429. 2 => '红土地',
  430. 3 => '黑土地',
  431. 4 => '金土地',
  432. 5 => '蓝土地',
  433. 6 => '紫土地',
  434. ];
  435. foreach ($landTypeStats as $typeId => $count) {
  436. $typeName = $landTypeNames[$typeId] ?? "类型{$typeId}";
  437. $html .= "<div>{$typeName}: {$count}块</div>";
  438. }
  439. return $html;
  440. });
  441. // 作物统计
  442. $grid->column('id', '作物统计')->display(function ($userId) {
  443. $crops = FarmCrop::where('user_id', $userId)->count();
  444. return $crops > 0 ? "{$crops}种作物" : '<span class="text-muted">无作物</span>';
  445. });
  446. // 物品统计
  447. $grid->column('id', '物品统计')->display(function ($userId) {
  448. $itemCount = ItemUser::where('user_id', $userId)->count();
  449. return $itemCount > 0 ? "{$itemCount}种物品" : '<span class="text-muted">无物品</span>';
  450. });
  451. // 代币统计
  452. $grid->column('id', '代币统计')->display(function ($userId) {
  453. $fundCount = FundModel::where('user_id', $userId)->count();
  454. return $fundCount > 0 ? "{$fundCount}个账户" : '<span class="text-muted">无账户</span>';
  455. });
  456. $grid->column('created_at', '创建时间')->sortable();
  457. // 添加查看详情操作
  458. $grid->actions(function (Grid\Displayers\Actions $actions) {
  459. // 禁用默认操作按钮
  460. $actions->disableDelete();
  461. $actions->disableEdit();
  462. $actions->disableQuickEdit();
  463. // 修改查看按钮,使其打开详情页
  464. $actions->append('<a href="' . admin_url('farm-user-summary/' . $actions->getKey()) . '" class="btn btn-sm btn-primary">查看详情</a>');
  465. });
  466. // 禁用创建按钮
  467. $grid->disableCreateButton();
  468. // 禁用批量操作
  469. $grid->disableBatchActions();
  470. // 添加搜索
  471. $grid->filter(function (Grid\Filter $filter) {
  472. $filter->equal('id', '用户ID');
  473. $filter->like('username', '用户名');
  474. $filter->like('info.nickname', '昵称');
  475. $filter->equal('farmUser.house_level', '房屋等级');
  476. });
  477. });
  478. }
  479. }