diff --git a/server/.env.example b/server/.env.example index 0159bc2..01a0984 100644 --- a/server/.env.example +++ b/server/.env.example @@ -18,13 +18,13 @@ REDIS_DB = 0 # API 鉴权与用户(可选,不填则用默认值) # authToken 签名密钥(必填,与客户端约定,用于 signature 校验) - API_AUTH_TOKEN_SECRET = xF75oK91TQj13s0UmNIr1NBWMWGfflNO +API_AUTH_TOKEN_SECRET = xF75oK91TQj13s0UmNIr1NBWMWGfflNO # authToken 时间戳允许误差秒数,防重放,默认 300 - API_AUTH_TOKEN_TIME_TOLERANCE = 300 - API_AUTH_TOKEN_EXP = 86400 +API_AUTH_TOKEN_TIME_TOLERANCE = 300 +API_AUTH_TOKEN_EXP = 86400 # API_USER_TOKEN_EXP = 604800 - API_USER_CACHE_EXPIRE = 86400 - API_USER_ENCRYPT_KEY = Wj818SK8dhKBKNOY3PUTmZfhQDMCXEZi +API_USER_CACHE_EXPIRE = 86400 +API_USER_ENCRYPT_KEY = Wj818SK8dhKBKNOY3PUTmZfhQDMCXEZi # 验证码配置,支持cache|session CAPTCHA_MODE = cache diff --git a/server/app/api/logic/GameLogic.php b/server/app/api/logic/GameLogic.php index cbdc0ae..73423a0 100644 --- a/server/app/api/logic/GameLogic.php +++ b/server/app/api/logic/GameLogic.php @@ -27,7 +27,8 @@ class GameLogic /** * 购买抽奖券 - * @param int $playerId 玩家ID(即 user_id) + * 先更新 Redis 玩家信息(后续游玩从 Redis 读),再用事务更新数据库;事务失败则回滚 Redis + * @param int $playerId 玩家ID * @param int $count 购买档位:1 / 5 / 10 * @return array 更新后的 coin, total_ticket_count, paid_ticket_count, free_ticket_count */ @@ -55,59 +56,70 @@ class GameLogic $totalBefore = (int) ($player->total_ticket_count ?? 0); $paidBefore = (int) ($player->paid_ticket_count ?? 0); $freeBefore = (int) ($player->free_ticket_count ?? 0); + $totalAfter = $totalBefore + $addTotal; + $paidAfter = $paidBefore + $addPaid; + $freeAfter = $freeBefore + $addFree; - Db::transaction(function () use ( - $player, - $playerId, - $cost, - $coinBefore, - $coinAfter, - $addTotal, - $addPaid, - $addFree, - $totalBefore, - $paidBefore, - $freeBefore - ) { - $player->coin = $coinAfter; - $player->total_ticket_count = $totalBefore + $addTotal; - $player->paid_ticket_count = $paidBefore + $addPaid; - $player->free_ticket_count = $freeBefore + $addFree; - $player->save(); + $oldUserArr = $player->hidden(['password'])->toArray(); + $updatedUserArr = $oldUserArr; + $updatedUserArr['coin'] = $coinAfter; + $updatedUserArr['total_ticket_count'] = $totalAfter; + $updatedUserArr['paid_ticket_count'] = $paidAfter; + $updatedUserArr['free_ticket_count'] = $freeAfter; - // 钱包流水记录 - DicePlayerWalletRecord::create([ - 'player_id' => $playerId, - 'coin' => -$cost, - 'type' => self::WALLET_TYPE_BUY_DRAW, - 'wallet_before' => $coinBefore, - 'wallet_after' => $coinAfter, - 'total_ticket_count' => $addTotal, - 'paid_ticket_count' => $addPaid, - 'free_ticket_count' => $addFree, - 'remark' => "购买抽奖券{$addTotal}次(付费{$addPaid}次+赠送{$addFree}次)", - ]); + UserCache::setUser($playerId, $updatedUserArr); - // 抽奖券获取记录 - DicePlayerTicketRecord::create([ - 'player_id' => $playerId, - 'use_coins' => $cost, - 'total_ticket_count' => $addTotal, - 'paid_ticket_count' => $addPaid, - 'free_ticket_count' => $addFree, - 'remark' => "购买抽奖券{$addTotal}次(付费{$addPaid}次+赠送{$addFree}次)", - ]); - }); + try { + Db::transaction(function () use ( + $player, + $playerId, + $cost, + $coinBefore, + $coinAfter, + $addTotal, + $addPaid, + $addFree, + $totalAfter, + $paidAfter, + $freeAfter + ) { + $player->coin = $coinAfter; + $player->total_ticket_count = $totalAfter; + $player->paid_ticket_count = $paidAfter; + $player->free_ticket_count = $freeAfter; + $player->save(); - $updated = DicePlayer::find($playerId); - $userArr = $updated->hidden(['password'])->toArray(); - UserCache::setUser($playerId, $userArr); + DicePlayerWalletRecord::create([ + 'player_id' => $playerId, + 'coin' => -$cost, + 'type' => self::WALLET_TYPE_BUY_DRAW, + 'wallet_before' => $coinBefore, + 'wallet_after' => $coinAfter, + 'total_ticket_count' => $addTotal, + 'paid_ticket_count' => $addPaid, + 'free_ticket_count' => $addFree, + 'remark' => "购买抽奖券{$addTotal}次(付费{$addPaid}次+赠送{$addFree}次)", + ]); + + DicePlayerTicketRecord::create([ + 'player_id' => $playerId, + 'use_coins' => $cost, + 'total_ticket_count' => $addTotal, + 'paid_ticket_count' => $addPaid, + 'free_ticket_count' => $addFree, + 'remark' => "购买抽奖券{$addTotal}次(付费{$addPaid}次+赠送{$addFree}次)", + ]); + }); + } catch (\Throwable $e) { + UserCache::setUser($playerId, $oldUserArr); + throw $e; + } return [ - 'coin' => (float) $updated->coin, - 'total_ticket_count' => (int) $updated->total_ticket_count, - 'paid_ticket_count' => (int) $updated->paid_ticket_count, - 'free_ticket_count' => (int) $updated->free_ticket_count, + 'coin' => (float) $coinAfter, + 'total_ticket_count' => (int) $totalAfter, + 'paid_ticket_count' => (int) $paidAfter, + 'free_ticket_count' => (int) $freeAfter, ]; } } diff --git a/server/app/dice/model/player/DicePlayer.php b/server/app/dice/model/player/DicePlayer.php index 3ff00c3..5464c76 100644 --- a/server/app/dice/model/player/DicePlayer.php +++ b/server/app/dice/model/player/DicePlayer.php @@ -49,6 +49,11 @@ class DicePlayer extends BaseModel */ protected $table = 'dice_player'; + /** 创建时间字段(dice_player 表为 created_at) */ + protected $createTime = 'created_at'; + /** 更新时间字段(dice_player 表为 updated_at) */ + protected $updateTime = 'updated_at'; + /** * 新增前:生成唯一 uid,昵称 name 默认使用 uid * 用 try-catch 避免表尚未含 uid 时 getAttr/getData 抛 InvalidArgumentException diff --git a/server/plugin/saiadmin/basic/think/BaseModel.php b/server/plugin/saiadmin/basic/think/BaseModel.php index b3cc4d5..4b46dfc 100644 --- a/server/plugin/saiadmin/basic/think/BaseModel.php +++ b/server/plugin/saiadmin/basic/think/BaseModel.php @@ -35,6 +35,12 @@ class BaseModel extends Model implements ModelInterface */ protected $updateTime = 'update_time'; + /** + * 自动写入时间戳(创建时写 create_time,更新时写 update_time) + * @var bool + */ + protected $autoWriteTimestamp = true; + /** * 隐藏字段 * @var array @@ -94,24 +100,48 @@ class BaseModel extends Model implements ModelInterface } /** - * 新增前事件 + * 新增前事件:自动写入 create_time,有后台登录信息时写入 created_by * @param Model $model * @return void */ public static function onBeforeInsert($model): void { - $info = getCurrentInfo(); - $info && $model->setAttr('created_by', $info['id']); + $createTime = $model->createTime ?? 'create_time'; + if ($createTime && !$model->getData($createTime)) { + $model->set($createTime, date('Y-m-d H:i:s')); + } + if (function_exists('getCurrentInfo')) { + $info = getCurrentInfo(); + if (!empty($info['id'])) { + try { + $model->setAttr('created_by', $info['id']); + } catch (\Throwable $e) { + } + } + } } /** - * 写入前事件 + * 写入前事件:更新时自动写入 update_time,有后台登录信息时写入 updated_by * @param Model $model * @return void */ public static function onBeforeWrite($model): void { - $info = getCurrentInfo(); - $info && $model->setAttr('updated_by', $info['id']); + if ($model->isUpdate()) { + $updateTime = $model->updateTime ?? 'update_time'; + if ($updateTime) { + $model->set($updateTime, date('Y-m-d H:i:s')); + } + } + if (function_exists('getCurrentInfo')) { + $info = getCurrentInfo(); + if (!empty($info['id'])) { + try { + $model->setAttr('updated_by', $info['id']); + } catch (\Throwable $e) { + } + } + } } }