diff --git a/.env-example b/.env-example index 935c9f9..99eddb2 100644 --- a/.env-example +++ b/.env-example @@ -18,7 +18,7 @@ DATABASE_CHARSET = utf8mb4 DATABASE_PREFIX = # PlayX 配置 -# 以下三项比例以数据库表 mall_config 为准(后台 积分商城 → 商城参数配置);未迁移或无记录时回退为下列 env 默认值 +# 以下三项比例以数据库表 mall_business_config 为准(后台 积分商城 → 商城参数配置);无记录时回退为下列 env 默认值 # 提现折算:积分 -> 现金(如 10 分 = 1 元,则 points_to_cash_ratio=0.1) PLAYX_POINTS_TO_CASH_RATIO=0.1 # 返还比例:新增保障金 = ABS(yesterday_win_loss_net) * return_ratio(仅亏损时) diff --git a/app/admin/controller/mall/PlayxConfig.php b/app/admin/controller/mall/PlayxConfig.php index 6e09fea..9aaa8fa 100644 --- a/app/admin/controller/mall/PlayxConfig.php +++ b/app/admin/controller/mall/PlayxConfig.php @@ -6,12 +6,12 @@ namespace app\admin\controller\mall; use app\common\controller\Backend; use app\common\library\MallPlayxRatios; -use app\common\model\MallConfig; +use app\common\model\MallBusinessConfig; use support\Response; use Webman\Http\Request; /** - * 积分商城参数(PlayX 比例等) + * 积分商城参数(PlayX 比例等,读写 mall_business_config) */ class PlayxConfig extends Backend { @@ -22,17 +22,21 @@ class PlayxConfig extends Backend return $response; } - $row = MallConfig::order('id', 'asc')->find(); + $row = MallBusinessConfig::order('id', 'asc')->find(); if (!$row) { $now = time(); - MallConfig::create([ + MallBusinessConfig::create([ 'return_ratio' => floatval(env('PLAYX_RETURN_RATIO', '0.1')), 'unlock_ratio' => floatval(env('PLAYX_UNLOCK_RATIO', '0.1')), 'points_to_cash_ratio' => floatval(env('PLAYX_POINTS_TO_CASH_RATIO', '0.1')), 'create_time' => $now, 'update_time' => $now, ]); - $row = MallConfig::order('id', 'asc')->find(); + $row = MallBusinessConfig::order('id', 'asc')->find(); + } + + if ($row) { + MallPlayxRatios::syncFromRow($row); } return $this->success('', [ @@ -67,10 +71,10 @@ class PlayxConfig extends Backend return $this->error(__('Parameter error')); } - $row = MallConfig::order('id', 'asc')->find(); + $row = MallBusinessConfig::order('id', 'asc')->find(); if (!$row) { $now = time(); - MallConfig::create([ + MallBusinessConfig::create([ 'return_ratio' => $returnF, 'unlock_ratio' => $unlockF, 'points_to_cash_ratio' => $cashF, @@ -84,7 +88,10 @@ class PlayxConfig extends Backend $row->save(); } - MallPlayxRatios::forget(); + $fresh = MallBusinessConfig::order('id', 'asc')->find(); + if ($fresh) { + MallPlayxRatios::syncFromRow($fresh); + } return $this->success(__('The current page configuration item was updated successfully')); } diff --git a/app/common/library/MallPlayxRatios.php b/app/common/library/MallPlayxRatios.php index a70787b..1598ef0 100644 --- a/app/common/library/MallPlayxRatios.php +++ b/app/common/library/MallPlayxRatios.php @@ -4,47 +4,148 @@ declare(strict_types=1); namespace app\common\library; -use app\common\model\MallConfig; +use app\common\model\MallBusinessConfig; +use support\Redis as RedisSupport; +use Throwable; /** - * PlayX 与积分商城相关的比例配置:优先读 mall_config,无表记录时回退 .env + * PlayX 与积分商城相关的比例配置:优先读 Redis,未命中则读 mall_business_config 并回写 Redis;无表记录时回退 .env 并写入 Redis。 */ final class MallPlayxRatios { - private static ?array $cache = null; + public const REDIS_KEY = 'mall:business_config:playx_ratios'; /** * @return array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float} */ public static function get(): array { - if (self::$cache !== null) { - return self::$cache; + $conn = self::redisConnection(); + if ($conn !== null) { + $cached = self::readFromRedis($conn); + if ($cached !== null) { + return $cached; + } } - $row = MallConfig::order('id', 'asc')->find(); - if ($row) { - self::$cache = [ - 'return_ratio' => self::toFloat($row->return_ratio), - 'unlock_ratio' => self::toFloat($row->unlock_ratio), - 'points_to_cash_ratio' => self::toFloat($row->points_to_cash_ratio), - ]; + return self::loadFromDatabaseAndWriteRedis($conn); + } - return self::$cache; - } - - self::$cache = [ - 'return_ratio' => floatval(env('PLAYX_RETURN_RATIO', '0.1')), - 'unlock_ratio' => floatval(env('PLAYX_UNLOCK_RATIO', '0.1')), - 'points_to_cash_ratio' => floatval(env('PLAYX_POINTS_TO_CASH_RATIO', '0.1')), + /** + * @param array{return_ratio?: mixed, unlock_ratio?: mixed, points_to_cash_ratio?: mixed} $ratios + */ + public static function syncToRedis(array $ratios): void + { + $payload = [ + 'return_ratio' => self::toFloat($ratios['return_ratio'] ?? 0), + 'unlock_ratio' => self::toFloat($ratios['unlock_ratio'] ?? 0), + 'points_to_cash_ratio' => self::toFloat($ratios['points_to_cash_ratio'] ?? 0), ]; + self::writeRedis(self::redisConnection(), $payload); + } - return self::$cache; + public static function syncFromRow(MallBusinessConfig $row): void + { + self::syncToRedis([ + 'return_ratio' => $row->return_ratio, + 'unlock_ratio' => $row->unlock_ratio, + 'points_to_cash_ratio' => $row->points_to_cash_ratio, + ]); } public static function forget(): void { - self::$cache = null; + $conn = self::redisConnection(); + if ($conn === null) { + return; + } + try { + $conn->del(self::REDIS_KEY); + } catch (Throwable) { + } + } + + private static function redisConnection(): ?object + { + $cfg = config('redis'); + if (!is_array($cfg) || empty($cfg)) { + return null; + } + try { + return RedisSupport::connection('default'); + } catch (Throwable) { + return null; + } + } + + /** + * @return array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float}|null + */ + private static function readFromRedis(object $conn): ?array + { + try { + $raw = $conn->get(self::REDIS_KEY); + } catch (Throwable) { + return null; + } + if (!is_string($raw) || $raw === '') { + return null; + } + $data = json_decode($raw, true); + if (!is_array($data)) { + return null; + } + if (!isset($data['return_ratio'], $data['unlock_ratio'], $data['points_to_cash_ratio'])) { + return null; + } + + return [ + 'return_ratio' => self::toFloat($data['return_ratio']), + 'unlock_ratio' => self::toFloat($data['unlock_ratio']), + 'points_to_cash_ratio' => self::toFloat($data['points_to_cash_ratio']), + ]; + } + + /** + * @return array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float} + */ + private static function loadFromDatabaseAndWriteRedis(?object $conn): array + { + $row = MallBusinessConfig::order('id', 'asc')->find(); + if ($row) { + $out = [ + 'return_ratio' => self::toFloat($row->return_ratio), + 'unlock_ratio' => self::toFloat($row->unlock_ratio), + 'points_to_cash_ratio' => self::toFloat($row->points_to_cash_ratio), + ]; + self::writeRedis($conn, $out); + + return $out; + } + + $out = [ + 'return_ratio' => floatval(env('PLAYX_RETURN_RATIO', '0.1')), + 'unlock_ratio' => floatval(env('PLAYX_UNLOCK_RATIO', '0.1')), + 'points_to_cash_ratio' => floatval(env('PLAYX_POINTS_TO_CASH_RATIO', '0.1')), + ]; + self::writeRedis($conn, $out); + + return $out; + } + + /** + * @param array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float} $payload + */ + private static function writeRedis(?object $conn, array $payload): void + { + if ($conn === null) { + return; + } + try { + $json = json_encode($payload, JSON_THROW_ON_ERROR); + $conn->set(self::REDIS_KEY, $json); + } catch (Throwable) { + } } private static function toFloat(mixed $v): float diff --git a/app/common/model/MallConfig.php b/app/common/model/MallBusinessConfig.php similarity index 73% rename from app/common/model/MallConfig.php rename to app/common/model/MallBusinessConfig.php index 9a2a8f4..f5a4f60 100644 --- a/app/common/model/MallConfig.php +++ b/app/common/model/MallBusinessConfig.php @@ -7,11 +7,11 @@ namespace app\common\model; use support\think\Model; /** - * 积分商城配置(比例等) + * 积分商城业务配置(含 PlayX 比例等) */ -class MallConfig extends Model +class MallBusinessConfig extends Model { - protected string $name = 'mall_config'; + protected string $name = 'mall_business_config'; protected bool $autoWriteTimestamp = true; diff --git a/config/playx.php b/config/playx.php index b0d5d9e..1aa3533 100644 --- a/config/playx.php +++ b/config/playx.php @@ -5,7 +5,7 @@ */ return [ /** - * 以下三项比例以数据表 mall_config 为准(后台「商城参数配置」)。 + * 以下三项比例以数据表 mall_business_config 为准(后台「商城参数配置」)。 * 此处保留 env 仅作兼容/文档默认值;业务代码请使用 MallPlayxRatios::get()。 */ 'return_ratio' => floatval(env('PLAYX_RETURN_RATIO', '0.1')), diff --git a/web/src/lang/backend/en/mall/pageIntro.ts b/web/src/lang/backend/en/mall/pageIntro.ts index 965953e..82682a8 100644 --- a/web/src/lang/backend/en/mall/pageIntro.ts +++ b/web/src/lang/backend/en/mall/pageIntro.ts @@ -53,6 +53,6 @@ export default { }, playxConfig: { title: 'About this page', - desc: 'Edit return/unlock/points-to-cash ratios used by daily push and asset APIs; values are stored in mall_config and apply immediately after save.', + desc: 'Edit return/unlock/points-to-cash ratios used by daily push and asset APIs; values are stored in mall_business_config and apply immediately after save.', }, } diff --git a/web/src/lang/backend/zh-cn/mall/pageIntro.ts b/web/src/lang/backend/zh-cn/mall/pageIntro.ts index 50a8985..7bc24df 100644 --- a/web/src/lang/backend/zh-cn/mall/pageIntro.ts +++ b/web/src/lang/backend/zh-cn/mall/pageIntro.ts @@ -53,6 +53,6 @@ export default { }, playxConfig: { title: '页面说明', - desc: '配置每日推送用到的返还比例、解锁比例及积分折算现金比例;保存后立即作用于接口逻辑(mall_config)。', + desc: '配置每日推送用到的返还比例、解锁比例及积分折算现金比例;保存后立即作用于接口逻辑(mall_business_config)。', }, }