From 932a43361344f6362914b8e4fe57ce51cb021302 Mon Sep 17 00:00:00 2001 From: zhenhui <1276357500@qq.com> Date: Thu, 14 May 2026 10:37:21 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BC=98=E5=8C=96=E4=B8=8B=E6=B3=A8=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3/api/game/betPlace=202.=E4=BC=98=E5=8C=96=E5=90=8E?= =?UTF-8?q?=E5=8F=B0/admin/config/gameConfig=E4=B8=AD=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=8E=8B=E6=B3=A8=E7=AD=B9=E7=A0=81=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/controller/Game.php | 65 ++++++-- app/api/lang/en.php | 3 + app/api/lang/zh-cn.php | 3 + app/common/library/game/BetChips.php | 148 +++++++++++++++++ app/common/middleware/LoadLangPack.php | 27 +++- docs/36字花-移动端接口设计草案.md | 20 ++- scripts/generate_auth_signature.php | 2 +- web/src/lang/backend/en/game/config.ts | 6 + web/src/lang/backend/zh-cn/game/config.ts | 6 + .../views/backend/config/gameConfig/index.vue | 153 ++++++++++++++++-- 10 files changed, 392 insertions(+), 41 deletions(-) create mode 100644 app/common/library/game/BetChips.php diff --git a/app/api/controller/Game.php b/app/api/controller/Game.php index 12c1c51..40b6ed2 100644 --- a/app/api/controller/Game.php +++ b/app/api/controller/Game.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace app\api\controller; +use app\common\library\game\BetChips; use app\common\library\game\ZiHuaDictionary; use app\common\model\BetOrder; use app\common\model\GameRecord; @@ -57,12 +58,14 @@ class Game extends MobileBase 'lock_at' => $lockAt, 'open_at' => $openAt, ], - 'bet_config' => [ - 'pick_max_number_count' => $this->getPickMaxNumberCount(), - 'chips' => ['1.00', '5.00', '10.00', '25.00', '50.00', '100.00'], - 'min_bet_per_number' => $this->getConfigValue('min_bet_per_number', '0.0100'), - 'max_bet_per_number' => $this->getConfigValue('max_bet_per_number', '10000.0000'), - ], + 'bet_config' => array_merge( + [ + 'pick_max_number_count' => $this->getPickMaxNumberCount(), + 'min_bet_per_number' => $this->getConfigValue('min_bet_per_number', '0.0100'), + 'max_bet_per_number' => $this->getConfigValue('max_bet_per_number', '10000.0000'), + ], + BetChips::lobbyChipsPayload() + ), 'dictionary' => $items, 'user_snapshot' => [ 'coin' => $user->coin, @@ -119,7 +122,7 @@ class Game extends MobileBase /** * 兼容旧路由:/api/game/betPlace - * 新语义与 place_bet 一致:bet_amount 作为“单注金额”。 + * 与 placeBet 一致:须传筹码标识 bet_id(1–6),单注金额取自后台 game_config 的 bet_chips。 */ public function betPlace(Request $request): Response { @@ -127,8 +130,7 @@ class Game extends MobileBase } /** - * 提交下注:入参为 period_no + numbers + single_bet_amount + idempotency_key。 - * 兼容前端传参 bet_amount(作为 single_bet_amount 同义字段)。 + * 提交下注:入参为 period_no + numbers + bet_id(1–6,对应 lobbyInit.bet_config.chips 的键)+ idempotency_key。 */ public function placeBet(Request $request): Response { @@ -138,9 +140,14 @@ class Game extends MobileBase } $periodNo = trim((string) $request->post('period_no', '')); $numbersRaw = $request->post('numbers', ''); - $singleBetAmount = trim((string) ($request->post('single_bet_amount', $request->post('bet_amount', '')))); $idempotencyKey = trim((string) $request->post('idempotency_key', '')); - if ($periodNo === '' || $singleBetAmount === '' || $idempotencyKey === '') { + $chipPick = $this->resolveBetChipFromRequest($request); + if (isset($chipPick['error'])) { + return $chipPick['error']; + } + $betChipId = $chipPick['bet_id']; + $singleBetAmount = $chipPick['amount']; + if ($periodNo === '' || $idempotencyKey === '') { return $this->mobileError(1001, 'Missing parameters'); } if (!is_numeric($singleBetAmount) || bccomp($singleBetAmount, '0', 2) <= 0) { @@ -275,6 +282,7 @@ class Game extends MobileBase 'user_id' => $userId, 'period_no' => $period->period_no, 'numbers' => $numbers, + 'bet_id' => $betChipId, 'single_bet_amount' => $singleAmount, 'numbers_count' => count($numbers), 'total_amount' => $totalAmount, @@ -291,6 +299,7 @@ class Game extends MobileBase 'order_no' => $orderNo, 'period_no' => $period->period_no, 'status' => 'accepted', + 'bet_id' => $betChipId, 'single_bet_amount' => $singleAmount, 'numbers_count' => count($numbers), 'locked_balance' => '0.00', @@ -321,9 +330,13 @@ class Game extends MobileBase $periodNo = trim((string) $request->post('period_no', '')); $numbersRaw = $request->post('numbers', ''); - $singleBetAmount = trim((string) ($request->post('single_bet_amount', $request->post('bet_amount', '')))); $rounds = $this->intValue($request->post('rounds', 1)); - if ($periodNo === '' || $singleBetAmount === '' || $rounds < 1) { + $chipPick = $this->resolveBetChipFromRequest($request); + if (isset($chipPick['error'])) { + return $chipPick['error']; + } + $singleBetAmount = $chipPick['amount']; + if ($periodNo === '' || $rounds < 1) { return $this->mobileError(1001, 'Missing parameters'); } if (!is_numeric($singleBetAmount) || bccomp($singleBetAmount, '0', 2) <= 0) { @@ -340,6 +353,7 @@ class Game extends MobileBase GameWebSocketEventBus::publish('auto.spin.progress', [ 'user_id' => $userIdValue, 'period_no' => $periodNo, + 'bet_id' => $chipPick['bet_id'], 'rounds' => $rounds, 'remaining_rounds' => $rounds, 'completed_rounds' => 0, @@ -351,6 +365,7 @@ class Game extends MobileBase 'auto_mode' => true, 'period_no' => $periodNo, 'numbers' => $numbers, + 'bet_id' => $chipPick['bet_id'], 'single_bet_amount' => bcadd($singleBetAmount, '0', 2), 'rounds' => $rounds, 'remaining_rounds' => $rounds, @@ -376,7 +391,7 @@ class Game extends MobileBase 'order_no' => (string) $item->id, 'period_no' => $item->period_no, 'numbers' => $item->pick_numbers ?? [], - // 整笔压注金额(与请求 bet_amount 语义一致) + // 整笔压注金额(本笔总扣款) 'bet_amount' => $item->total_amount, 'total_amount' => $item->total_amount, 'result_number' => null, @@ -456,6 +471,28 @@ class Game extends MobileBase return 'finished'; } + /** + * @return array{bet_id: int, amount: string}|array{error: Response} + */ + private function resolveBetChipFromRequest(Request $request): array + { + $betIdRaw = $request->post('bet_id', ''); + if ($betIdRaw === '' || $betIdRaw === null) { + return ['error' => $this->mobileError(1001, 'Missing parameters')]; + } + $betId = filter_var($betIdRaw, FILTER_VALIDATE_INT); + if ($betId === false || $betId < 1 || $betId > 6) { + return ['error' => $this->mobileError(1003, 'Invalid parameter value')]; + } + $resolved = BetChips::resolveFromHotData(); + $amount = BetChips::amountForBetId($betId, $resolved['map']); + if ($amount === null) { + return ['error' => $this->mobileError(1003, 'Invalid parameter value')]; + } + + return ['bet_id' => $betId, 'amount' => $amount]; + } + /** * 单注最多可选号码个数:`game_config.config_key = pick_max_number_count` */ diff --git a/app/api/lang/en.php b/app/api/lang/en.php index 7e73fc0..bc317f8 100644 --- a/app/api/lang/en.php +++ b/app/api/lang/en.php @@ -25,12 +25,15 @@ return [ 'Register only supports phone' => 'Register only supports phone', 'Invite code required' => 'Invite code is required', 'Invite code not bound to channel' => 'This invite code is not bound to a valid channel', + 'Channel disabled' => 'Channel is disabled', 'Account already registered' => 'This phone number is already registered. Please sign in.', 'Please enter the correct mobile number' => 'Please enter the correct mobile number', 'Registered successfully but login failed' => 'Registered successfully but login failed', 'Incorrect account or password' => 'Incorrect account or password', 'Login status has expired' => 'Login status has expired', 'Game period does not exist' => 'Game period does not exist', + 'Game is paused' => 'Game is paused', + 'Bet amount out of range' => 'Bet amount out of range', 'Betting is closed' => 'Betting is closed', 'Insufficient balance' => 'Insufficient balance', 'Duplicate request' => 'Duplicate request', diff --git a/app/api/lang/zh-cn.php b/app/api/lang/zh-cn.php index c9cd83f..bfb1979 100644 --- a/app/api/lang/zh-cn.php +++ b/app/api/lang/zh-cn.php @@ -57,12 +57,15 @@ return [ 'Register only supports phone' => '注册仅支持手机号', 'Invite code required' => '请填写邀请码', 'Invite code not bound to channel' => '该邀请码未绑定有效渠道', + 'Channel disabled' => '渠道已关闭', 'Account already registered' => '该手机号已注册,请直接登录', 'Please enter the correct mobile number' => '请输入正确的手机号', 'Registered successfully but login failed' => '注册成功但登录失败', 'Incorrect account or password' => '账号或密码错误', 'Login status has expired' => '登录状态已过期', 'Game period does not exist' => '对局不存在', + 'Game is paused' => '游戏已暂停(维护或已关闭运行开关)', + 'Bet amount out of range' => '单注金额超出允许范围', 'Betting is closed' => '已封盘,禁止下注', 'Insufficient balance' => '余额不足', 'Duplicate request' => '重复请求(幂等冲突)', diff --git a/app/common/library/game/BetChips.php b/app/common/library/game/BetChips.php new file mode 100644 index 0000000..44c74b4 --- /dev/null +++ b/app/common/library/game/BetChips.php @@ -0,0 +1,148 @@ + 键 1..6 => 两位小数字符串面额 + */ + public static function defaultChipAmounts(): array + { + return [ + 1 => '1.00', + 2 => '5.00', + 3 => '10.00', + 4 => '25.00', + 5 => '50.00', + 6 => '100.00', + ]; + } + + /** + * @return array{map: array, default_id: int} + */ + public static function resolveFromHotData(): array + { + $rowChips = GameHotDataRedis::gameConfigRow(self::CONFIG_KEY_CHIPS); + $rowDefault = GameHotDataRedis::gameConfigRow(self::CONFIG_KEY_DEFAULT_ID); + $rawJson = $rowChips !== null ? ($rowChips['config_value'] ?? null) : null; + $map = self::parseChipsJson($rawJson); + + $defaultRaw = $rowDefault !== null ? ($rowDefault['config_value'] ?? null) : null; + $defaultId = filter_var(trim('' . $defaultRaw), FILTER_VALIDATE_INT); + if ($defaultId === false || $defaultId < 1 || $defaultId > 6) { + $defaultId = 1; + } + $amt = $map[$defaultId] ?? null; + if ($amt === null || !is_numeric($amt) || bccomp(bcadd($amt, '0', 2), '0', 2) <= 0) { + $defaultId = self::firstPositiveBetId($map); + } + + return ['map' => $map, 'default_id' => $defaultId]; + } + + /** + * @param array $map + */ + public static function amountForBetId(int $betId, array $map): ?string + { + if ($betId < 1 || $betId > 6) { + return null; + } + if (!isset($map[$betId])) { + return null; + } + $amt = $map[$betId]; + if (!is_numeric($amt) || bccomp(bcadd($amt, '0', 2), '0', 2) <= 0) { + return null; + } + + return bcadd($amt, '0', 2); + } + + /** + * lobbyInit 用:筹码为字典,键为标识字符串 `"1"`…`"6"`,值为两位小数字符串面额。 + * + * @return array{chips: array, default_bet_chip_id: int} + */ + public static function lobbyChipsPayload(): array + { + $resolved = self::resolveFromHotData(); + $chips = []; + foreach ($resolved['map'] as $id => $amount) { + $chips['' . $id] = $amount; + } + + return [ + 'chips' => $chips, + 'default_bet_chip_id' => $resolved['default_id'], + ]; + } + + /** + * @param mixed $rawJson + * @return array + */ + private static function parseChipsJson($rawJson): array + { + $defaults = self::defaultChipAmounts(); + $parsed = []; + if (is_string($rawJson) && $rawJson !== '') { + $decoded = json_decode($rawJson, true); + if (is_array($decoded)) { + foreach ($decoded as $k => $v) { + $id = filter_var($k, FILTER_VALIDATE_INT); + if ($id === false || $id < 1 || $id > 6) { + continue; + } + $amtRaw = trim('' . $v); + if (!is_numeric($amtRaw) || bccomp(bcadd($amtRaw, '0', 2), '0', 2) <= 0) { + continue; + } + $parsed[$id] = bcadd($amtRaw, '0', 2); + } + } + } + $out = []; + foreach ($defaults as $id => $def) { + if (isset($parsed[$id])) { + $out[$id] = $parsed[$id]; + } else { + $out[$id] = $def; + } + } + ksort($out); + + return $out; + } + + /** + * @param array $map + */ + private static function firstPositiveBetId(array $map): int + { + for ($i = 1; $i <= 6; $i++) { + if (!isset($map[$i])) { + continue; + } + $a = $map[$i]; + if (is_numeric($a) && bccomp(bcadd($a, '0', 2), '0', 2) > 0) { + return $i; + } + } + + return 1; + } +} diff --git a/app/common/middleware/LoadLangPack.php b/app/common/middleware/LoadLangPack.php index a3fffb6..545671f 100644 --- a/app/common/middleware/LoadLangPack.php +++ b/app/common/middleware/LoadLangPack.php @@ -26,7 +26,7 @@ class LoadLangPack implements MiddlewareInterface /** * 解析当前请求语言。 * - 后台 admin:优先请求头 think-lang(zh-cn / en),其次 lang 头,再次查询/表单参数 lang(支持 zh→zh-cn)。 - * - 对外 api:优先查询/表单参数 lang(zh / en),其次 lang 头,再次 think-lang;未显式指定时固定 zh-cn(不使用 Accept-Language)。 + * - 对外 api:优先查询/表单参数 lang(zh / zh-cn / en),其次 lang 头,再次 think-lang;仅当解析结果为允许列表中的 zh-cn 或 en 时生效,否则固定 zh-cn(不使用 Accept-Language)。仅 lang=en(规范化后)返回英文文案。 */ protected function resolveLangSet(Request $request): string { @@ -38,13 +38,28 @@ class LoadLangPack implements MiddlewareInterface if ($queryRaw === null || $queryRaw === '') { $queryRaw = $request->post('lang'); } - $queryLang = is_string($queryRaw) ? $queryRaw : ''; + $queryLang = ''; + if (is_string($queryRaw)) { + $queryLang = $queryRaw; + } elseif (is_scalar($queryRaw)) { + $queryLang = trim('' . $queryRaw); + } - $thinkRaw = $request->header('think-lang'); - $thinkLang = is_string($thinkRaw) ? $thinkRaw : ''; + $thinkRaw = $request->header('think-lang', ''); + $thinkLang = ''; + if (is_string($thinkRaw)) { + $thinkLang = $thinkRaw; + } elseif (is_array($thinkRaw) && isset($thinkRaw[0]) && is_string($thinkRaw[0])) { + $thinkLang = $thinkRaw[0]; + } - $headerLangRaw = $request->header('lang'); - $headerLang = is_string($headerLangRaw) ? $headerLangRaw : ''; + $headerLangRaw = $request->header('lang', ''); + $headerLang = ''; + if (is_string($headerLangRaw)) { + $headerLang = $headerLangRaw; + } elseif (is_array($headerLangRaw) && isset($headerLangRaw[0]) && is_string($headerLangRaw[0])) { + $headerLang = $headerLangRaw[0]; + } $normalize = static function (string $raw): string { $s = str_replace('_', '-', strtolower(trim($raw))); diff --git a/docs/36字花-移动端接口设计草案.md b/docs/36字花-移动端接口设计草案.md index a6550fc..4248590 100644 --- a/docs/36字花-移动端接口设计草案.md +++ b/docs/36字花-移动端接口设计草案.md @@ -231,8 +231,10 @@ - `open_at`:int(含义:预计开奖时间戳) - `bet_config`:object - `pick_max_number_count`:int(含义:单注最多可选号码数,来自 `game_config.config_key = pick_max_number_count`,缺省与库内种子一致,通常为 10,合法范围 1–36) - - `chips`:array[string](如 `["1.00","5.00"]`,含义:快捷筹码面额) - - `single_number_max_bet`:string(含义:单号码最大下注额) + - `chips`:object(含义:快捷筹码字典,固定 6 个键 `"1"`…`"6"`,值为该档单注面额字符串,两位小数;与后台 `game_config.bet_chips` 语义一致) + - `default_bet_chip_id`:int(含义:默认选中的筹码标识,来自 `game_config.default_bet_chip_id`,非法或指向无效档位时服务端回退为首个有效档) + - `min_bet_per_number`:string(含义:单号码最小下注额,须 ≤ 所选筹码面额且受后台配置约束) + - `max_bet_per_number`:string(含义:单号码最大下注额) - `dictionary`:array - `number`:int(1-36,含义:字花编号) - `name`:string(含义:字花名称) @@ -263,20 +265,20 @@ ### 4.2 提交下注 - **POST** `/api/game/placeBet`(兼容旧路径 `/api/game/betPlace`) -- 用途:单期手动下注;玩家传入**压注号码**与**单注金额 `single_bet_amount`**。服务端按 `single_bet_amount × numbers数量` 计算本笔总扣款(落库 `total_amount`),开奖只出一个号码,若该号码 ∈ 所选号码集合即视为中奖。 +- 用途:单期手动下注;玩家传入**压注号码**与**筹码标识 `bet_id`(1–6)**。单注金额由后台 `game_config.bet_chips` 解析,服务端按 `单注金额 × numbers数量` 计算本笔总扣款(落库 `total_amount`),开奖只出一个号码,若该号码 ∈ 所选号码集合即视为中奖。 请求参数: - `period_no`:string(含义:下注目标期号) - `numbers`:string(含义:本次压注号码集合,**英文逗号分隔**,如 `1,8,16`;每个号码为 1–36 的整数,数量不超过 `pick_max_number_count`(同 `lobbyInit.bet_config`),重复号码会去重) -- `single_bet_amount`:string(含义:**单注金额**,> 0) -- `bet_amount`:string(兼容字段,含义同 `single_bet_amount`) +- `bet_id`:int(含义:**快捷筹码标识**,取值 1–6,须为 `lobbyInit.bet_config.chips` 中存在的键;不再使用 `single_bet_amount` / `bet_amount` 传参) - `idempotency_key`:string(必填,含义:防止重复下单) 返回参数: - `order_no`:string(含义:下注订单号) - `period_no`:string(含义:实际落单期号) - `status`:string(`accepted`/`rejected`,含义:受理结果) -- `single_bet_amount`:string(含义:本次单注金额) +- `bet_id`:int(含义:本次使用的筹码标识) +- `single_bet_amount`:string(含义:本次单注金额,由 `bet_id` 对应档位解析得到) - `numbers_count`:int(含义:本次号码数量) - `locked_balance`:string(可选,含义:冻结金额) - `balance_after`:string(含义:下单后余额) @@ -294,12 +296,14 @@ - `action`:string(`start`/`stop`) - `period_no`:string(`action=start` 时必填) - `numbers`:string(`action=start` 时必填,英文逗号分隔) -- `single_bet_amount`:string(`action=start` 时必填,支持兼容字段 `bet_amount`) +- `bet_id`:int(`action=start` 时必填,含义同 `placeBet`,快捷筹码 1–6) - `rounds`:int(`action=start` 时必填,>=1) 返回参数: - `status`:string(`scheduled`/`stopped`) - `auto_mode`:bool +- `bet_id`:int(仅 `start` 返回,本次托管使用的筹码标识) +- `single_bet_amount`:string(仅 `start` 返回,由 `bet_id` 解析得到的单注面额) - `remaining_rounds`:int(仅 `start` 返回) ### 4.4 查询我的下注记录(最近1个月) @@ -715,7 +719,7 @@ - **客户端**:浏览器原生 `WebSocket`(`ws://` / `wss://`) - **连接时携带参数(建议)**: - URL Query:`token`(用户登录态 user-token)、`auth_token`(接口鉴权)、`device_id`(设备标识)、`lang`(`zh/en`) - - 示例:`wss://ws.example.com/game?token=xxx&auth_token=xxx&device_id=ios_001&lang=zh` + - 示例:`wss://ws.example.com/ws?token=xxx&auth_token=xxx&device_id=ios_001&lang=zh` - **连接成功返回(服务端首帧建议)**: - `event`:`ws.connected` - `connection_id`:连接唯一标识 diff --git a/scripts/generate_auth_signature.php b/scripts/generate_auth_signature.php index ef85abb..d101285 100644 --- a/scripts/generate_auth_signature.php +++ b/scripts/generate_auth_signature.php @@ -4,7 +4,7 @@ * 执行方法 * php scripts/generate_auth_signature.php * php scripts/generate_auth_signature.php 设备码 密钥 时间戳 - * php scripts/generate_auth_signature.php 1 564d14asdasd113e46542asd6das1a2a 1776331077 + * php scripts/generate_auth_signature.php 1 564d14asdasd113e46542asd6das1a2a */ declare(strict_types=1); diff --git a/web/src/lang/backend/en/game/config.ts b/web/src/lang/backend/en/game/config.ts index 3a1229c..8b50b65 100644 --- a/web/src/lang/backend/en/game/config.ts +++ b/web/src/lang/backend/en/game/config.ts @@ -12,6 +12,12 @@ export default { 'field_tip bet_seconds': 'How many seconds betting stays open in each period', 'field pick_max_number_count': 'Max numbers per ticket', 'field_tip pick_max_number_count': 'Maximum amount of selectable numbers per ticket', + 'field bet_chips': 'Quick chip amounts', + 'field_tip bet_chips': 'Exactly 6 tiers (ids 1–6, fixed). Edit amounts only; stored as JSON for lobbyInit.', + bet_chips_colon: ': ', + bet_chips_validate_slot: 'Chip tier {slot} must be a number greater than 0 (prefer ≥ min bet per number)', + 'field default_bet_chip_id': 'Default selected chip id', + 'field_tip default_bet_chip_id': 'Default highlighted chip id (1–6), must map to a valid amount in bet_chips', 'field min_bet_per_number': 'Min bet per number', 'field_tip min_bet_per_number': 'Minimum bet amount per selected number', 'field max_bet_per_number': 'Max bet per number', diff --git a/web/src/lang/backend/zh-cn/game/config.ts b/web/src/lang/backend/zh-cn/game/config.ts index 1dd7577..c2ce3ac 100644 --- a/web/src/lang/backend/zh-cn/game/config.ts +++ b/web/src/lang/backend/zh-cn/game/config.ts @@ -12,6 +12,12 @@ export default { 'field_tip bet_seconds': '每一局允许下注的时长(秒)', 'field pick_max_number_count': '单注最多号码个数', 'field_tip pick_max_number_count': '单注最多可选号码数量', + 'field bet_chips': '快捷筹码面额', + 'field_tip bet_chips': '固定 6 档(标识 1–6 不可改),仅可修改每档面额;保存时写入为 JSON,与移动端 lobbyInit 一致', + bet_chips_colon: ':', + bet_chips_validate_slot: '第 {slot} 档筹码面额须为大于 0 的数字(建议 ≥ 单号最小下注额)', + 'field default_bet_chip_id': '默认选中筹码', + 'field_tip default_bet_chip_id': '大厅默认高亮的筹码标识,须为 1–6 且对应 bet_chips 有效面额', 'field min_bet_per_number': '单号最小下注额', 'field_tip min_bet_per_number': '每个号码允许的最小下注金额', 'field max_bet_per_number': '单号最大下注额', diff --git a/web/src/views/backend/config/gameConfig/index.vue b/web/src/views/backend/config/gameConfig/index.vue index 2a3a91f..08be171 100644 --- a/web/src/views/backend/config/gameConfig/index.vue +++ b/web/src/views/backend/config/gameConfig/index.vue @@ -14,14 +14,43 @@
- -
{{ item.config_key }}
+ +
{{ t('Reset') }} {{ t('Save') }} @@ -34,6 +63,7 @@