POINT_TYPE::class, 'operate_type' => LOG_TYPE::class, ]; /** * 创建积分日志 * * @param int $userId 用户ID * @param int $pointId 积分类型ID * @param int $amount 积分数量(正数为收入,负数为支出) * @param LOG_TYPE $operateType 操作类型 * @param string $operateId 操作ID * @param string $remark 备注 * @param int $beforeBalance 操作前余额 * @param int $laterBalance 操作后余额 * @return PointLogModel|false 成功返回日志模型,失败返回false */ public static function createLog( int $userId, int $pointId, int $amount, LOG_TYPE $operateType, string $operateId, string $remark, int $beforeBalance, int $laterBalance ) { $log = new self(); $log->user_id = $userId; $log->point_id = $pointId; $log->amount = $amount; $log->operate_type = $operateType; $log->operate_id = $operateId; $log->remark = $remark; $log->before_balance = $beforeBalance; $log->later_balance = $laterBalance; $log->create_time = time(); $log->create_ip = request()->ip() ?? ''; $log->date_key = (int)date('Ym'); // 获取上一条记录的哈希值 $prevLog = self::where('user_id', $userId) ->where('point_id', $pointId) ->orderBy('id', 'desc') ->first(); $log->prev_hash = $prevLog ? $prevLog->hash : ''; // 生成当前记录的哈希值 $log->hash = self::generateHash($log); if ($log->save()) { return $log; } return false; } /** * 生成防篡改哈希值 * * @param PointLogModel $log 日志模型 * @return string 哈希值 */ private static function generateHash(PointLogModel $log): string { $data = [ $log->user_id, $log->point_id->value, $log->amount, $log->operate_type->value, $log->operate_id, $log->before_balance, $log->later_balance, $log->create_time, $log->prev_hash ]; return hash('sha256', implode('|', $data)); } /** * 验证日志记录的完整性 * * @return bool 是否完整 */ public function verifyIntegrity(): bool { $expectedHash = self::generateHash($this); return $this->hash === $expectedHash; } /** * 获取用户积分日志 * * @param int $userId 用户ID * @param int|null $pointId 积分类型ID(可选) * @param int $limit 限制数量 * @return \Illuminate\Database\Eloquent\Collection 日志集合 */ public static function getUserLogs(int $userId, ?int $pointId = null, int $limit = 50) { $query = self::where('user_id', $userId); if ($pointId !== null) { $query->where('point_id', $pointId); } return $query->orderBy('create_time', 'desc') ->limit($limit) ->get(); } /** * 获取用户指定时间范围的积分日志 * * @param int $userId 用户ID * @param int $startTime 开始时间 * @param int $endTime 结束时间 * @param int|null $pointId 积分类型ID(可选) * @return \Illuminate\Database\Eloquent\Collection 日志集合 */ public static function getUserLogsByTimeRange( int $userId, int $startTime, int $endTime, ?int $pointId = null ) { $query = self::where('user_id', $userId) ->whereBetween('create_time', [$startTime, $endTime]); if ($pointId !== null) { $query->where('point_id', $pointId); } return $query->orderBy('create_time', 'desc')->get(); } /** * 获取操作类型名称 * * @return string 操作类型名称 */ public function getOperateTypeName(): string { return $this->operate_type->getTypeName(); } /** * 判断是否为收入记录 * * @return bool 是否为收入 */ public function isIncome(): bool { return $this->amount > 0; } /** * 判断是否为支出记录 * * @return bool 是否为支出 */ public function isExpense(): bool { return $this->amount < 0; } /** * 获取积分类型名称 * * @return string 积分类型名称 */ public function getPointTypeName(): string { return $this->point_id->getTypeName(); } }