auth) { return false; } $controllerPath = get_controller_path($request); if (!$controllerPath) { return false; } $paths = []; $paths[] = $controllerPath . '/' . $action; $parts = explode('/', $controllerPath); foreach ($parts as &$part) { if (str_contains($part, '_')) { $part = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $part)))); } } $paths[] = implode('/', $parts) . '/' . $action; foreach (array_values(array_unique($paths)) as $path) { if ($this->auth->check($path)) { return true; } } return false; } protected function initController(WebmanRequest $request): ?Response { return null; } /** * 列表(baTable:list / total / remark)+ registry(弹窗展示名) */ public function index(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if (!$this->hasNodePermission($request, 'index')) { return $this->error(__('You have no permission'), [], 401); } if ($request->method() !== 'GET') { return $this->error(__('Parameter error')); } $registryOut = $this->buildRegistryOut(); $parsed = DepositChannelLib::parseStoredOverridesFromDb(); $items = DepositChannelLib::expandRowsForAdmin($parsed); $quickSearch = $request->get('quickSearch', ''); if (is_string($quickSearch) && trim($quickSearch) !== '') { $q = mb_strtolower(trim($quickSearch)); $items = array_values(array_filter($items, static function (array $it) use ($q, $registryOut): bool { $code = isset($it['code']) && is_string($it['code']) ? mb_strtolower($it['code']) : ''; $name = ''; if (isset($it['code']) && is_string($it['code']) && isset($registryOut[$it['code']])) { $meta = $registryOut[$it['code']]; $name = isset($meta['name']) && is_string($meta['name']) ? mb_strtolower($meta['name']) : ''; } return $q === '' || str_contains($code, $q) || str_contains($name, $q); })); } $orderRaw = $request->get('order', ''); if (is_string($orderRaw) && str_contains($orderRaw, ',')) { $parts = explode(',', $orderRaw, 2); $field = trim($parts[0]); $dir = strtolower(trim($parts[1] ?? 'asc')); if ($field === 'sort') { usort($items, static function (array $a, array $b) use ($dir): int { $sa = isset($a['sort']) && is_numeric($a['sort']) ? intval($a['sort']) : 0; $sb = isset($b['sort']) && is_numeric($b['sort']) ? intval($b['sort']) : 0; if ($sa !== $sb) { return $dir === 'desc' ? ($sb <=> $sa) : ($sa <=> $sb); } $ca = isset($a['code']) && is_string($a['code']) ? $a['code'] : ''; $cb = isset($b['code']) && is_string($b['code']) ? $b['code'] : ''; return strcmp($ca, $cb); }); } } $total = count($items); $pageRaw = $request->get('page', '1'); $limitRaw = $request->get('limit', '20'); $page = is_numeric($pageRaw) ? max(1, intval($pageRaw)) : 1; $limit = is_numeric($limitRaw) ? max(1, min(500, intval($limitRaw))) : 20; $offset = ($page - 1) * $limit; $pageRows = array_slice($items, $offset, $limit); foreach ($pageRows as &$pr) { if (!is_array($pr)) { continue; } $code = isset($pr['code']) && is_string($pr['code']) ? $pr['code'] : ''; $meta = $code !== '' && isset($registryOut[$code]) ? $registryOut[$code] : null; $pr['display_name'] = is_array($meta) && isset($meta['name']) && is_string($meta['name']) ? $meta['name'] : $code; $pr['name_en'] = is_array($meta) && isset($meta['name_en']) && is_string($meta['name_en']) ? $meta['name_en'] : ''; } unset($pr); return $this->success('', [ 'list' => $pageRows, 'total' => $total, 'remark' => '', 'registry' => $registryOut, 'items' => $pageRows, ]); } /** * 单条读取 / 单条更新(弹窗) */ public function edit(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if (!$this->hasNodePermission($request, 'edit')) { return $this->error(__('You have no permission'), [], 401); } if ($request->method() === 'GET') { $code = $request->get('code', ''); if (!is_string($code) || trim($code) === '') { $code = $request->get('id', ''); } if (!is_string($code) || trim($code) === '') { return $this->error(__('Parameter error')); } $code = strtolower(trim($code)); $parsed = DepositChannelLib::parseStoredOverridesFromDb(); $items = DepositChannelLib::expandRowsForAdmin($parsed); $found = null; foreach ($items as $it) { if (!is_array($it)) { continue; } $c = isset($it['code']) && is_string($it['code']) ? strtolower(trim($it['code'])) : ''; if ($c === $code) { $found = $it; break; } } if ($found === null) { return $this->error(__('Record not found')); } return $this->success('', ['row' => $found]); } if ($request->method() === 'POST') { $payload = $request->post(); if (!is_array($payload)) { return $this->error(__('Parameter %s can not be empty', [''])); } $code = isset($payload['code']) && is_string($payload['code']) ? strtolower(trim($payload['code'])) : ''; if ($code === '') { return $this->error(__('Parameter error')); } $parsed = DepositChannelLib::parseStoredOverridesFromDb(); $items = DepositChannelLib::expandRowsForAdmin($parsed); $foundIdx = -1; $foundRow = null; foreach ($items as $k => $it) { if (!is_array($it)) { continue; } $c = isset($it['code']) && is_string($it['code']) ? strtolower(trim($it['code'])) : ''; if ($c === $code) { $foundIdx = $k; $foundRow = $it; break; } } if ($foundIdx < 0 || $foundRow === null) { return $this->error(__('Record not found')); } $items[$foundIdx] = $this->mergeDepositChannelEditPayload($foundRow, $payload, $code); return $this->persistChannelList($items); } return $this->error(__('Parameter error')); } public function save(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } if (!$this->hasNodePermission($request, 'save')) { return $this->error(__('You have no permission'), [], 401); } if ($request->method() !== 'POST') { return $this->error(__('Parameter error')); } $payload = $request->post(); if (!is_array($payload)) { return $this->error(__('Parameter %s can not be empty', [''])); } $items = $payload['items'] ?? null; if (!is_array($items)) { return $this->error('items 必须为数组'); } return $this->persistChannelList($items); } /** * @param list> $items */ private function persistChannelList(array $items): Response { try { $registry = DepositChannelLib::codeRegistry(); $clean = DepositChannelLib::prepareOverridesForSave(array_values($items)); $expectedCodes = array_keys($registry); sort($expectedCodes); $got = array_column($clean, 'code'); sort($got); if ($expectedCodes !== $got) { return $this->error('请保存全部已注册渠道行(不可缺行)'); } $json = DepositChannelLib::encodeForDb($clean); } catch (InvalidArgumentException $e) { return $this->error($e->getMessage()); } $now = time(); $resourceKey = GameHotDataLock::safeResourceKeyForConfig(DepositChannelLib::CONFIG_KEY); $lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey); if (!$lock['acquired']) { return $this->error('该配置正在被其他操作占用,请稍后再试'); } try { try { $exists = Db::name('game_config')->where('config_key', DepositChannelLib::CONFIG_KEY)->find(); if ($exists) { Db::name('game_config')->where('config_key', DepositChannelLib::CONFIG_KEY)->update([ 'config_value' => $json, 'value_type' => 'json', 'update_time' => $now, ]); } else { Db::name('game_config')->insert([ 'config_key' => DepositChannelLib::CONFIG_KEY, 'config_value' => $json, 'value_type' => 'json', 'remark' => '充值支付渠道 JSON(与 finance_cashier.channels 同步)', 'create_time' => $now, 'update_time' => $now, ]); } $fcExists = Db::name('game_config')->where('config_key', FinanceCashierConfigLib::CONFIG_KEY)->find(); if ($fcExists) { $fcPayload = FinanceCashierConfigLib::parseFromConfigValue($fcExists['config_value'] ?? null); $fcPayload['channels'] = $clean; $fcJson = FinanceCashierConfigLib::encodeForDb($fcPayload); Db::name('game_config')->where('config_key', FinanceCashierConfigLib::CONFIG_KEY)->update([ 'config_value' => $fcJson, 'value_type' => 'json', 'update_time' => $now, ]); GameHotDataCoordinator::afterGameConfigKeyCommitted(FinanceCashierConfigLib::CONFIG_KEY); } } catch (Throwable $e) { return $this->error($e->getMessage()); } GameHotDataCoordinator::afterGameConfigKeyCommitted(DepositChannelLib::CONFIG_KEY); return $this->success(__('Saved successfully')); } finally { GameHotDataLock::release(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey, $lock['token'], $lock['redis_lock']); } } /** * @return array */ private function buildRegistryOut(): array { $registry = DepositChannelLib::codeRegistry(); $registryOut = []; foreach ($registry as $code => $meta) { if (!is_array($meta)) { continue; } $registryOut[$code] = [ 'name' => isset($meta['name']) && is_string($meta['name']) ? $meta['name'] : '', 'name_en' => isset($meta['name_en']) && is_string($meta['name_en']) ? $meta['name_en'] : '', 'sort' => isset($meta['sort']) && is_numeric($meta['sort']) ? intval($meta['sort']) : 10, ]; } return $registryOut; } /** * 弹窗整表提交与列表内开关均走此合并:未出现在 payload 中的字段沿用 $current。 * * @param array $current * @param array $payload * * @return array{code: string, sort: int, status: int, tier_ids: list} */ private function mergeDepositChannelEditPayload(array $current, array $payload, string $code): array { $form = []; if (array_key_exists('sort', $payload)) { $form['sort'] = $payload['sort']; } else { $form['sort'] = $current['sort'] ?? 0; } if (array_key_exists('status', $payload)) { $form['status'] = $payload['status']; } else { $form['status'] = $current['status'] ?? 0; } return $this->normalizeChannelFormRow($form, $code); } /** * @param array $payload * * @return array{code: string, sort: int, status: int, tier_ids: list} */ private function normalizeChannelFormRow(array $payload, string $code): array { $sort = isset($payload['sort']) && is_numeric($payload['sort']) ? intval($payload['sort']) : 0; $status = 0; $st = $payload['status'] ?? 1; if ($st === true || $st === 1 || $st === '1') { $status = 1; } return [ 'code' => $code, 'sort' => $sort, 'status' => $status, 'tier_ids' => [], ]; } }