修改缓存方式
This commit is contained in:
@@ -7,6 +7,7 @@ use ba\Random;
|
||||
use support\think\Db;
|
||||
use app\common\model\User;
|
||||
use app\common\facade\Token;
|
||||
use app\common\service\GameHotDataRedis;
|
||||
use Webman\Http\Request;
|
||||
|
||||
/**
|
||||
@@ -69,7 +70,7 @@ class Auth extends \ba\Auth
|
||||
Token::tokenExpirationCheck($tokenData);
|
||||
$userId = $tokenData['user_id'];
|
||||
if ($tokenData['type'] == self::TOKEN_TYPE && $userId > 0) {
|
||||
$this->model = User::where('id', $userId)->find();
|
||||
$this->model = GameHotDataRedis::userModelFromCacheOrDb($userId);
|
||||
if (!$this->model) {
|
||||
$this->setError('Account not exist');
|
||||
return false;
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace app\common\library\finance;
|
||||
|
||||
use support\think\Db;
|
||||
use app\common\service\GameHotDataRedis;
|
||||
|
||||
/**
|
||||
* 提现打码量(流水)门槛工具库
|
||||
@@ -38,7 +38,7 @@ final class WithdrawFlow
|
||||
*/
|
||||
public static function ratio(): string
|
||||
{
|
||||
$row = Db::name('game_config')->where('config_key', self::CONFIG_KEY)->find();
|
||||
$row = GameHotDataRedis::gameConfigRow(self::CONFIG_KEY);
|
||||
if (!$row) {
|
||||
return self::DEFAULT_RATIO;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace app\common\library\game;
|
||||
|
||||
use support\think\Db;
|
||||
use app\common\service\GameHotDataRedis;
|
||||
|
||||
/**
|
||||
* 连胜奖励(game_config.streak_win_reward):按「连胜档位」1~10 配置赔率系数与是否大奖。
|
||||
@@ -100,7 +100,7 @@ final class StreakWinReward
|
||||
if (self::$cache !== null) {
|
||||
return self::$cache;
|
||||
}
|
||||
$row = Db::name('game_config')->where('config_key', self::CONFIG_KEY)->find();
|
||||
$row = GameHotDataRedis::gameConfigRow(self::CONFIG_KEY);
|
||||
self::$cache = self::parseFromConfigValue($row['config_value'] ?? null);
|
||||
|
||||
return self::$cache;
|
||||
|
||||
@@ -23,33 +23,87 @@ class LoadLangPack implements MiddlewareInterface
|
||||
return $handler($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析当前请求语言。
|
||||
* - 后台 admin:优先请求头 think-lang(zh-cn / en),其次 lang 头,再次查询/表单参数 lang(支持 zh→zh-cn)。
|
||||
* - 对外 api:优先查询/表单参数 lang(zh / en),其次 lang 头,再次 think-lang。
|
||||
*/
|
||||
protected function resolveLangSet(Request $request): string
|
||||
{
|
||||
$path = trim($request->path(), '/');
|
||||
$parts = explode('/', $path);
|
||||
$app = $parts[0] ?? 'api';
|
||||
|
||||
$queryRaw = $request->get('lang');
|
||||
if ($queryRaw === null || $queryRaw === '') {
|
||||
$queryRaw = $request->post('lang');
|
||||
}
|
||||
$queryLang = is_string($queryRaw) ? $queryRaw : '';
|
||||
|
||||
$thinkRaw = $request->header('think-lang');
|
||||
$thinkLang = is_string($thinkRaw) ? $thinkRaw : '';
|
||||
|
||||
$headerLangRaw = $request->header('lang');
|
||||
$headerLang = is_string($headerLangRaw) ? $headerLangRaw : '';
|
||||
|
||||
$normalize = static function (string $raw): string {
|
||||
$s = str_replace('_', '-', strtolower(trim($raw)));
|
||||
if ($s === 'zh') {
|
||||
return 'zh-cn';
|
||||
}
|
||||
|
||||
return $s;
|
||||
};
|
||||
|
||||
$allowLangList = config('lang.allow_lang_list', ['zh-cn', 'en']);
|
||||
|
||||
$candidates = [];
|
||||
if ($app === 'admin') {
|
||||
if ($thinkLang !== '') {
|
||||
$candidates[] = $normalize($thinkLang);
|
||||
}
|
||||
if ($headerLang !== '') {
|
||||
$candidates[] = $normalize($headerLang);
|
||||
}
|
||||
if ($queryLang !== '') {
|
||||
$candidates[] = $normalize($queryLang);
|
||||
}
|
||||
} else {
|
||||
if ($queryLang !== '') {
|
||||
$candidates[] = $normalize($queryLang);
|
||||
}
|
||||
if ($headerLang !== '') {
|
||||
$candidates[] = $normalize($headerLang);
|
||||
}
|
||||
if ($thinkLang !== '') {
|
||||
$candidates[] = $normalize($thinkLang);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($candidates as $code) {
|
||||
if ($code !== '' && in_array($code, $allowLangList, true)) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
$acceptRaw = $request->header('accept-language');
|
||||
$acceptLang = is_string($acceptRaw) ? $acceptRaw : '';
|
||||
if (preg_match('/^zh[-_]?cn|^zh/i', $acceptLang)) {
|
||||
return 'zh-cn';
|
||||
}
|
||||
if (preg_match('/^en/i', $acceptLang)) {
|
||||
return 'en';
|
||||
}
|
||||
|
||||
$defaultRaw = config('lang.default_lang', config('translation.locale', 'zh-cn'));
|
||||
$default = is_string($defaultRaw) ? $defaultRaw : 'zh-cn';
|
||||
|
||||
return str_replace('_', '-', strtolower($default));
|
||||
}
|
||||
|
||||
protected function loadLang(Request $request): void
|
||||
{
|
||||
// 优先从请求头 lang / think-lang 获取前端选择的语言
|
||||
// 支持:lang=en / lang=zh / think-lang=en / think-lang=zh-cn
|
||||
// 未发送时回退到 Accept-Language 或配置默认值
|
||||
$headerLang = $request->header('lang', '');
|
||||
if ($headerLang === '') {
|
||||
$headerLang = $request->header('think-lang', '');
|
||||
}
|
||||
$allowLangList = config('lang.allow_lang_list', ['zh-cn', 'en']);
|
||||
$normalizedHeaderLang = str_replace('_', '-', strtolower($headerLang));
|
||||
if ($normalizedHeaderLang === 'zh') {
|
||||
$normalizedHeaderLang = 'zh-cn';
|
||||
}
|
||||
if ($headerLang && in_array($normalizedHeaderLang, $allowLangList)) {
|
||||
$langSet = $normalizedHeaderLang;
|
||||
} else {
|
||||
$acceptLang = $request->header('accept-language', '');
|
||||
if (preg_match('/^zh[-_]?cn|^zh/i', $acceptLang)) {
|
||||
$langSet = 'zh-cn';
|
||||
} elseif (preg_match('/^en/i', $acceptLang)) {
|
||||
$langSet = 'en';
|
||||
} else {
|
||||
$langSet = config('lang.default_lang', config('translation.locale', 'zh-cn'));
|
||||
}
|
||||
$langSet = str_replace('_', '-', strtolower($langSet));
|
||||
}
|
||||
$langSet = $this->resolveLangSet($request);
|
||||
|
||||
// 设置当前请求的翻译语言,使 __() 和 trans() 使用正确的语言
|
||||
if (function_exists('locale')) {
|
||||
@@ -74,6 +128,12 @@ class LoadLangPack implements MiddlewareInterface
|
||||
$translator->addResource('phpfile', $rootLangFile, $langSet, 'messages');
|
||||
}
|
||||
|
||||
// 1.5 公共语言包(app/common/lang/{locale}/*.php),供 common 服务层与多应用共用
|
||||
$commonLangPattern = base_path() . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $langSet . DIRECTORY_SEPARATOR . '*.php';
|
||||
foreach (glob($commonLangPattern) ?: [] as $commonLangFile) {
|
||||
$translator->addResource('phpfile', $commonLangFile, $langSet, 'messages');
|
||||
}
|
||||
|
||||
// 2. 加载控制器专用语言包(如 zh-cn/auth/group.php),供 get_route_remark 等使用
|
||||
// 同时加载到 messages 域,使 __() 能正确翻译控制器内的文案(如安装页错误提示)
|
||||
$controllerPath = get_controller_path($request);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use app\common\library\game\StreakWinReward;
|
||||
use app\common\service\GameHotDataRedis;
|
||||
use support\think\Model;
|
||||
|
||||
/**
|
||||
@@ -17,4 +19,26 @@ class GameConfig extends Model
|
||||
'create_time' => 'integer',
|
||||
'update_time' => 'integer',
|
||||
];
|
||||
|
||||
public static function onAfterWrite(GameConfig $model): void
|
||||
{
|
||||
$key = trim((string) ($model->getAttr('config_key') ?? ''));
|
||||
if ($key !== '') {
|
||||
GameHotDataRedis::gameConfigForget($key);
|
||||
}
|
||||
if ($key === StreakWinReward::CONFIG_KEY) {
|
||||
StreakWinReward::clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
public static function onAfterDelete(GameConfig $model): void
|
||||
{
|
||||
$key = trim((string) ($model->getAttr('config_key') ?? ''));
|
||||
if ($key !== '') {
|
||||
GameHotDataRedis::gameConfigForget($key);
|
||||
}
|
||||
if ($key === StreakWinReward::CONFIG_KEY) {
|
||||
StreakWinReward::clearCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use app\common\service\GameHotDataRedis;
|
||||
use support\think\Model;
|
||||
|
||||
class GameRecord extends Model
|
||||
@@ -41,4 +42,16 @@ class GameRecord extends Model
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function onAfterWrite(GameRecord $model): void
|
||||
{
|
||||
$id = filter_var($model->getAttr('id'), FILTER_VALIDATE_INT);
|
||||
GameHotDataRedis::gameRecordForget($id === false ? null : $id);
|
||||
}
|
||||
|
||||
public static function onAfterDelete(GameRecord $model): void
|
||||
{
|
||||
$id = filter_var($model->getAttr('id'), FILTER_VALIDATE_INT);
|
||||
GameHotDataRedis::gameRecordForget($id === false ? null : $id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use app\common\service\GameHotDataRedis;
|
||||
use support\think\Model;
|
||||
|
||||
/**
|
||||
@@ -62,4 +63,20 @@ class User extends Model
|
||||
{
|
||||
return $this->where(['id' => $uid])->update(['password' => hash_password($newPassword)]);
|
||||
}
|
||||
|
||||
public static function onAfterWrite(User $model): void
|
||||
{
|
||||
$id = filter_var($model->getAttr('id'), FILTER_VALIDATE_INT);
|
||||
if ($id !== false && $id > 0) {
|
||||
GameHotDataRedis::userForget($id);
|
||||
}
|
||||
}
|
||||
|
||||
public static function onAfterDelete(User $model): void
|
||||
{
|
||||
$id = filter_var($model->getAttr('id'), FILTER_VALIDATE_INT);
|
||||
if ($id !== false && $id > 0) {
|
||||
GameHotDataRedis::userForget($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ final class GameBetSettleService
|
||||
'current_streak' => $next,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::userForget($userId);
|
||||
}
|
||||
|
||||
foreach ($aggregateByUser as $userId => $agg) {
|
||||
@@ -272,6 +273,7 @@ final class GameBetSettleService
|
||||
'bet_flow_coin' => Db::raw('bet_flow_coin + ' . $flow),
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::userForget($userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,6 +321,7 @@ final class GameBetSettleService
|
||||
'coin' => $after,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::userForget($userId);
|
||||
|
||||
return $after;
|
||||
}
|
||||
|
||||
279
app/common/service/GameHotDataRedis.php
Normal file
279
app/common/service/GameHotDataRedis.php
Normal file
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\User;
|
||||
use support\Redis;
|
||||
use support\think\Db;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 热点数据 Redis 缓存:game_config、game_record、user 全行 JSON。
|
||||
* Redis 不可用时自动回退为直连数据库。
|
||||
*/
|
||||
final class GameHotDataRedis
|
||||
{
|
||||
private const KEY_GC = 'dfw:v1:gc:';
|
||||
|
||||
private const KEY_GR_ID = 'dfw:v1:gr:id:';
|
||||
|
||||
private const KEY_GR_ACTIVE = 'dfw:v1:gr:active';
|
||||
|
||||
private const KEY_GR_LATEST = 'dfw:v1:gr:latest';
|
||||
|
||||
private const KEY_USER = 'dfw:v1:user:';
|
||||
|
||||
public static function enabled(): bool
|
||||
{
|
||||
return config('game_hot_cache.enabled', true) === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public static function gameConfigRow(string $configKey): ?array
|
||||
{
|
||||
if ($configKey === '') {
|
||||
return null;
|
||||
}
|
||||
if (self::enabled()) {
|
||||
$cached = self::redisGet(self::KEY_GC . $configKey);
|
||||
if ($cached !== null && $cached !== '') {
|
||||
$decoded = json_decode($cached, true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
$row = Db::name('game_config')->where('config_key', $configKey)->find();
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
if (self::enabled()) {
|
||||
$ttl = self::intConfig('ttl_game_config', 86400);
|
||||
self::redisSetEx(self::KEY_GC . $configKey, $ttl, json_encode($row, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
public static function gameConfigForget(string $configKey): void
|
||||
{
|
||||
if ($configKey === '') {
|
||||
return;
|
||||
}
|
||||
self::redisDel(self::KEY_GC . $configKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public static function gameRecordById(int $id): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return null;
|
||||
}
|
||||
$key = self::KEY_GR_ID . $id;
|
||||
if (self::enabled()) {
|
||||
$cached = self::redisGet($key);
|
||||
if ($cached !== null && $cached !== '') {
|
||||
$decoded = json_decode($cached, true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
$row = Db::name('game_record')->where('id', $id)->find();
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
if (self::enabled()) {
|
||||
$ttl = self::intConfig('ttl_game_record', 60);
|
||||
self::redisSetEx($key, $ttl, json_encode($row, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前未完全结束的对局(status ∈ 0,1,2,3 中 id 最大的一条)
|
||||
*
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public static function gameRecordActive(): ?array
|
||||
{
|
||||
if (self::enabled()) {
|
||||
$cached = self::redisGet(self::KEY_GR_ACTIVE);
|
||||
if ($cached !== null && $cached !== '') {
|
||||
$decoded = json_decode($cached, true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
$row = Db::name('game_record')->whereIn('status', [0, 1, 2, 3])->order('id', 'desc')->find();
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
if (self::enabled()) {
|
||||
$ttl = self::intConfig('ttl_game_record', 60);
|
||||
self::redisSetEx(self::KEY_GR_ACTIVE, $ttl, json_encode($row, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* 最新一条对局(含已结束),与 GameRecord::order('id','desc')->find() 一致
|
||||
*
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public static function gameRecordLatest(): ?array
|
||||
{
|
||||
if (self::enabled()) {
|
||||
$cached = self::redisGet(self::KEY_GR_LATEST);
|
||||
if ($cached !== null && $cached !== '') {
|
||||
$decoded = json_decode($cached, true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
$row = Db::name('game_record')->order('id', 'desc')->find();
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
if (self::enabled()) {
|
||||
$ttl = self::intConfig('ttl_game_record', 60);
|
||||
self::redisSetEx(self::KEY_GR_LATEST, $ttl, json_encode($row, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任意 game_record 变更后调用:删除活跃局、最新局及指定 id 缓存
|
||||
*/
|
||||
public static function gameRecordForget(?int $id = null): void
|
||||
{
|
||||
$keys = [self::KEY_GR_ACTIVE, self::KEY_GR_LATEST];
|
||||
if ($id !== null && $id > 0) {
|
||||
$keys[] = self::KEY_GR_ID . $id;
|
||||
}
|
||||
self::redisDel(...$keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public static function userRow(int $userId): ?array
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return null;
|
||||
}
|
||||
$key = self::KEY_USER . $userId;
|
||||
if (self::enabled()) {
|
||||
$cached = self::redisGet($key);
|
||||
if ($cached !== null && $cached !== '') {
|
||||
$decoded = json_decode($cached, true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
$row = Db::name('user')->where('id', $userId)->find();
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
if (self::enabled()) {
|
||||
$ttl = self::intConfig('ttl_user', 90);
|
||||
self::redisSetEx($key, $ttl, json_encode($row, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
public static function userRemember(User $user): void
|
||||
{
|
||||
if (!self::enabled()) {
|
||||
return;
|
||||
}
|
||||
$id = $user->getAttr('id');
|
||||
$uid = filter_var($id, FILTER_VALIDATE_INT);
|
||||
if ($uid === false || $uid <= 0) {
|
||||
return;
|
||||
}
|
||||
$ttl = self::intConfig('ttl_user', 90);
|
||||
self::redisSetEx(self::KEY_USER . $uid, $ttl, json_encode($user->toArray(), JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
public static function userForget(int $userId): void
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
self::redisDel(self::KEY_USER . $userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用缓存行构造已存在库的 User(供 Auth 等高频读)
|
||||
*/
|
||||
public static function userModelFromCacheOrDb(int $userId): ?User
|
||||
{
|
||||
$row = self::userRow($userId);
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
return (new User())->newInstance($row);
|
||||
}
|
||||
|
||||
private static function intConfig(string $name, int $default): int
|
||||
{
|
||||
$v = config('game_hot_cache.' . $name, $default);
|
||||
if (is_int($v)) {
|
||||
return $v > 0 ? $v : $default;
|
||||
}
|
||||
if (is_numeric($v)) {
|
||||
$n = filter_var($v, FILTER_VALIDATE_INT);
|
||||
if ($n === false) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $n > 0 ? $n : $default;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
private static function redisGet(string $key): ?string
|
||||
{
|
||||
try {
|
||||
$v = Redis::get($key);
|
||||
if ($v === false || $v === null) {
|
||||
return null;
|
||||
}
|
||||
if (!is_string($v)) {
|
||||
return null;
|
||||
}
|
||||
return $v;
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static function redisSetEx(string $key, int $ttl, string $value): void
|
||||
{
|
||||
try {
|
||||
Redis::setEx($key, $ttl, $value);
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
private static function redisDel(string ...$keys): void
|
||||
{
|
||||
if ($keys === []) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Redis::del(...$keys);
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ final class GameRecordService
|
||||
|
||||
public static function getConfigBool(string $key): bool
|
||||
{
|
||||
$row = Db::name('game_config')->where('config_key', $key)->find();
|
||||
$row = GameHotDataRedis::gameConfigRow($key);
|
||||
if (!$row) {
|
||||
return false;
|
||||
}
|
||||
@@ -99,6 +99,7 @@ final class GameRecordService
|
||||
'create_time' => $now,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::gameRecordForget();
|
||||
return $periodNo;
|
||||
}
|
||||
|
||||
@@ -122,6 +123,7 @@ final class GameRecordService
|
||||
'remark' => $remark,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::gameConfigForget($key);
|
||||
return;
|
||||
}
|
||||
Db::name('game_config')->insert([
|
||||
@@ -132,5 +134,6 @@ final class GameRecordService
|
||||
'create_time' => $now,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::gameConfigForget($key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ final class GameRecordStatService
|
||||
'winner_user_count' => 0,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::gameRecordForget($recordId);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -78,6 +79,7 @@ final class GameRecordStatService
|
||||
'winner_user_count' => count($winnerUserIds),
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameHotDataRedis::gameRecordForget($recordId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user