| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- <?php
- namespace App\Module\Point\Models;
- use App\Module\Point\Enums\POINT_TYPE;
- use App\Module\Point\Enums\LOG_TYPE;
- use UCore\ModelCore;
- /**
- * 积分日志表
- *
- * 记录用户积分的所有变更操作,包括增加、减少、转账等
- * 专注于整数积分处理,不涉及小数运算
- *
- * field start
- * @property int $id
- * @property int $user_id 用户ID
- * @property \App\Module\Point\Enums\POINT_TYPE $point_id 积分类型ID
- * @property int $amount 操作积分数量,正值为收入,负值为支出
- * @property string $operate_id 上游操作ID
- * @property \App\Module\Point\Enums\LOG_TYPE $operate_type 上游操作类型
- * @property string $remark 备注
- * @property int $create_time 创建时间
- * @property string $create_ip 创建IP
- * @property int $later_balance 操作后余额
- * @property int $before_balance 操作前余额
- * @property int $date_key 日期key(用于分表)
- * @property string $hash 防篡改哈希值
- * @property string $prev_hash 上一条记录的哈希值
- * field end
- */
- class PointLogModel extends ModelCore
- {
- protected $table = 'point_logs';
- // attrlist start
- protected $fillable = [
- 'id',
- 'user_id',
- 'point_id',
- 'amount',
- 'operate_id',
- 'operate_type',
- 'remark',
- 'create_time',
- 'create_ip',
- 'later_balance',
- 'before_balance',
- 'date_key',
- 'hash',
- 'prev_hash',
- ];
- // attrlist end
- public $timestamps = false;
- protected $casts = [
- 'point_id' => 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,
- $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();
- }
- }
|