PromotionAdminService.php 6.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <?php
  2. namespace App\Services;
  3. use App\Models\PromotionActivity;
  4. use App\Support\PromotionRules;
  5. use Illuminate\Support\Facades\DB;
  6. use Illuminate\Support\Facades\Schema;
  7. use Illuminate\Support\Facades\Validator;
  8. use Illuminate\Validation\ValidationException;
  9. class PromotionAdminService
  10. {
  11. public function options(): array
  12. {
  13. $types = []; foreach (PromotionRules::types() as $value => $label) $types[] = compact('value', 'label');
  14. return ['types' => $types, 'defaults' => [7 => PromotionRules::defaults(7), 8 => PromotionRules::defaults(8), 9 => PromotionRules::defaults(9)],
  15. 'prizes' => PromotionRules::PRIZES, 'tasks' => PromotionRules::TASKS];
  16. }
  17. public function listing(array $input): array
  18. {
  19. $input = Validator::make($input, ['page' => ['sometimes', 'integer', 'min:1'], 'limit' => ['sometimes', 'integer', 'between:1,100'],
  20. 'type' => ['sometimes', 'integer', 'in:7,8,9'], 'status' => ['sometimes', 'integer', 'in:0,1'], 'title' => ['sometimes', 'string', 'max:140']])->validate();
  21. $q = PromotionActivity::query();
  22. foreach (['type', 'status'] as $key) if (isset($input[$key])) $q->where($key, $input[$key]);
  23. if (!empty($input['title'])) $q->where('title', 'like', '%' . $input['title'] . '%');
  24. return ['total' => $q->count(), 'data' => $q->orderByDesc('sort')->orderByDesc('id')->forPage($input['page'] ?? 1, $input['limit'] ?? 20)->get()->map(fn ($r) => $this->format($r))->all()];
  25. }
  26. public function detail(int $id): array
  27. {
  28. $row = PromotionActivity::find($id);
  29. if (!$row) throw ValidationException::withMessages(['id' => '独立活动不存在']);
  30. return $this->format($row);
  31. }
  32. private function format(PromotionActivity $row): array
  33. {
  34. return array_replace($row->toArray(), ['params' => json_decode($row->params, true),
  35. 'start_time' => date('Y-m-d H:i:s', (int)$row->start_time), 'end_time' => date('Y-m-d H:i:s', (int)$row->end_time),
  36. 'first_published_at' => DB::table('promotion_campaigns')->where('activity_id', $row->id)->value('first_published_at')]);
  37. }
  38. public function save(array $input): array
  39. {
  40. $money = ['nullable', 'numeric', 'min:0', 'regex:/^\d{1,12}(\.\d{1,2})?$/'];
  41. $data = Validator::make($input, ['id' => ['sometimes', 'integer', 'min:1'], 'title' => ['required', 'string', 'max:140'],
  42. 'sub_title' => ['sometimes', 'nullable', 'string', 'max:200'], 'type' => ['required', 'integer', 'in:7,8,9'], 'status' => ['required', 'integer', 'in:0,1'],
  43. 'start_time' => ['required', 'date'], 'end_time' => ['required', 'date', 'after:start_time'], 'lang' => ['sometimes', 'string', 'max:10'],
  44. 'sort' => ['sometimes', 'integer', 'between:0,4294967295'], 'params' => ['sometimes', 'array'], 'content' => ['sometimes', 'nullable', 'string', 'max:100000'],
  45. 'image' => ['sometimes', 'nullable', 'string', 'max:2048'], 'publish_platforms' => ['sometimes', 'array'], 'publish_platforms.*' => ['string', 'distinct', 'in:PC,H5,APP'],
  46. 'register_time_limited' => ['sometimes', 'boolean'], 'register_start_time' => ['nullable', 'required_if:register_time_limited,1', 'date'],
  47. 'register_end_time' => ['nullable', 'required_if:register_time_limited,1', 'date', 'after_or_equal:register_start_time'],
  48. 'register_platforms' => ['sometimes', 'array'], 'register_platforms.*' => ['string', 'distinct', 'in:PC,H5,APP'], 'deposit_limited' => ['sometimes', 'boolean'],
  49. 'deposit_min' => [...$money, 'required_if:deposit_limited,1'], 'deposit_max' => [...$money, 'required_if:deposit_limited,1', 'gte:deposit_min'],
  50. 'show_ineligible' => ['sometimes', 'boolean'], 'reward_quota' => ['sometimes', 'nullable', 'integer', 'between:0,2147483647'], 'budget' => ['sometimes', ...$money]])->validate();
  51. return DB::transaction(function () use ($data) {
  52. $row = isset($data['id']) ? PromotionActivity::where('id', $data['id'])->lockForUpdate()->first() : new PromotionActivity();
  53. if (!$row) throw ValidationException::withMessages(['id' => '独立活动不存在']);
  54. if ($row->exists && (int)$row->type !== (int)$data['type']) throw ValidationException::withMessages(['type' => '创建后不能变更活动类型']);
  55. $before = $row->exists ? $row->toArray() : [];
  56. $params = array_replace($row->params ? json_decode($row->params, true) : [], $data['params'] ?? []);
  57. $values = $data; unset($values['id']);
  58. $values['params'] = json_encode(PromotionRules::normalize((int)$data['type'], $params));
  59. $values['start_time'] = strtotime($data['start_time']); $values['end_time'] = strtotime($data['end_time']);
  60. if (!$row->exists) $values += ['lang' => 'zh', 'sort' => 0, 'publish_platforms' => [], 'register_platforms' => []];
  61. $row->fill($values); $row->save(); PromotionService::publish($row);
  62. if (Schema::hasTable('operation_audits')) OperationAuditService::record('promotion', $row->id, $before ? 'update' : 'create', $before, $row->toArray());
  63. return $this->format($row);
  64. }, 3);
  65. }
  66. public function status(int $id, int $status): array
  67. {
  68. return DB::transaction(function () use ($id, $status) {
  69. $row = PromotionActivity::where('id', $id)->lockForUpdate()->first();
  70. if (!$row) throw ValidationException::withMessages(['id' => '独立活动不存在']);
  71. $before = $row->toArray(); $row->status = $status; $row->save(); PromotionService::publish($row);
  72. if (Schema::hasTable('operation_audits')) OperationAuditService::record('promotion', $id, 'status', $before, $row->toArray());
  73. return $this->format($row);
  74. }, 3);
  75. }
  76. public function records(array $input): array
  77. {
  78. $input = Validator::make($input, ['activity_id' => ['required', 'integer', 'min:1'], 'user_id' => ['sometimes', 'integer', 'min:1'],
  79. 'kind' => ['required', 'in:accounts,rounds,tasks,spins,rewards'], 'page' => ['sometimes', 'integer', 'min:1'], 'limit' => ['sometimes', 'integer', 'between:1,100']])->validate();
  80. $q = DB::table('promotion_accounts as a')->where('a.activity_id', $input['activity_id']);
  81. if (isset($input['user_id'])) $q->where('a.user_id', $input['user_id']);
  82. if ($input['kind'] === 'accounts') $q->select('a.*')->orderByDesc('a.id');
  83. else {
  84. $table = match ($input['kind']) { 'rounds' => 'promotion_rounds', 'tasks' => 'promotion_task_grants', 'spins' => 'promotion_spins', 'rewards' => 'promotion_rewards' };
  85. $q->join($table . ' as r', 'r.account_id', '=', 'a.id')->select(['r.*', 'a.user_id', 'a.activity_id'])->orderByDesc('r.id');
  86. }
  87. return ['total' => $q->count(), 'data' => $q->forPage($input['page'] ?? 1, $input['limit'] ?? 20)->get()];
  88. }
  89. }