Files
webman-buildadmin/app/admin/controller/config/DepositTier.php

462 lines
17 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\admin\controller\config;
use app\common\controller\Backend;
use app\common\library\game\FinanceCashierConfig as FinanceCashierConfigLib;
use app\common\library\game\DepositTier as DepositTierLib;
use app\common\service\GameHotDataCoordinator;
use app\common\service\GameHotDataLock;
use InvalidArgumentException;
use support\think\Db;
use support\Response;
use Throwable;
use Webman\Http\Request as WebmanRequest;
/**
* 充值档位独立编辑(仅 game_config.deposit_tier
*/
class DepositTier extends Backend
{
protected bool $modelValidate = false;
protected array $noNeedPermission = ['index', 'save'];
/**
* 读取支付货币下拉来源game_config.finance_cashier.currencies
* 用于充值档位表单的“支付货币”选项,避免前端硬编码。
*/
public function currencyOptions(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'));
}
$row = Db::name('game_config')->where('config_key', FinanceCashierConfigLib::CONFIG_KEY)->find();
$cfg = FinanceCashierConfigLib::parseFromConfigValue($row['config_value'] ?? null);
$currencies = [];
if (isset($cfg['currencies']) && is_array($cfg['currencies'])) {
foreach ($cfg['currencies'] as $item) {
if (!is_array($item)) {
continue;
}
$code = isset($item['code']) && is_string($item['code']) ? strtoupper(trim($item['code'])) : '';
if ($code === '') {
continue;
}
$currencies[] = $code;
}
}
$currencies = array_values(array_unique($currencies));
if ($currencies === []) {
$currencies = ['MYR', 'CNY', 'USD', 'USDT', 'VND', 'THB', 'SGD', 'IDR'];
}
return $this->success('', ['list' => $currencies]);
}
private function hasNodePermission(WebmanRequest $request, string $action): bool
{
if (!$this->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;
}
/**
* 列表baTablelist / total / remark支持 quickSearch、分页
*/
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'));
}
$row = Db::name('game_config')->where('config_key', DepositTierLib::CONFIG_KEY)->find();
$items = DepositTierLib::parseFromConfigValue($row['config_value'] ?? null);
$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): bool {
$id = isset($it['id']) && is_string($it['id']) ? mb_strtolower($it['id']) : '';
$t = isset($it['title']) && is_string($it['title']) ? mb_strtolower($it['title']) : '';
$te = isset($it['title_en']) && is_string($it['title_en']) ? mb_strtolower($it['title_en']) : '';
return $q === '' || str_contains($id, $q) || str_contains($t, $q) || str_contains($te, $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);
}
$ida = isset($a['id']) && is_string($a['id']) ? $a['id'] : '';
$idb = isset($b['id']) && is_string($b['id']) ? $b['id'] : '';
return strcmp($ida, $idb);
});
}
}
$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);
return $this->success('', [
'list' => $pageRows,
'total' => $total,
'remark' => '',
'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') {
$id = $request->get('id', '');
if (!is_string($id) || trim($id) === '') {
return $this->error(__('Parameter error'));
}
$row = Db::name('game_config')->where('config_key', DepositTierLib::CONFIG_KEY)->find();
$items = DepositTierLib::parseFromConfigValue($row['config_value'] ?? null);
$found = null;
foreach ($items as $it) {
if (!is_array($it)) {
continue;
}
$rid = $it['id'] ?? '';
if (is_string($rid) && $rid === $id) {
$found = $it;
break;
}
}
if ($found === null) {
return $this->error(__('Record not found'));
}
return $this->success('', ['row' => $found]);
}
if ($request->method() === 'POST') {
if (!$this->hasNodePermission($request, 'edit')) {
return $this->error(__('You have no permission'), [], 401);
}
$payload = $request->post();
if (!is_array($payload)) {
return $this->error(__('Parameter %s can not be empty', ['']));
}
$id = isset($payload['id']) && is_string($payload['id']) ? trim($payload['id']) : '';
if ($id === '') {
return $this->error(__('Parameter error'));
}
$cfgRow = Db::name('game_config')->where('config_key', DepositTierLib::CONFIG_KEY)->find();
$items = DepositTierLib::parseFromConfigValue($cfgRow['config_value'] ?? null);
$foundIdx = -1;
$foundRow = null;
foreach ($items as $k => $it) {
if (!is_array($it)) {
continue;
}
$rid = $it['id'] ?? '';
if (is_string($rid) && $rid === $id) {
$foundIdx = $k;
$foundRow = $it;
break;
}
}
if ($foundIdx < 0 || $foundRow === null) {
return $this->error(__('Record not found'));
}
$items[$foundIdx] = $this->mergeDepositTierEditPayload($foundRow, $payload, $id);
return $this->persistTierList($items);
}
return $this->error(__('Parameter error'));
}
/**
* 新增一条档位
*/
public function add(WebmanRequest $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if (!$this->hasNodePermission($request, 'add')) {
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', ['']));
}
$cfgRow = Db::name('game_config')->where('config_key', DepositTierLib::CONFIG_KEY)->find();
$items = DepositTierLib::parseFromConfigValue($cfgRow['config_value'] ?? null);
$newId = isset($payload['id']) && is_string($payload['id']) ? trim($payload['id']) : '';
if ($newId === '') {
$newId = DepositTierLib::generateId();
}
foreach ($items as $it) {
if (!is_array($it)) {
continue;
}
$rid = $it['id'] ?? '';
if (is_string($rid) && $rid === $newId) {
return $this->error(__('Tier ID already exists'));
}
}
$items[] = $this->normalizeFormRow($payload, $newId);
return $this->persistTierList($items);
}
/**
* 删除(支持批量 ids
*/
public function del(WebmanRequest $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if (!$this->hasNodePermission($request, 'del')) {
return $this->error(__('You have no permission'), [], 401);
}
if ($request->method() !== 'DELETE') {
return $this->error(__('Parameter error'));
}
$ids = $request->get('ids', []);
if (!is_array($ids)) {
if (is_string($ids) && $ids !== '') {
$ids = [$ids];
} else {
$ids = [];
}
}
$idSet = [];
foreach ($ids as $id) {
if (is_string($id) && trim($id) !== '') {
$idSet[trim($id)] = true;
}
}
if ($idSet === []) {
return $this->error(__('Parameter error'));
}
$cfgRow = Db::name('game_config')->where('config_key', DepositTierLib::CONFIG_KEY)->find();
$items = DepositTierLib::parseFromConfigValue($cfgRow['config_value'] ?? null);
$filtered = [];
foreach ($items as $it) {
if (!is_array($it)) {
continue;
}
$rid = isset($it['id']) && is_string($it['id']) ? $it['id'] : '';
if ($rid !== '' && isset($idSet[$rid])) {
continue;
}
$filtered[] = $it;
}
return $this->persistTierList($filtered);
}
/**
* 整表保存 JSON 数组(兼容旧版批量提交)
*/
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 must be an array'));
}
return $this->persistTierList($items);
}
/**
* @param list<array<string, mixed>> $items
*/
private function persistTierList(array $items): Response
{
try {
$clean = DepositTierLib::prepareItemsForSave(array_values($items));
$json = DepositTierLib::encodeForDb($clean);
} catch (InvalidArgumentException $e) {
return $this->error($e->getMessage());
}
$now = time();
$resourceKey = GameHotDataLock::safeResourceKeyForConfig(DepositTierLib::CONFIG_KEY);
$lock = GameHotDataLock::tryAcquire(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey);
if (!$lock['acquired']) {
return $this->error(__('This config is locked by another operation, please try again later'));
}
try {
try {
$exists = Db::name('game_config')->where('config_key', DepositTierLib::CONFIG_KEY)->find();
if ($exists) {
Db::name('game_config')->where('config_key', DepositTierLib::CONFIG_KEY)->update([
'config_value' => $json,
'value_type' => 'json',
'update_time' => $now,
]);
} else {
Db::name('game_config')->insert([
'config_key' => DepositTierLib::CONFIG_KEY,
'config_value' => $json,
'value_type' => 'json',
'remark' => '充值档位 JSON 数组(独立表单维护)',
'create_time' => $now,
'update_time' => $now,
]);
}
} catch (Throwable $e) {
return $this->error($e->getMessage());
}
GameHotDataCoordinator::afterGameConfigKeyCommitted(DepositTierLib::CONFIG_KEY);
return $this->success(__('Saved successfully'));
} finally {
GameHotDataLock::release(GameHotDataLock::TYPE_GAME_CONFIG, $resourceKey, $lock['token'], $lock['redis_lock']);
}
}
/**
* 弹窗整表提交与列表内开关:未出现在 payload 中的字段沿用 $current。
*
* @param array<string, mixed> $current
* @param array<string, mixed> $payload
*
* @return array<string, mixed>
*/
private function mergeDepositTierEditPayload(array $current, array $payload, string $id): array
{
$merged = [];
$merged['id'] = $id;
if (array_key_exists('sort', $payload)) {
$merged['sort'] = $payload['sort'];
} else {
$merged['sort'] = $current['sort'] ?? 0;
}
if (array_key_exists('status', $payload)) {
$merged['status'] = $payload['status'];
} else {
$merged['status'] = $current['status'] ?? 0;
}
$stringKeys = ['title', 'title_en', 'currency', 'pay_amount', 'amount', 'bonus_amount', 'desc', 'desc_en'];
foreach ($stringKeys as $key) {
if (array_key_exists($key, $payload)) {
$merged[$key] = $payload[$key];
} else {
$merged[$key] = $current[$key] ?? ($key === 'bonus_amount' ? '0' : '');
}
}
return $this->normalizeFormRow($merged, $id);
}
/**
* @param array<string, mixed> $payload
*
* @return array<string, mixed>
*/
private function normalizeFormRow(array $payload, string $id): 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 [
'id' => $id,
'title' => isset($payload['title']) && is_string($payload['title']) ? $payload['title'] : '',
'title_en' => isset($payload['title_en']) && is_string($payload['title_en']) ? $payload['title_en'] : '',
'currency' => isset($payload['currency']) && is_string($payload['currency']) ? $payload['currency'] : '',
'pay_amount' => $payload['pay_amount'] ?? '',
'amount' => $payload['amount'] ?? '',
'bonus_amount' => $payload['bonus_amount'] ?? '0',
'desc' => isset($payload['desc']) && is_string($payload['desc']) ? $payload['desc'] : '',
'desc_en' => isset($payload['desc_en']) && is_string($payload['desc_en']) ? $payload['desc_en'] : '',
'sort' => $sort,
'status' => $status,
];
}
}