Show country on the device list beside IP.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
hashbro
2026-09-14 23:27:37 +08:00
parent 8c9a15c523
commit 74a85b415b
3 changed files with 84 additions and 2 deletions
@@ -23,6 +23,7 @@ use App\Services\PhotoOrigin;
use App\Services\PhotoPreview;
use App\Services\Tokenview\TokenviewMonitorService;
use App\Support\AgentScope;
use App\Support\CfIpCountry;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
@@ -52,7 +53,7 @@ class DeviceController extends Controller
$filters = $this->filtersFrom($request);
$q = $this->filteredQuery($filters);
$sortable = ['id', 'device_id', 'chain', 'channel_id', 'device_model', 'ios_version', 'ip', 'has_wallet', 'created_at', 'updated_at'];
$sortable = ['id', 'device_id', 'chain', 'channel_id', 'device_model', 'ios_version', 'ip', 'country', 'has_wallet', 'created_at', 'updated_at'];
$field = (string) $request->query('field', 'created_at');
$order = strtolower((string) $request->query('order', 'desc')) === 'asc' ? 'asc' : 'desc';
if (! in_array($field, $sortable, true)) {
@@ -65,7 +66,12 @@ class DeviceController extends Controller
$paginator = $q->paginate($limit, ['devices.*'], 'page', $page);
$portal = $this->portal();
$data = collect($paginator->items())->map(function (Device $d) use ($portal) {
$items = collect($paginator->items());
$visitCountries = $this->visitCountriesFor($items);
$data = $items->map(function (Device $d) use ($portal, $visitCountries) {
$country = CfIpCountry::normalize($d->country)
?? CfIpCountry::normalize($visitCountries[trim((string) $d->ip)] ?? null);
return [
'id' => $d->id,
'device_id' => $d->device_id,
@@ -75,6 +81,8 @@ class DeviceController extends Controller
'device_model' => $d->device_model ?: '',
'ios_version' => $d->ios_version ?: '',
'ip' => $d->ip ?: '',
'country' => $country ?: '',
'country_label' => CfIpCountry::label($country),
'has_wallet' => (int) $d->has_wallet,
'wallet_names' => $d->walletNameList(),
'has_whatsapp' => $d->hasWhatsApp() ? 1 : 0,
@@ -986,4 +994,39 @@ class DeviceController extends Controller
'msg' => '队列顺序已更新',
]);
}
/**
* Latest visit country per IP for devices that have no country of their own.
*
* @param Collection<int, Device> $devices
* @return array<string, string>
*/
private function visitCountriesFor(Collection $devices): array
{
$ips = $devices
->filter(fn (Device $d) => CfIpCountry::normalize($d->country) === null)
->map(fn (Device $d) => trim((string) $d->ip))
->filter()
->unique()
->values();
if ($ips->isEmpty()) {
return [];
}
$latestIds = PageVisit::query()
->selectRaw('MAX(id) as id')
->whereIn('ip', $ips)
->whereNotNull('country')
->where('country', '!=', '')
->groupBy('ip')
->pluck('id');
if ($latestIds->isEmpty()) {
return [];
}
return PageVisit::query()
->whereIn('id', $latestIds)
->pluck('country', 'ip')
->all();
}
}