|
|
@@ -0,0 +1,333 @@
|
|
|
+<x-admin::layouts>
|
|
|
+ <x-slot:title>
|
|
|
+ @lang('rewardpoints::rewardpoints.admin.transactions')
|
|
|
+ </x-slot:title>
|
|
|
+
|
|
|
+ {{-- 页面标题和操作按钮 --}}
|
|
|
+ <div class="flex flex-wrap gap-4 justify-between items-center mb-6">
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
+ <div class="icon-list text-2xl text-blue-500"></div>
|
|
|
+ <p class="text-2xl text-gray-800 dark:text-white font-bold">
|
|
|
+ @if($viewType === 'earned')
|
|
|
+ @lang('rewardpoints::rewardpoints.admin.earned-transactions')
|
|
|
+ @else
|
|
|
+ @lang('rewardpoints::rewardpoints.admin.transactions')
|
|
|
+ @endif
|
|
|
+ </p>
|
|
|
+ <span class="px-2.5 py-0.5 text-sm bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded-full">
|
|
|
+ {{ $transactions->total() }}
|
|
|
+ @lang('rewardpoints::rewardpoints.admin.total')
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="flex gap-x-2.5 items-center">
|
|
|
+ {{-- 视图切换按钮 --}}
|
|
|
+ <div class="flex gap-2">
|
|
|
+ <a
|
|
|
+ href="{{ route('admin.reward-points.transactions.index', array_merge(request()->except('view_type'), ['view_type' => 'all'])) }}"
|
|
|
+ class="{{ $viewType !== 'earned' ? 'primary-button' : 'secondary-button' }}"
|
|
|
+ >
|
|
|
+ <span class="icon-list text-lg"></span>
|
|
|
+ @lang('rewardpoints::rewardpoints.admin.view-all-transactions')
|
|
|
+ </a>
|
|
|
+ <a
|
|
|
+ href="{{ route('admin.reward-points.transactions.earned', array_merge(request()->except('view_type'))) }}"
|
|
|
+ class="{{ $viewType === 'earned' ? 'primary-button' : 'secondary-button' }}"
|
|
|
+ >
|
|
|
+ <span class="icon-arrow-up text-lg"></span>
|
|
|
+ @lang('rewardpoints::rewardpoints.admin.view-earned-only')
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <a
|
|
|
+ href="{{ route('admin.reward-points.transactions.export', request()->all()) }}"
|
|
|
+ class="secondary-button"
|
|
|
+ >
|
|
|
+ <span class="icon-download text-lg"></span>
|
|
|
+ @lang('Export')
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ {{-- 筛选器 --}}
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-800 p-4 mb-6">
|
|
|
+ <form method="GET" action="{{ route('admin.reward-points.transactions.index') }}" class="flex flex-wrap items-end gap-4">
|
|
|
+ {{-- 开始日期 --}}
|
|
|
+ <div class="flex-1 min-w-[180px]">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">
|
|
|
+ @lang('Start Date')
|
|
|
+ </label>
|
|
|
+ <input
|
|
|
+ type="date"
|
|
|
+ name="start_date"
|
|
|
+ value="{{ $startDate }}"
|
|
|
+ class="flex w-full min-h-[39px] py-2 px-3 border border-gray-300 dark:border-gray-800 rounded-md text-sm text-gray-600 dark:text-gray-300 transition-all hover:border-gray-400 dark:hover:border-gray-400 focus:border-gray-400 dark:focus:border-gray-400"
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 结束日期 --}}
|
|
|
+ <div class="flex-1 min-w-[180px]">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">
|
|
|
+ @lang('End Date')
|
|
|
+ </label>
|
|
|
+ <input
|
|
|
+ type="date"
|
|
|
+ name="end_date"
|
|
|
+ value="{{ $endDate }}"
|
|
|
+ class="flex w-full min-h-[39px] py-2 px-3 border border-gray-300 dark:border-gray-800 rounded-md text-sm text-gray-600 dark:text-gray-300 transition-all hover:border-gray-400 dark:hover:border-gray-400 focus:border-gray-400 dark:focus:border-gray-400"
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 客户邮箱 --}}
|
|
|
+ <div class="flex-1 min-w-[200px]">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">
|
|
|
+ @lang('Customer Email')
|
|
|
+ </label>
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ name="customer_email"
|
|
|
+ value="{{ $customerEmail }}"
|
|
|
+ placeholder="@lang('Search by email')"
|
|
|
+ class="flex w-full min-h-[39px] py-2 px-3 border border-gray-300 dark:border-gray-800 rounded-md text-sm text-gray-600 dark:text-gray-300 transition-all hover:border-gray-400 dark:hover:border-gray-400 focus:border-gray-400 dark:focus:border-gray-400"
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 交易类型 --}}
|
|
|
+ <div class="flex-1 min-w-[160px]">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">
|
|
|
+ @lang('Transaction Type')
|
|
|
+ </label>
|
|
|
+ <select
|
|
|
+ name="transaction_type"
|
|
|
+ class="flex w-full min-h-[39px] py-2 px-3 border border-gray-300 dark:border-gray-800 rounded-md text-sm text-gray-600 dark:text-gray-300 transition-all hover:border-gray-400 dark:hover:border-gray-400 focus:border-gray-400 dark:focus:border-gray-400"
|
|
|
+ >
|
|
|
+ <option value="">@lang('All Types')</option>
|
|
|
+ <option value="1" {{ $transactionType == '1' ? 'selected' : '' }}>@lang('Order')</option>
|
|
|
+ <option value="2" {{ $transactionType == '2' ? 'selected' : '' }}>@lang('Registration')</option>
|
|
|
+ <option value="3" {{ $transactionType == '3' ? 'selected' : '' }}>@lang('Product Review')</option>
|
|
|
+ <option value="4" {{ $transactionType == '4' ? 'selected' : '' }}>@lang('Daily Sign In')</option>
|
|
|
+ <option value="5" {{ $transactionType == '5' ? 'selected' : '' }}>@lang('Referral')</option>
|
|
|
+ <option value="6" {{ $transactionType == '6' ? 'selected' : '' }}>@lang('Birthday')</option>
|
|
|
+ <option value="8" {{ $transactionType == '8' ? 'selected' : '' }}>@lang('Subscribe')</option>
|
|
|
+ <option value="0" {{ $transactionType == '0' ? 'selected' : '' }}>@lang('Admin Adjustment')</option>
|
|
|
+ <option value="99" {{ $transactionType == '99' ? 'selected' : '' }}>@lang('Admin Action')</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 金额类型 --}}
|
|
|
+ <div class="flex-1 min-w-[140px]">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">
|
|
|
+ @lang('Amount Type')
|
|
|
+ </label>
|
|
|
+ <select
|
|
|
+ name="amount_type"
|
|
|
+ class="flex w-full min-h-[39px] py-2 px-3 border border-gray-300 dark:border-gray-800 rounded-md text-sm text-gray-600 dark:text-gray-300 transition-all hover:border-gray-400 dark:hover:border-gray-400 focus:border-gray-400 dark:focus:border-gray-400"
|
|
|
+ >
|
|
|
+ <option value="">@lang('All')</option>
|
|
|
+ <option value="earned" {{ $amountType == 'earned' ? 'selected' : '' }}>@lang('Earned')</option>
|
|
|
+ <option value="redeemed" {{ $amountType == 'redeemed' ? 'selected' : '' }}>@lang('Redeemed')</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 操作按钮 --}}
|
|
|
+ <div class="flex gap-2">
|
|
|
+ <button
|
|
|
+ type="submit"
|
|
|
+ class="primary-button"
|
|
|
+ >
|
|
|
+ <span class="icon-search text-lg"></span>
|
|
|
+ @lang('Search')
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <a
|
|
|
+ href="{{ route('admin.reward-points.transactions.index') }}"
|
|
|
+ class="secondary-button"
|
|
|
+ >
|
|
|
+ <span class="icon-reset text-lg"></span>
|
|
|
+ @lang('Reset')
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
+ {{-- 统计卡片 - 强制一行三列 --}}
|
|
|
+ <div class="grid grid-cols-3 gap-4 mb-6">
|
|
|
+ {{-- 总赚取积分 --}}
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-800 overflow-hidden">
|
|
|
+ <div class="p-5">
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <div>
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400">
|
|
|
+ @lang('Total Points Earned')
|
|
|
+ </p>
|
|
|
+ <p class="text-3xl font-bold text-green-600 dark:text-green-400 mt-2">
|
|
|
+ {{ number_format($totalEarned) }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="w-12 h-12 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center">
|
|
|
+ <span class="icon-arrow-up text-2xl text-green-600 dark:text-green-400"></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 总兑换积分 --}}
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-800 overflow-hidden">
|
|
|
+ <div class="p-5">
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <div>
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400">
|
|
|
+ @lang('Total Points Redeemed')
|
|
|
+ </p>
|
|
|
+ <p class="text-3xl font-bold text-red-600 dark:text-red-400 mt-2">
|
|
|
+ {{ number_format($totalRedeemed) }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="w-12 h-12 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center">
|
|
|
+ <span class="icon-arrow-down text-2xl text-red-600 dark:text-red-400"></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 总交易数 --}}
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-800 overflow-hidden">
|
|
|
+ <div class="p-5">
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <div>
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400">
|
|
|
+ @lang('Total Transactions')
|
|
|
+ </p>
|
|
|
+ <p class="text-3xl font-bold text-blue-600 dark:text-blue-400 mt-2">
|
|
|
+ {{ number_format($totalTransactions) }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-full flex items-center justify-center">
|
|
|
+ <span class="icon-list text-2xl text-blue-600 dark:text-blue-400"></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ {{-- 表格 --}}
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-800 overflow-hidden">
|
|
|
+ <div class="overflow-x-auto">
|
|
|
+ <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-800">
|
|
|
+ <thead class="bg-gray-50 dark:bg-gray-800">
|
|
|
+ <tr>
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ @lang('ID')
|
|
|
+ </th>
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ @lang('Customer')
|
|
|
+ </th>
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ @lang('Type')
|
|
|
+ </th>
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ @lang('Amount')
|
|
|
+ </th>
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ @lang('Balance')
|
|
|
+ </th>
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ @lang('Date')
|
|
|
+ </th>
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ @lang('Description')
|
|
|
+ </th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody class="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-800">
|
|
|
+ @forelse($transactions as $transaction)
|
|
|
+ <tr class="hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-300">
|
|
|
+ #{{ $transaction->history_id }}
|
|
|
+ </td>
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap">
|
|
|
+ <div class="text-sm text-gray-900 dark:text-gray-300">
|
|
|
+ @if($transaction->customer)
|
|
|
+ {{ $transaction->customer->first_name }} {{ $transaction->customer->last_name }}
|
|
|
+ @else
|
|
|
+ N/A
|
|
|
+ @endif
|
|
|
+ </div>
|
|
|
+ <div class="text-sm text-gray-500 dark:text-gray-400">
|
|
|
+ {{ $transaction->customer ? $transaction->customer->email : 'N/A' }}
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap">
|
|
|
+ @php
|
|
|
+ $typeNames = [
|
|
|
+ 1 => 'rewardpoints::rewardpoints.admin.transaction-types.order',
|
|
|
+ 2 => 'rewardpoints::rewardpoints.admin.transaction-types.registration',
|
|
|
+ 3 => 'rewardpoints::rewardpoints.admin.transaction-types.review',
|
|
|
+ 4 => 'rewardpoints::rewardpoints.admin.transaction-types.sign-in',
|
|
|
+ 5 => 'rewardpoints::rewardpoints.admin.transaction-types.referral',
|
|
|
+ 6 => 'rewardpoints::rewardpoints.admin.transaction-types.birthday',
|
|
|
+ 7 => 'rewardpoints::rewardpoints.admin.transaction-types.share',
|
|
|
+ 8 => 'rewardpoints::rewardpoints.admin.transaction-types.subscribe',
|
|
|
+ 0 => 'rewardpoints::rewardpoints.admin.admin-adjustment',
|
|
|
+ 99 => 'rewardpoints::rewardpoints.admin.admin-action',
|
|
|
+ ];
|
|
|
+ @endphp
|
|
|
+ <span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full
|
|
|
+ @if($transaction->amount > 0)
|
|
|
+ bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200
|
|
|
+ @else
|
|
|
+ bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200
|
|
|
+ @endif">
|
|
|
+ @lang($typeNames[$transaction->type_of_transaction] ?? 'Unknown')
|
|
|
+ </span>
|
|
|
+ </td>
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-sm">
|
|
|
+ <span class="font-semibold
|
|
|
+ @if($transaction->amount > 0)
|
|
|
+ text-green-600 dark:text-green-400
|
|
|
+ @else
|
|
|
+ text-red-600 dark:text-red-400
|
|
|
+ @endif">
|
|
|
+ {{ $transaction->amount > 0 ? '+' : '' }}{{ number_format($transaction->amount) }}
|
|
|
+ </span>
|
|
|
+ </td>
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-300">
|
|
|
+ {{ number_format($transaction->balance) }}
|
|
|
+ </td>
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-300">
|
|
|
+ {{ \Carbon\Carbon::parse($transaction->transaction_time)->format('Y-m-d H:i') }}
|
|
|
+ </td>
|
|
|
+ <td class="px-6 py-4 text-sm text-gray-900 dark:text-gray-300 max-w-xs truncate">
|
|
|
+ {{ $transaction->transaction_detail }}
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ @empty
|
|
|
+ <tr>
|
|
|
+ <td colspan="7" class="px-6 py-12 text-center">
|
|
|
+ <div class="flex flex-col items-center gap-4">
|
|
|
+ <div class="w-20 h-20 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center">
|
|
|
+ <span class="icon-list text-4xl text-gray-400"></span>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <p class="text-lg font-medium text-gray-600 dark:text-gray-400 mb-1">
|
|
|
+ @lang('No transactions found')
|
|
|
+ </p>
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-500">
|
|
|
+ @lang('Try adjusting your filters')
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ @endforelse
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 分页 --}}
|
|
|
+ @if($transactions->hasPages())
|
|
|
+ <div class="p-4 border-t border-gray-200 dark:border-gray-800">
|
|
|
+ {{ $transactions->links() }}
|
|
|
+ </div>
|
|
|
+ @endif
|
|
|
+ </div>
|
|
|
+</x-admin::layouts>
|