feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
2026-01-29 21:56:53 +09:00
|
|
|
use App\Models\Stats\Monthly\StatFinanceMonthly;
|
|
|
|
|
use App\Models\Stats\Monthly\StatSalesMonthly;
|
feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
use App\Models\Tenants\Approval;
|
|
|
|
|
use App\Models\Tenants\ApprovalStep;
|
|
|
|
|
use App\Models\Tenants\Attendance;
|
|
|
|
|
use App\Models\Tenants\Deposit;
|
|
|
|
|
use App\Models\Tenants\Leave;
|
|
|
|
|
use App\Models\Tenants\Purchase;
|
|
|
|
|
use App\Models\Tenants\Sale;
|
|
|
|
|
use App\Models\Tenants\Withdrawal;
|
|
|
|
|
use Carbon\Carbon;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
|
|
|
|
|
class DashboardService extends Service
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* 대시보드 요약 데이터 조회
|
|
|
|
|
*/
|
|
|
|
|
public function summary(): array
|
|
|
|
|
{
|
|
|
|
|
$tenantId = $this->tenantId();
|
|
|
|
|
$userId = $this->apiUserId();
|
|
|
|
|
$today = Carbon::today();
|
|
|
|
|
$startOfMonth = Carbon::now()->startOfMonth();
|
|
|
|
|
$endOfMonth = Carbon::now()->endOfMonth();
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'today' => $this->getTodaySummary($tenantId, $today),
|
|
|
|
|
'finance' => $this->getFinanceSummary($tenantId, $startOfMonth, $endOfMonth),
|
|
|
|
|
'sales' => $this->getSalesSummary($tenantId, $startOfMonth, $endOfMonth),
|
|
|
|
|
'tasks' => $this->getTasksSummary($tenantId, $userId),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 대시보드 차트 데이터 조회
|
|
|
|
|
*
|
|
|
|
|
* @param array $params [period: week|month|quarter]
|
|
|
|
|
*/
|
|
|
|
|
public function charts(array $params): array
|
|
|
|
|
{
|
|
|
|
|
$tenantId = $this->tenantId();
|
|
|
|
|
$period = $params['period'] ?? 'month';
|
|
|
|
|
|
|
|
|
|
[$startDate, $endDate] = $this->getPeriodRange($period);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'period' => $period,
|
|
|
|
|
'start_date' => $startDate->toDateString(),
|
|
|
|
|
'end_date' => $endDate->toDateString(),
|
|
|
|
|
'deposit_trend' => $this->getDepositTrend($tenantId, $startDate, $endDate),
|
|
|
|
|
'withdrawal_trend' => $this->getWithdrawalTrend($tenantId, $startDate, $endDate),
|
|
|
|
|
'sales_by_client' => $this->getSalesByClient($tenantId, $startDate, $endDate),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 결재 현황 조회
|
|
|
|
|
*
|
|
|
|
|
* @param array $params [limit: int]
|
|
|
|
|
*/
|
|
|
|
|
public function approvals(array $params): array
|
|
|
|
|
{
|
|
|
|
|
$tenantId = $this->tenantId();
|
|
|
|
|
$userId = $this->apiUserId();
|
|
|
|
|
$limit = $params['limit'] ?? 10;
|
|
|
|
|
|
|
|
|
|
// 내가 결재할 문서 (결재함)
|
|
|
|
|
$pendingApprovals = $this->getPendingApprovals($tenantId, $userId, $limit);
|
|
|
|
|
|
|
|
|
|
// 내가 기안한 문서 중 진행중인 것
|
|
|
|
|
$myDrafts = $this->getMyPendingDrafts($tenantId, $userId, $limit);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'pending_approvals' => $pendingApprovals,
|
|
|
|
|
'my_drafts' => $myDrafts,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 오늘 요약 데이터
|
|
|
|
|
*/
|
|
|
|
|
private function getTodaySummary(int $tenantId, Carbon $today): array
|
|
|
|
|
{
|
|
|
|
|
// 오늘 출근자 수
|
|
|
|
|
$attendancesCount = Attendance::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereDate('work_date', $today)
|
|
|
|
|
->whereNotNull('check_in')
|
|
|
|
|
->count();
|
|
|
|
|
|
|
|
|
|
// 오늘 휴가자 수
|
|
|
|
|
$leavesCount = Leave::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->where('status', 'approved')
|
|
|
|
|
->whereDate('start_date', '<=', $today)
|
|
|
|
|
->whereDate('end_date', '>=', $today)
|
|
|
|
|
->count();
|
|
|
|
|
|
|
|
|
|
// 결재 대기 문서 수 (전체)
|
|
|
|
|
$approvalsPending = Approval::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->where('status', 'pending')
|
|
|
|
|
->count();
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'date' => $today->toDateString(),
|
|
|
|
|
'attendances_count' => $attendancesCount,
|
|
|
|
|
'leaves_count' => $leavesCount,
|
|
|
|
|
'approvals_pending' => $approvalsPending,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-29 21:56:53 +09:00
|
|
|
* 재무 요약 데이터 (sam_stat 우선, 폴백: 원본 DB)
|
feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
*/
|
|
|
|
|
private function getFinanceSummary(int $tenantId, Carbon $startOfMonth, Carbon $endOfMonth): array
|
|
|
|
|
{
|
2026-01-29 21:56:53 +09:00
|
|
|
// sam_stat 월간 데이터 시도
|
|
|
|
|
$monthly = StatFinanceMonthly::where('tenant_id', $tenantId)
|
|
|
|
|
->where('stat_year', $startOfMonth->year)
|
|
|
|
|
->where('stat_month', $startOfMonth->month)
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if ($monthly) {
|
|
|
|
|
return [
|
|
|
|
|
'monthly_deposit' => (float) $monthly->deposit_amount,
|
|
|
|
|
'monthly_withdrawal' => (float) $monthly->withdrawal_amount,
|
|
|
|
|
'balance' => (float) ($monthly->deposit_amount - $monthly->withdrawal_amount),
|
|
|
|
|
'source' => 'sam_stat',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 폴백: 원본 DB 실시간 집계
|
feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
$monthlyDeposit = Deposit::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereBetween('deposit_date', [$startOfMonth, $endOfMonth])
|
|
|
|
|
->sum('amount');
|
|
|
|
|
|
|
|
|
|
$monthlyWithdrawal = Withdrawal::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereBetween('withdrawal_date', [$startOfMonth, $endOfMonth])
|
|
|
|
|
->sum('amount');
|
|
|
|
|
|
|
|
|
|
$totalDeposits = Deposit::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->sum('amount');
|
|
|
|
|
|
|
|
|
|
$totalWithdrawals = Withdrawal::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->sum('amount');
|
|
|
|
|
|
|
|
|
|
$balance = $totalDeposits - $totalWithdrawals;
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'monthly_deposit' => (float) $monthlyDeposit,
|
|
|
|
|
'monthly_withdrawal' => (float) $monthlyWithdrawal,
|
|
|
|
|
'balance' => (float) $balance,
|
2026-01-29 21:56:53 +09:00
|
|
|
'source' => 'samdb',
|
feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-29 21:56:53 +09:00
|
|
|
* 매출/매입 요약 데이터 (sam_stat 우선, 폴백: 원본 DB)
|
feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
*/
|
|
|
|
|
private function getSalesSummary(int $tenantId, Carbon $startOfMonth, Carbon $endOfMonth): array
|
|
|
|
|
{
|
2026-01-29 21:56:53 +09:00
|
|
|
// sam_stat 월간 데이터 시도
|
|
|
|
|
$monthly = StatSalesMonthly::where('tenant_id', $tenantId)
|
|
|
|
|
->where('stat_year', $startOfMonth->year)
|
|
|
|
|
->where('stat_month', $startOfMonth->month)
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if ($monthly) {
|
|
|
|
|
return [
|
|
|
|
|
'monthly_sales' => (float) $monthly->sales_amount,
|
|
|
|
|
'monthly_purchases' => 0,
|
|
|
|
|
'source' => 'sam_stat',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 폴백: 원본 DB 실시간 집계
|
feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
$monthlySales = Sale::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereBetween('sale_date', [$startOfMonth, $endOfMonth])
|
|
|
|
|
->sum('total_amount');
|
|
|
|
|
|
|
|
|
|
$monthlyPurchases = Purchase::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereBetween('purchase_date', [$startOfMonth, $endOfMonth])
|
|
|
|
|
->sum('total_amount');
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'monthly_sales' => (float) $monthlySales,
|
|
|
|
|
'monthly_purchases' => (float) $monthlyPurchases,
|
2026-01-29 21:56:53 +09:00
|
|
|
'source' => 'samdb',
|
feat: 대시보드 API 및 FCM 푸시 알림 API 구현
Dashboard API:
- DashboardController, DashboardService 추가
- /dashboard/summary, /charts, /approvals 엔드포인트
Push Notification API:
- FCM 토큰 관리 (등록/해제/목록)
- 알림 설정 관리 (유형별 on/off, 알림음 설정)
- 알림 유형: deposit, withdrawal, order, approval, attendance, notice, system
- 알림음: default, deposit, withdrawal, order, approval, urgent
- PushDeviceToken, PushNotificationSetting 모델
- Swagger 문서 추가
2025-12-18 11:16:24 +09:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 할 일 요약 데이터
|
|
|
|
|
*/
|
|
|
|
|
private function getTasksSummary(int $tenantId, int $userId): array
|
|
|
|
|
{
|
|
|
|
|
// 내가 결재해야 할 문서 수
|
|
|
|
|
$pendingApprovals = ApprovalStep::query()
|
|
|
|
|
->whereHas('approval', function ($query) use ($tenantId) {
|
|
|
|
|
$query->where('tenant_id', $tenantId)
|
|
|
|
|
->where('status', 'pending');
|
|
|
|
|
})
|
|
|
|
|
->where('approver_id', $userId)
|
|
|
|
|
->where('status', 'pending')
|
|
|
|
|
->count();
|
|
|
|
|
|
|
|
|
|
// 승인 대기 휴가 신청 수 (관리자용)
|
|
|
|
|
$pendingLeaves = Leave::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->where('status', 'pending')
|
|
|
|
|
->count();
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'pending_approvals' => $pendingApprovals,
|
|
|
|
|
'pending_leaves' => $pendingLeaves,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 기간 범위 계산
|
|
|
|
|
*
|
|
|
|
|
* @return array [Carbon $startDate, Carbon $endDate]
|
|
|
|
|
*/
|
|
|
|
|
private function getPeriodRange(string $period): array
|
|
|
|
|
{
|
|
|
|
|
$endDate = Carbon::today();
|
|
|
|
|
|
|
|
|
|
switch ($period) {
|
|
|
|
|
case 'week':
|
|
|
|
|
$startDate = $endDate->copy()->subDays(6);
|
|
|
|
|
break;
|
|
|
|
|
case 'quarter':
|
|
|
|
|
$startDate = $endDate->copy()->subMonths(3)->startOfMonth();
|
|
|
|
|
break;
|
|
|
|
|
case 'month':
|
|
|
|
|
default:
|
|
|
|
|
$startDate = $endDate->copy()->subDays(29);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [$startDate, $endDate];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 입금 추이 데이터
|
|
|
|
|
*/
|
|
|
|
|
private function getDepositTrend(int $tenantId, Carbon $startDate, Carbon $endDate): array
|
|
|
|
|
{
|
|
|
|
|
$deposits = Deposit::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereBetween('deposit_date', [$startDate, $endDate])
|
|
|
|
|
->select(
|
|
|
|
|
DB::raw('DATE(deposit_date) as date'),
|
|
|
|
|
DB::raw('SUM(amount) as amount')
|
|
|
|
|
)
|
|
|
|
|
->groupBy(DB::raw('DATE(deposit_date)'))
|
|
|
|
|
->orderBy('date')
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
return $deposits->map(function ($item) {
|
|
|
|
|
return [
|
|
|
|
|
'date' => $item->date,
|
|
|
|
|
'amount' => (float) $item->amount,
|
|
|
|
|
];
|
|
|
|
|
})->toArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 출금 추이 데이터
|
|
|
|
|
*/
|
|
|
|
|
private function getWithdrawalTrend(int $tenantId, Carbon $startDate, Carbon $endDate): array
|
|
|
|
|
{
|
|
|
|
|
$withdrawals = Withdrawal::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereBetween('withdrawal_date', [$startDate, $endDate])
|
|
|
|
|
->select(
|
|
|
|
|
DB::raw('DATE(withdrawal_date) as date'),
|
|
|
|
|
DB::raw('SUM(amount) as amount')
|
|
|
|
|
)
|
|
|
|
|
->groupBy(DB::raw('DATE(withdrawal_date)'))
|
|
|
|
|
->orderBy('date')
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
return $withdrawals->map(function ($item) {
|
|
|
|
|
return [
|
|
|
|
|
'date' => $item->date,
|
|
|
|
|
'amount' => (float) $item->amount,
|
|
|
|
|
];
|
|
|
|
|
})->toArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 거래처별 매출 데이터
|
|
|
|
|
*/
|
|
|
|
|
private function getSalesByClient(int $tenantId, Carbon $startDate, Carbon $endDate): array
|
|
|
|
|
{
|
|
|
|
|
$sales = Sale::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->whereBetween('sale_date', [$startDate, $endDate])
|
|
|
|
|
->with('client:id,name')
|
|
|
|
|
->select(
|
|
|
|
|
'client_id',
|
|
|
|
|
DB::raw('SUM(total_amount) as amount')
|
|
|
|
|
)
|
|
|
|
|
->groupBy('client_id')
|
|
|
|
|
->orderByDesc('amount')
|
|
|
|
|
->limit(10)
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
return $sales->map(function ($item) {
|
|
|
|
|
return [
|
|
|
|
|
'client_id' => $item->client_id,
|
|
|
|
|
'client_name' => $item->client?->name ?? __('message.dashboard.unknown_client'),
|
|
|
|
|
'amount' => (float) $item->amount,
|
|
|
|
|
];
|
|
|
|
|
})->toArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 내가 결재해야 할 문서 목록
|
|
|
|
|
*/
|
|
|
|
|
private function getPendingApprovals(int $tenantId, int $userId, int $limit): array
|
|
|
|
|
{
|
|
|
|
|
$steps = ApprovalStep::query()
|
|
|
|
|
->whereHas('approval', function ($query) use ($tenantId) {
|
|
|
|
|
$query->where('tenant_id', $tenantId)
|
|
|
|
|
->where('status', 'pending');
|
|
|
|
|
})
|
|
|
|
|
->where('approver_id', $userId)
|
|
|
|
|
->where('status', 'pending')
|
|
|
|
|
->with(['approval' => function ($query) {
|
|
|
|
|
$query->with('drafter:id,name');
|
|
|
|
|
}])
|
|
|
|
|
->orderBy('created_at', 'desc')
|
|
|
|
|
->limit($limit)
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
return $steps->map(function ($step) {
|
|
|
|
|
return [
|
|
|
|
|
'id' => $step->approval->id,
|
|
|
|
|
'title' => $step->approval->title,
|
|
|
|
|
'drafter_name' => $step->approval->drafter?->name ?? '',
|
|
|
|
|
'status' => $step->approval->status,
|
|
|
|
|
'created_at' => $step->approval->created_at?->toDateTimeString(),
|
|
|
|
|
];
|
|
|
|
|
})->toArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 내가 기안한 진행중인 문서 목록
|
|
|
|
|
*/
|
|
|
|
|
private function getMyPendingDrafts(int $tenantId, int $userId, int $limit): array
|
|
|
|
|
{
|
|
|
|
|
$approvals = Approval::query()
|
|
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->where('drafter_id', $userId)
|
|
|
|
|
->where('status', 'pending')
|
|
|
|
|
->orderBy('created_at', 'desc')
|
|
|
|
|
->limit($limit)
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
return $approvals->map(function ($approval) {
|
|
|
|
|
return [
|
|
|
|
|
'id' => $approval->id,
|
|
|
|
|
'title' => $approval->title,
|
|
|
|
|
'status' => $approval->status,
|
|
|
|
|
'current_step' => $approval->current_step,
|
|
|
|
|
'created_at' => $approval->created_at?->toDateTimeString(),
|
|
|
|
|
];
|
|
|
|
|
})->toArray();
|
|
|
|
|
}
|
2025-12-18 11:23:35 +09:00
|
|
|
}
|