RecipeController.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. <?php
  2. namespace App\Module\GameItems\AdminControllers;
  3. use App\Module\GameItems\Repositorys\ItemRecipeRepository;
  4. use Dcat\Admin\Form;
  5. use Dcat\Admin\Grid;
  6. use Dcat\Admin\Show;
  7. use UCore\DcatAdmin\AdminController;
  8. use Dcat\Admin\Layout\Content;
  9. use Spatie\RouteAttributes\Attributes\Resource;
  10. use App\Module\GameItems\AdminControllers\Helper\FilterHelper;
  11. use App\Module\GameItems\AdminControllers\Helper\FormHelper;
  12. use App\Module\GameItems\AdminControllers\Helper\GridHelper;
  13. use App\Module\GameItems\AdminControllers\Helper\ShowHelper;
  14. use App\Module\GameItems\AdminControllers\Actions\DuplicateItemRecipeAction;
  15. /**
  16. * 合成配方管理控制器
  17. *
  18. * @package App\Module\GameItems\AdminControllers
  19. */
  20. #[Resource('game-items-recipes', names: 'dcat.admin.game-items-recipes')]
  21. class RecipeController extends AdminController
  22. {
  23. /**
  24. * 标题
  25. *
  26. * @var string
  27. */
  28. protected $title = '合成配方管理';
  29. /**
  30. * 列表页
  31. *
  32. * @return Grid
  33. */
  34. protected function grid()
  35. {
  36. return Grid::make(new ItemRecipeRepository(), function (Grid $grid) {
  37. // 首先设置关联查询,确保数据正确预加载
  38. $grid->model()->with(['consumeGroup.consumeItems', 'rewardGroup.rewardItems', 'conditionGroup.conditionItems']);
  39. $helper = new GridHelper($grid, $this);
  40. $helper->columnId();
  41. $grid->column('name', '配方名称');
  42. $grid->column('code', '配方编码');
  43. $grid->column('description', '描述')->limit(50);
  44. // 消耗组列 - 可点击跳转
  45. $grid->column('consumeGroup.name', '消耗组')->display(function ($name) {
  46. if (!$name || !$this->consume_group_id) {
  47. return '<span class="text-muted">无消耗</span>';
  48. }
  49. return $name;
  50. })->link(function () {
  51. if (!$this->consume_group_id) {
  52. return '';
  53. }
  54. return admin_url('game-consume-groups/' . $this->consume_group_id);
  55. });
  56. // 奖励组列 - 可点击跳转
  57. $grid->column('rewardGroup.name', '奖励组')->display(function ($name) {
  58. if (!$name || !$this->reward_group_id) {
  59. return '<span class="text-danger">未配置</span>';
  60. }
  61. return $name;
  62. })->link(function () {
  63. if (!$this->reward_group_id) {
  64. return '';
  65. }
  66. return admin_url('game-reward-groups/' . $this->reward_group_id);
  67. });
  68. // 条件组列 - 可点击跳转
  69. $grid->column('conditionGroup.name', '条件组')->display(function ($name) {
  70. if (!$name || !$this->condition_group_id) {
  71. return '<span class="text-muted">无条件</span>';
  72. }
  73. return $name;
  74. })->link(function () {
  75. if (!$this->condition_group_id) {
  76. return '';
  77. }
  78. return admin_url('game-condition-groups/' . $this->condition_group_id);
  79. });
  80. // 消耗组详情列
  81. $grid->column('consume_group_details', '消耗组详情')->display(function () {
  82. return $this->formatConsumeDetails();
  83. })->width('200px');
  84. // 奖励组详情列
  85. $grid->column('reward_group_details', '奖励组详情')->display(function () {
  86. return $this->formatRewardDetails();
  87. })->width('200px');
  88. // 条件组详情列
  89. $grid->column('condition_group_details', '条件组详情')->display(function () {
  90. return $this->formatConditionDetails();
  91. })->width('200px');
  92. // 展示属性列
  93. $grid->column('display_attributes', '展示属性')->display(function ($value) {
  94. if (empty($value)) {
  95. return '-';
  96. }
  97. if (is_string($value)) {
  98. $value = json_decode($value, true);
  99. }
  100. $html = '<div style="max-width: 200px; max-height: 100px; overflow: auto;">';
  101. foreach ((array)$value as $key => $val) {
  102. if (empty($val)) continue;
  103. $html .= "<div><strong>{$key}</strong>: {$val}</div>";
  104. }
  105. $html .= '</div>';
  106. return $html;
  107. })->width('200px');
  108. $grid->column('success_rate', '成功率')->display(function ($value) {
  109. return $value . '%';
  110. });
  111. $grid->column('cooldown_seconds', '冷却时间(秒)');
  112. $grid->column('is_active', '是否激活')->switch();
  113. $grid->column('created_at', '创建时间');
  114. $grid->column('updated_at', '更新时间');
  115. // 筛选
  116. $grid->filter(function ($filter) {
  117. $helper = new FilterHelper($filter, $this);
  118. $helper->equal('id', 'ID');
  119. $filter->like('name', '配方名称');
  120. $filter->like('code', '配方编码');
  121. $filter->equal('consume_group_id', '消耗组')->select(
  122. \App\Module\Game\Models\GameConsumeGroup::pluck('name', 'id')
  123. );
  124. $filter->equal('reward_group_id', '奖励组')->select(
  125. \App\Module\Game\Models\GameRewardGroup::pluck('name', 'id')
  126. );
  127. $filter->equal('condition_group_id', '条件组')->select(
  128. \App\Module\Game\Models\GameConditionGroup::pluck('name', 'id')
  129. );
  130. $filter->equal('is_active', '是否激活')->radio([
  131. 1 => '是',
  132. 0 => '否',
  133. ]);
  134. });
  135. // 行操作
  136. $grid->actions(function (Grid\Displayers\Actions $actions) {
  137. // 添加复制按钮
  138. $actions->append(new DuplicateItemRecipeAction());
  139. });
  140. });
  141. }
  142. /**
  143. * 详情页
  144. *
  145. * @param mixed $id
  146. * @param Content $content
  147. * @return Content
  148. */
  149. public function show($id, Content $content)
  150. {
  151. return $content
  152. ->header($this->title)
  153. ->description('详情')
  154. ->body($this->detail($id));
  155. }
  156. /**
  157. * 详情页
  158. *
  159. * @param mixed $id
  160. * @return Show
  161. */
  162. protected function detail($id)
  163. {
  164. return Show::make($id, new ItemRecipeRepository(), function (Show $show) {
  165. $helper = new ShowHelper($show, $this);
  166. $helper->field('id', 'ID');
  167. $helper->field('name', '配方名称');
  168. $helper->field('code', '配方编码');
  169. $helper->field('description', '配方描述');
  170. // 展示属性
  171. $show->field('display_attributes', '展示属性')->as(function ($value) {
  172. if (empty($value)) {
  173. return '无';
  174. }
  175. if (is_string($value)) {
  176. $value = json_decode($value, true);
  177. }
  178. $html = '<div class="table-responsive"><table class="table table-sm table-bordered">';
  179. $html .= '<thead><tr><th>属性</th><th>值</th></tr></thead><tbody>';
  180. foreach ((array)$value as $key => $val) {
  181. if (empty($val)) continue;
  182. $html .= "<tr><td><strong>{$key}</strong></td><td>{$val}</td></tr>";
  183. }
  184. $html .= '</tbody></table></div>';
  185. return $html;
  186. });
  187. $show->field('success_rate', '成功率')->as(function ($value) {
  188. return $value . '%';
  189. });
  190. $helper->field('cooldown_seconds', '冷却时间(秒)');
  191. $show->field('is_active', '是否激活')->as(function ($value) {
  192. return $value ? '是' : '否';
  193. });
  194. // 显示消耗组
  195. $show->divider('消耗组');
  196. $show->field('consumeGroup.name', '消耗组名称');
  197. $show->field('consumeGroup.description', '消耗组描述');
  198. // 显示奖励组
  199. $show->divider('奖励组');
  200. $show->field('rewardGroup.name', '奖励组名称');
  201. $show->field('rewardGroup.description', '奖励组描述');
  202. // 显示条件组
  203. $show->divider('条件组');
  204. $show->field('conditionGroup.name', '条件组名称');
  205. $show->field('conditionGroup.description', '条件组描述');
  206. $helper->field('created_at', '创建时间');
  207. $helper->field('updated_at', '更新时间');
  208. });
  209. }
  210. /**
  211. * 创建页
  212. *
  213. * @param Content $content
  214. * @return Content
  215. */
  216. public function create(Content $content)
  217. {
  218. return $content
  219. ->header($this->title)
  220. ->description('创建')
  221. ->body($this->form());
  222. }
  223. /**
  224. * 编辑页
  225. *
  226. * @param mixed $id
  227. * @param Content $content
  228. * @return Content
  229. */
  230. public function edit($id, Content $content)
  231. {
  232. return $content
  233. ->header($this->title)
  234. ->description('编辑')
  235. ->body($this->form()->edit($id));
  236. }
  237. /**
  238. * 表单
  239. *
  240. * @return Form
  241. */
  242. protected function form()
  243. {
  244. return Form::make(new ItemRecipeRepository(), function (Form $form) {
  245. $helper = new \App\Module\GameItems\AdminControllers\Helper\FormHelper($form, $this);
  246. $helper->text('name', '配方名称')->required();
  247. $helper->text('code', '配方编码')
  248. ->help('唯一的配方编码,用于程序识别');
  249. $form->textarea('description', '配方描述')
  250. ->help('配方的详细描述');
  251. // 消耗组选择
  252. $form->select('consume_group_id', '消耗组')
  253. ->options(\App\Module\Game\Models\GameConsumeGroup::pluck('name', 'id'))
  254. ->help('选择合成时需要消耗的材料组');
  255. // 奖励组选择
  256. $form->select('reward_group_id', '奖励组')
  257. ->options(\App\Module\Game\Models\GameRewardGroup::pluck('name', 'id'))
  258. ->help('选择合成成功后获得的奖励组')
  259. ->required();
  260. // 条件组选择
  261. $form->select('condition_group_id', '条件组')
  262. ->options(\App\Module\Game\Models\GameConditionGroup::pluck('name', 'id'))
  263. ->help('选择解锁该配方需要满足的条件组(可选)');
  264. // 展示属性
  265. $form->keyValue('display_attributes', '展示属性')
  266. ->help('用于界面展示的属性,如图标路径、颜色、描述等。常用属性:icon(图标路径)、color(颜色)、description(描述)、background(背景图片)、animation(动画效果)、badge(特殊标记)、difficulty(难度等级)、recommended_level(推荐等级)、source(配方来源)、craft_time_display(制作时间显示)');
  267. $form->rate('success_rate', '成功率')
  268. ->default(100)
  269. ->help('合成成功的概率,100表示100%成功率');
  270. $form->number('cooldown_seconds', '冷却时间(秒)')
  271. ->default(0)
  272. ->min(0)
  273. ->help('两次合成之间的冷却时间,0表示无冷却');
  274. $form->number('sort_order', '排序权重')
  275. ->default(0)
  276. ->help('数值越大排序越靠前');
  277. $form->switch('is_active', '是否激活')
  278. ->default(true)
  279. ->help('是否激活该配方');
  280. });
  281. }
  282. }