validate([ 'page' => ['nullable', 'integer', 'min:1'], 'limit' => ['nullable', 'integer', 'min:1'], 'id' => ['nullable', 'integer', 'min:1'], 'user_id' => ['nullable'], 'member_id' => ['nullable'], 'account' => ['nullable', 'string', 'max:64'], 'first_name' => ['nullable'], 'start_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:end_time'], 'end_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:start_time'], ]); $page = request()->input('page', 1); $limit = request()->input('limit', 15); $query = YuebaoItem::join('users', 'users.user_id', '=', 'yuebao_item.user_id') ->select("yuebao_item.*", "users.first_name", "users.member_id", "users.account", "users.admin_note as user_admin_note"); \App\Support\MemberAudience::visibleUsers($query, 'users'); // 后台模拟会员只在模拟管理里出现 if (!empty($params['id'])) { $query = $query->where('yuebao_item.id', $params['id']); } if (!empty($params['user_id'])) { $query = $query->where('yuebao_item.user_id', $params['user_id']); } if (!empty($params['member_id'])) { $query = $query->where('yuebao_item.user_id', $params['member_id']); } if (!empty($params['start_time'])) { $startTime = strtotime($params['start_time'] . " 00:00:00"); $query = $query->where('yuebao_item.create_time', '>=', $startTime); } if (!empty($params['end_time'])) { $endTime = strtotime($params['end_time'] . " 23:59:59"); $query = $query->where('yuebao_item.create_time', '<=', $endTime); } if (!empty($params['account'])) { $query = $query->where('users.account', 'like', '%' . trim((string)$params['account']) . '%'); } if (isset($params['first_name']) && !empty($params['first_name'])) { $query = $query->where('users.first_name', 'like', "%" . $params['first_name'] . "%"); } $count = $query->count(); $list = $query ->forPage($page, $limit) ->orderByDesc('yuebao_item.create_time') ->get(); } catch (Exception $e) { return $this->error(HttpStatus::CUSTOM_ERROR,$e->getMessage()); } return $this->success(['total' => $count, 'data' => $list]); } /** * 余额宝日志列表 */ public function log() { try { $params = request()->validate([ 'page' => ['nullable', 'integer', 'min:1'], 'limit' => ['nullable', 'integer', 'min:1'], 'id' => ['nullable', 'integer', 'min:1'], 'item_id' => ['nullable', 'integer', 'min:1'], 'user_id' => ['nullable'], 'type' => ['nullable', 'integer'], 'start_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:end_time'], 'end_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:start_time'], ]); $page = request()->input('page', 1); $limit = request()->input('limit', 15); $query = new YuebaoLog(); if (!empty($params['id'])) { $query = $query->where('id', $params['id']); } if (!empty($params['item_id'])) { $query = $query->where('item_id', $params['item_id']); } if (!empty($params['user_id'])) { $query = $query->where('user_id', $params['user_id']); } if (!empty($params['type'])) { $query = $query->where('type', $params['type']); } if (!empty($params['start_time'])) { $startTime = strtotime($params['start_time'] . " 00:00:00"); $query = $query->where('create_time', '>=', $startTime); } if (!empty($params['end_time'])) { $endTime = strtotime($params['end_time'] . " 23:59:59"); $query = $query->where('create_time', '<=', $endTime); } $count = $query->count(); $list = $query ->forPage($page, $limit) ->orderByDesc('create_time') ->get(); } catch (Exception $e) { return $this->error(HttpStatus::CUSTOM_ERROR,$e->getMessage()); } return $this->success(['total' => $count, 'data' => $list]); } /** 余额宝配置固定为一条 type=6 活动行;与会员端选取顺序一致取排序最高、ID 最大的一条。 */ private static function configRow(): ?ActivityReward { return ActivityReward::where('type', ActivityCatalog::YUEBAO_TYPE) ->orderByDesc('sort')->orderByDesc('id')->first(); } /** * 余额宝配置详情 */ public function config(): JsonResponse { $row = self::configRow(); if (!$row) { return $this->success(null); } $data = $row->toArray(); $params = json_decode((string)$row->getRawOriginal('params'), true) ?: []; $data['daily_interest_rate'] = $params['daily_interest_rate'] ?? null; $data['number_of_consecutive_days_of_deposit'] = $params['number_of_consecutive_days_of_deposit'] ?? null; // 活动类型、游戏分类、点击行为、排序不属于余额宝配置。 unset($data['params'], $data['type'], $data['type_name'], $data['game_category'], $data['game_category_name'], $data['click_type'], $data['link'], $data['link_pc'], $data['link_h5'], $data['click_position'], $data['can_jump'], $data['sort']); return $this->success($data); } /** * 保存余额宝配置(无则新建) */ public function saveConfig(): JsonResponse { DB::beginTransaction(); try { $params = request()->validate([ 'title' => ['required', 'string', 'min:1', 'max:140'], 'sub_title' => ['required', 'string', 'min:1', 'max:140'], 'start_time' => ['nullable', 'required_with:end_time', 'date'], 'end_time' => ['nullable', 'required_with:start_time', 'date', 'after_or_equal:start_time'], 'detail_image' => ['required'], 'pc_image' => ['required'], 'status' => ['required', 'integer', 'in:0,1'], 'lang' => ['required', 'string'], 'content' => ['nullable', 'string'], 'daily_interest_rate' => ['required', 'numeric', 'min:0', 'max:100'], 'number_of_consecutive_days_of_deposit' => ['required', 'integer', 'min:1', 'max:3650'], ], [ 'start_time.required_with' => '活动开始和结束时间必须同时填写或同时留空', 'end_time.required_with' => '活动开始和结束时间必须同时填写或同时留空', 'daily_interest_rate.required' => '请填写日化率', 'number_of_consecutive_days_of_deposit.required' => '请填写连续存款天数', ]); $row = self::configRow(); $stored = $row ? (json_decode((string)$row->getRawOriginal('params'), true) ?: []) : []; $stored['daily_interest_rate'] = (string)$params['daily_interest_rate']; $stored['number_of_consecutive_days_of_deposit'] = (int)$params['number_of_consecutive_days_of_deposit']; unset($params['daily_interest_rate'], $params['number_of_consecutive_days_of_deposit']); $defaults = ActivityRewardService::configurationDefaults(); unset($defaults['sort']); $params = array_merge($params, array_intersect_key(request()->all(), $defaults + ['budget' => true])); $params['type'] = ActivityCatalog::YUEBAO_TYPE; $params['params'] = json_encode($stored); if ($row) { $params['id'] = $row->id; } ActivityRewardService::submit($params); DB::commit(); } catch (ValidationException $e) { DB::rollBack(); return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first()); } catch (Exception $e) { DB::rollBack(); return $this->error($e->getCode() ?: HttpStatus::CUSTOM_ERROR, $e->getMessage()); } return $this->success(); } }