ShareEarning.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. namespace App\Http\Controllers\admin;
  3. use App\Constants\HttpStatus;
  4. use App\Http\Controllers\Controller;
  5. use App\Models\ShareBlacklist;
  6. use App\Services\Sharing\ShareAdminService;
  7. use App\Models\User;
  8. use App\Services\OperationAuditService;
  9. use App\Services\ShareEarningReportService;
  10. use Illuminate\Support\Facades\DB;
  11. use Illuminate\Validation\Rule;
  12. use Illuminate\Validation\ValidationException;
  13. use Illuminate\Database\QueryException;
  14. use Illuminate\Support\Facades\Log;
  15. use Throwable;
  16. class ShareEarning extends Controller
  17. {
  18. public function memberList(ShareEarningReportService $service)
  19. {
  20. return $this->report(fn ($params) => $service->memberDays($params), $this->dateListRules());
  21. }
  22. public function promoterDetails(ShareEarningReportService $service)
  23. {
  24. return $this->report(fn ($params) => $service->promoterDetails($params), $this->detailRules());
  25. }
  26. public function registrationDetails(ShareEarningReportService $service)
  27. {
  28. return $this->report(fn ($params) => $service->registrationDetails($params), $this->detailRules());
  29. }
  30. public function summary(ShareEarningReportService $service)
  31. {
  32. return $this->report(fn ($params) => $service->summary($params), $this->dateListRules([
  33. 'account' => ['nullable', 'string', 'max:100'],
  34. ]));
  35. }
  36. public function settings(ShareAdminService $service)
  37. {
  38. return $this->run(fn () => $service->settings());
  39. }
  40. public function saveSettings(ShareAdminService $service)
  41. {
  42. return $this->run(fn () => $service->saveSettings(request()->all()));
  43. }
  44. public function blacklists()
  45. {
  46. return $this->run(function () {
  47. $params = request()->validate([
  48. 'page' => ['nullable', 'integer', 'min:1'],
  49. 'limit' => ['nullable', 'integer', 'min:1', 'max:200'],
  50. 'account' => ['nullable', 'string', 'max:100'],
  51. ]);
  52. $query = ShareBlacklist::query();
  53. if (!empty($params['account'])) {
  54. $ids = User::query()->where('account', 'like', '%' . $params['account'] . '%')->pluck('id');
  55. $query->whereIn('user_id', $ids);
  56. }
  57. $total = $query->count();
  58. $rows = $query->orderByDesc('id')->forPage((int)($params['page'] ?? 1), (int)($params['limit'] ?? 20))->get();
  59. $users = User::query()->whereIn('id', $rows->pluck('user_id'))->get()->keyBy('id');
  60. $rows->each(function ($row) use ($users) {
  61. $user = $users->get($row->user_id);
  62. $row->account = (string)($user->account ?? '');
  63. $row->nickname = (string)($user->first_name ?? '');
  64. });
  65. return ['total' => $total, 'data' => $rows];
  66. });
  67. }
  68. public function saveBlacklist()
  69. {
  70. return $this->run(function () {
  71. $params = request()->validate([
  72. 'id' => ['nullable', 'integer'],
  73. 'account' => ['required_without:id', 'string', 'max:100'],
  74. 'blocked_categories' => ['required', 'array', 'min:1'],
  75. 'blocked_categories.*' => [Rule::in(['sports', 'lottery', 'third_party_game'])],
  76. 'status' => ['nullable', Rule::in([0, 1])],
  77. ]);
  78. return DB::transaction(function () use ($params) {
  79. $id = (int)($params['id'] ?? 0);
  80. $model = $id ? ShareBlacklist::query()->lockForUpdate()->findOrFail($id) : new ShareBlacklist();
  81. $before = $model->exists ? $model->toArray() : [];
  82. if (!$id) {
  83. $user = User::query()->where('account', $params['account'])->first();
  84. if (!$user) throw new \RuntimeException('会员账号不存在');
  85. $existing = ShareBlacklist::withTrashed()->where('user_id', $user->id)->lockForUpdate()->first();
  86. if ($existing && !$existing->trashed()) throw new \RuntimeException('该会员已在禁止推广列表');
  87. if ($existing) {
  88. $model = $existing;
  89. $model->restore();
  90. $before = [];
  91. } else {
  92. $model->user_id = $user->id;
  93. $model->member_id = (string)$user->member_id;
  94. }
  95. }
  96. $model->blocked_categories = array_values(array_unique($params['blocked_categories']));
  97. $model->status = (int)($params['status'] ?? ($model->status ?? 1));
  98. $model->fill(OperationAuditService::actor())->save();
  99. OperationAuditService::record('share_blacklist', (int)$model->id, $id ? 'update' : 'create', $before, $model);
  100. return $model->fresh();
  101. });
  102. });
  103. }
  104. public function blacklistStatus()
  105. {
  106. return $this->run(function () {
  107. $params = request()->validate(['id' => ['required', 'integer'], 'status' => ['required', Rule::in([0, 1])]]);
  108. return DB::transaction(function () use ($params) {
  109. $model = ShareBlacklist::query()->lockForUpdate()->findOrFail($params['id']);
  110. $before = $model->toArray();
  111. $model->fill(['status' => $params['status']] + OperationAuditService::actor())->save();
  112. OperationAuditService::record('share_blacklist', (int)$model->id, 'status', $before, $model);
  113. return $model->fresh();
  114. });
  115. });
  116. }
  117. public function deleteBlacklist()
  118. {
  119. return $this->run(function () {
  120. $params = request()->validate(['id' => ['required', 'integer']]);
  121. return DB::transaction(function () use ($params) {
  122. $model = ShareBlacklist::query()->lockForUpdate()->findOrFail($params['id']);
  123. $before = $model->toArray();
  124. $model->delete();
  125. OperationAuditService::record('share_blacklist', (int)$model->id, 'delete', $before, []);
  126. return [];
  127. });
  128. });
  129. }
  130. private function dateListRules(array $extra = []): array
  131. {
  132. return [
  133. 'page' => ['nullable', 'integer', 'min:1'],
  134. 'limit' => ['nullable', 'integer', 'min:1', 'max:200'],
  135. 'start_date' => ['nullable', 'date_format:Y-m-d'],
  136. 'end_date' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:start_date'],
  137. ] + $extra;
  138. }
  139. private function detailRules(): array
  140. {
  141. return [
  142. 'date' => ['required', 'date_format:Y-m-d'],
  143. 'page' => ['nullable', 'integer', 'min:1'],
  144. 'limit' => ['nullable', 'integer', 'min:1', 'max:200'],
  145. 'member_id' => ['nullable', 'string', 'max:64'],
  146. 'account' => ['nullable', 'string', 'max:100'],
  147. ];
  148. }
  149. private function report(callable $callback, array $rules)
  150. {
  151. return $this->run(fn () => $callback(request()->validate($rules)));
  152. }
  153. private function run(callable $callback)
  154. {
  155. try {
  156. return $this->success($callback());
  157. } catch (ValidationException $e) {
  158. return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first());
  159. } catch (QueryException $e) {
  160. Log::error('share_earning_database_error', ['exception' => $e]);
  161. return $this->error(HttpStatus::CUSTOM_ERROR, '分享服务暂不可用,请稍后重试');
  162. } catch (Throwable $e) {
  163. return $this->error(HttpStatus::CUSTOM_ERROR, $e->getMessage());
  164. }
  165. }
  166. }