|
|
@@ -1,27 +1,32 @@
|
|
|
<x-admin::layouts>
|
|
|
<x-slot:title>
|
|
|
- 会员成长值
|
|
|
+ 会员成长值管理
|
|
|
</x-slot>
|
|
|
|
|
|
{{-- 页面标题和操作按钮 --}}
|
|
|
<div class="flex flex-wrap gap-4 justify-between items-center mb-6">
|
|
|
<div class="flex items-center gap-3">
|
|
|
- <div class="icon-star text-2xl text-purple-500"></div>
|
|
|
- <p class="text-2xl text-gray-800 dark:text-white font-bold">
|
|
|
- 会员成长值
|
|
|
- </p>
|
|
|
- <span class="px-2.5 py-0.5 text-sm bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded-full">
|
|
|
+ <div class="w-10 h-10 bg-gradient-to-br from-purple-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
|
|
|
+ <span class="icon-star text-white text-xl"></span>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <p class="text-2xl font-bold text-gray-800 dark:text-white">
|
|
|
+ 会员成长值
|
|
|
+ </p>
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
|
|
|
+ 管理会员成长值和等级体系
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <span class="px-3 py-1 text-sm bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 rounded-full font-medium">
|
|
|
{{ $customers->total() }} 位会员
|
|
|
</span>
|
|
|
</div>
|
|
|
|
|
|
- <div class="flex gap-x-2.5 items-center">
|
|
|
+ <div class="flex gap-x-3 items-center">
|
|
|
{{-- 调整成长值按钮 --}}
|
|
|
<button
|
|
|
onclick="openAdjustModal()"
|
|
|
- style="padding: 0.5rem 1rem; background-color: #8b5cf6; color: white; font-weight: 500; border-radius: 0.5rem; border: none; cursor: pointer; transition: all 0.15s ease;"
|
|
|
- onmouseover="this.style.backgroundColor='#7c3aed'"
|
|
|
- onmouseout="this.style.backgroundColor='#8b5cf6'"
|
|
|
+ class="px-4 py-2 bg-gradient-to-r from-purple-600 to-purple-700 text-white rounded-lg hover:from-purple-700 hover:to-purple-800 transition-all duration-200 flex items-center gap-2 shadow-md hover:shadow-lg"
|
|
|
>
|
|
|
<span class="icon-plus text-lg"></span>
|
|
|
调整成长值
|
|
|
@@ -30,7 +35,7 @@
|
|
|
{{-- 等级配置按钮 --}}
|
|
|
<a
|
|
|
href="{{ route('admin.growth-value.levels') }}"
|
|
|
- class="secondary-button"
|
|
|
+ class="px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-all duration-200 flex items-center gap-2"
|
|
|
>
|
|
|
<span class="icon-settings text-lg"></span>
|
|
|
等级配置
|
|
|
@@ -39,62 +44,67 @@
|
|
|
</div>
|
|
|
|
|
|
{{-- 统计卡片 --}}
|
|
|
- <div class="flex flex-wrap gap-4 mb-6">
|
|
|
- <div class="flex-1 min-w-[200px] bg-gradient-to-br from-purple-50 to-purple-100 dark:from-purple-900/20 dark:to-purple-800/20 rounded-xl p-5 border border-purple-200 dark:border-purple-800">
|
|
|
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-800 p-6 hover:shadow-md transition-shadow">
|
|
|
<div class="flex items-center justify-between">
|
|
|
<div>
|
|
|
- <p class="text-sm text-gray-600 dark:text-gray-400 mb-1">
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400 mb-1">
|
|
|
总会员数
|
|
|
</p>
|
|
|
<p class="text-3xl font-bold text-purple-600 dark:text-purple-400">
|
|
|
- {{ $customers->total() }}
|
|
|
+ {{ number_format($customers->total()) }}
|
|
|
</p>
|
|
|
</div>
|
|
|
- <div class="w-12 h-12 bg-purple-100 dark:bg-purple-900/50 rounded-full flex items-center justify-center">
|
|
|
- <span class="icon-users text-2xl text-purple-600 dark:text-purple-400"></span>
|
|
|
+ <div class="w-12 h-12 bg-purple-100 dark:bg-purple-900/30 rounded-xl flex items-center justify-center">
|
|
|
+ <svg class="w-6 h-6 text-purple-600 dark:text-purple-400" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z"/>
|
|
|
+ </svg>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="flex-1 min-w-[200px] bg-gradient-to-br from-blue-50 to-blue-100 dark:from-blue-900/20 dark:to-blue-800/20 rounded-xl p-5 border border-blue-200 dark:border-blue-800">
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-800 p-6 hover:shadow-md transition-shadow">
|
|
|
<div class="flex items-center justify-between">
|
|
|
<div>
|
|
|
- <p class="text-sm text-gray-600 dark:text-gray-400 mb-1">
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400 mb-1">
|
|
|
总成长值
|
|
|
</p>
|
|
|
<p class="text-3xl font-bold text-blue-600 dark:text-blue-400">
|
|
|
- {{ number_format($customers->sum('growth_value')) }}
|
|
|
+ {{ number_format($totalGrowthValue) }}
|
|
|
</p>
|
|
|
</div>
|
|
|
- <div class="w-12 h-12 bg-blue-100 dark:bg-blue-900/50 rounded-full flex items-center justify-center">
|
|
|
- <span class="icon-star text-2xl text-blue-600 dark:text-blue-400"></span>
|
|
|
+ <div class="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-xl flex items-center justify-center">
|
|
|
+ <svg class="w-6 h-6 text-blue-600 dark:text-blue-400" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
|
|
|
+ </svg>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="flex-1 min-w-[200px] bg-gradient-to-br from-green-50 to-green-100 dark:from-green-900/20 dark:to-green-800/20 rounded-xl p-5 border border-green-200 dark:border-green-800">
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-800 p-6 hover:shadow-md transition-shadow">
|
|
|
<div class="flex items-center justify-between">
|
|
|
<div>
|
|
|
- <p class="text-sm text-gray-600 dark:text-gray-400 mb-1">
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400 mb-1">
|
|
|
平均成长值
|
|
|
</p>
|
|
|
<p class="text-3xl font-bold text-green-600 dark:text-green-400">
|
|
|
- {{ $customers->total() > 0 ? number_format(round($customers->sum('growth_value') / $customers->total(), 2)) : 0 }}
|
|
|
+ {{ number_format($avgGrowthValue) }}
|
|
|
</p>
|
|
|
</div>
|
|
|
- <div class="w-12 h-12 bg-green-100 dark:bg-green-900/50 rounded-full flex items-center justify-center">
|
|
|
- <span class="icon-chart-line text-2xl text-green-600 dark:text-green-400"></span>
|
|
|
+ <div class="w-12 h-12 bg-green-100 dark:bg-green-900/30 rounded-xl flex items-center justify-center">
|
|
|
+ <svg class="w-6 h-6 text-green-600 dark:text-green-400" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path fill-rule="evenodd" d="M12 7a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0V8.414l-4.293 4.293a1 1 0 01-1.414 0L8 10.414l-4.293 4.293a1 1 0 01-1.414-1.414l5-5a1 1 0 011.414 0L11 10.586 14.586 7H12z" clip-rule="evenodd"/>
|
|
|
+ </svg>
|
|
|
</div>
|
|
|
</div>
|
|
|
</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">
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-800 p-6 mb-6">
|
|
|
<form method="GET" action="{{ route('admin.growth-value.index') }}" class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
|
- {{-- 邮箱查询 --}}
|
|
|
<div>
|
|
|
- <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
客户邮箱
|
|
|
</label>
|
|
|
<input
|
|
|
@@ -102,13 +112,12 @@
|
|
|
name="email"
|
|
|
value="{{ request('email') }}"
|
|
|
placeholder="搜索客户邮箱..."
|
|
|
- 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"
|
|
|
+ class="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 dark:bg-gray-800 dark:text-white transition-all"
|
|
|
>
|
|
|
</div>
|
|
|
|
|
|
- {{-- 成长值最小值 --}}
|
|
|
<div>
|
|
|
- <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
最小成长值
|
|
|
</label>
|
|
|
<input
|
|
|
@@ -117,13 +126,12 @@
|
|
|
value="{{ request('min_growth_value') }}"
|
|
|
placeholder="0"
|
|
|
min="0"
|
|
|
- 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"
|
|
|
+ class="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 dark:bg-gray-800 dark:text-white transition-all"
|
|
|
>
|
|
|
</div>
|
|
|
|
|
|
- {{-- 成长值最大值 --}}
|
|
|
<div>
|
|
|
- <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
最大成长值
|
|
|
</label>
|
|
|
<input
|
|
|
@@ -132,25 +140,28 @@
|
|
|
value="{{ request('max_growth_value') }}"
|
|
|
placeholder="10000"
|
|
|
min="0"
|
|
|
- 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"
|
|
|
+ class="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 dark:bg-gray-800 dark:text-white transition-all"
|
|
|
>
|
|
|
</div>
|
|
|
|
|
|
- {{-- 操作按钮 --}}
|
|
|
<div class="flex items-end gap-2">
|
|
|
<button
|
|
|
type="submit"
|
|
|
- class="primary-button flex-1"
|
|
|
+ class="flex-1 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-all duration-200 flex items-center justify-center gap-2"
|
|
|
>
|
|
|
- <span class="icon-search text-lg"></span>
|
|
|
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
|
|
+ </svg>
|
|
|
搜索
|
|
|
</button>
|
|
|
|
|
|
<a
|
|
|
href="{{ route('admin.growth-value.index') }}"
|
|
|
- class="secondary-button"
|
|
|
+ class="px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition-all duration-200 flex items-center justify-center gap-2"
|
|
|
>
|
|
|
- <span class="icon-reset text-lg"></span>
|
|
|
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
|
|
+ </svg>
|
|
|
重置
|
|
|
</a>
|
|
|
</div>
|
|
|
@@ -158,90 +169,118 @@
|
|
|
</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="bg-white dark:bg-gray-900 rounded-xl 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">
|
|
|
+ <thead class="bg-gray-50 dark:bg-gray-800/50">
|
|
|
<tr>
|
|
|
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ <th class="px-6 py-4 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
客户ID
|
|
|
</th>
|
|
|
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ <th class="px-6 py-4 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
客户姓名
|
|
|
</th>
|
|
|
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ <th class="px-6 py-4 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
邮箱
|
|
|
</th>
|
|
|
- <th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ <th class="px-6 py-4 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
成长值
|
|
|
</th>
|
|
|
- <th class="px-6 py-3 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
- 等级
|
|
|
+ <th class="px-6 py-4 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ 当前等级
|
|
|
</th>
|
|
|
- <th class="px-6 py-3 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ <th class="px-6 py-4 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
首单时间
|
|
|
</th>
|
|
|
- <th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ <th class="px-6 py-4 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
+ 最后活动
|
|
|
+ </th>
|
|
|
+ <th class="px-6 py-4 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
|
操作
|
|
|
</th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
<tbody class="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-800">
|
|
|
@forelse($customers as $customer)
|
|
|
- <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">
|
|
|
+ <tr class="hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-gray-300">
|
|
|
#{{ $customer->customer_id }}
|
|
|
</td>
|
|
|
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-300">
|
|
|
- {{ $customer->customer->name ?? 'N/A' }}
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap">
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <div class="w-8 h-8 bg-gradient-to-br from-purple-400 to-purple-600 rounded-full flex items-center justify-center text-white text-sm font-medium">
|
|
|
+ {{ substr($customer->customer->name ?? 'U', 0, 1) }}
|
|
|
+ </div>
|
|
|
+ <span class="text-sm font-medium text-gray-900 dark:text-gray-300">
|
|
|
+ {{ $customer->customer->name ?? 'N/A' }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
</td>
|
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
|
|
|
{{ $customer->customer->email ?? 'N/A' }}
|
|
|
</td>
|
|
|
<td class="px-6 py-4 whitespace-nowrap text-right">
|
|
|
<div class="flex items-center justify-end gap-1">
|
|
|
- <span class="text-xl font-bold text-blue-600 dark:text-blue-500">
|
|
|
+ <span class="text-xl font-bold text-blue-600 dark:text-blue-400">
|
|
|
{{ number_format($customer->growth_value) }}
|
|
|
</span>
|
|
|
<span class="text-xs text-gray-500">分</span>
|
|
|
</div>
|
|
|
</td>
|
|
|
<td class="px-6 py-4 whitespace-nowrap text-center">
|
|
|
- @if($customer->customer && $customer->customer->group && $customer->customer->group->growth_level_name)
|
|
|
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200">
|
|
|
- {{ $customer->customer->group->growth_level_name }}
|
|
|
- </span>
|
|
|
- @else
|
|
|
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200">
|
|
|
- V0
|
|
|
- </span>
|
|
|
- @endif
|
|
|
+ @php
|
|
|
+ $levelBadge = match($customer->customer->group->growth_level_name ?? 'V0') {
|
|
|
+ 'V0' => 'bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300',
|
|
|
+ 'V1' => 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300',
|
|
|
+ 'V2' => 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300',
|
|
|
+ 'V3' => 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300',
|
|
|
+ 'V4' => 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300',
|
|
|
+ 'V5' => 'bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-300',
|
|
|
+ default => 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300',
|
|
|
+ };
|
|
|
+ @endphp
|
|
|
+ <span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium {{ $levelBadge }}">
|
|
|
+ {{ $customer->customer->group->growth_level_name ?? 'V0' }}
|
|
|
+ </span>
|
|
|
</td>
|
|
|
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400 text-center">
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400 text-center">
|
|
|
{{ $customer->first_order_completed_at ? \Carbon\Carbon::parse($customer->first_order_completed_at)->format('Y-m-d') : '-' }}
|
|
|
</td>
|
|
|
- <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400 text-center">
|
|
|
+ {{ $customer->updated_at ? \Carbon\Carbon::parse($customer->updated_at)->diffForHumans() : '-' }}
|
|
|
+ </td>
|
|
|
+ <td class="px-6 py-4 whitespace-nowrap text-right">
|
|
|
<div class="flex items-center justify-end gap-2">
|
|
|
- <a href="{{ route('admin.growth-value.show', $customer->customer_id) }}"
|
|
|
- class="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300"
|
|
|
- title="查看详情">
|
|
|
- <span class="icon-view text-lg"></span>
|
|
|
- </a>
|
|
|
- <a href="#"
|
|
|
- onclick="quickAdjust({{ $customer->customer_id }}, '{{ $customer->customer->name ?? '' }}')"
|
|
|
- class="text-green-600 hover:text-green-900 dark:text-green-400 dark:hover:text-green-300"
|
|
|
- title="快速调整">
|
|
|
- <span class="icon-edit text-lg"></span>
|
|
|
- </a>
|
|
|
+ <button
|
|
|
+ onclick="viewDetails({{ $customer->customer_id }})"
|
|
|
+ class="p-1 text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 transition-colors"
|
|
|
+ title="查看详情"
|
|
|
+ >
|
|
|
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onclick="quickAdjust({{ $customer->customer_id }}, '{{ addslashes($customer->customer->name ?? '') }}')"
|
|
|
+ class="p-1 text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-300 transition-colors"
|
|
|
+ title="快速调整"
|
|
|
+ >
|
|
|
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
</div>
|
|
|
</td>
|
|
|
</tr>
|
|
|
@empty
|
|
|
<tr>
|
|
|
- <td colspan="7" class="px-6 py-12 text-center">
|
|
|
+ <td colspan="8" 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-star text-4xl text-gray-400"></span>
|
|
|
+ <div class="w-24 h-24 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center">
|
|
|
+ <svg class="w-12 h-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>
|
|
|
+ </svg>
|
|
|
</div>
|
|
|
<div>
|
|
|
<p class="text-lg font-medium text-gray-600 dark:text-gray-400 mb-1">
|
|
|
@@ -261,60 +300,95 @@
|
|
|
|
|
|
{{-- 分页 --}}
|
|
|
@if($customers->hasPages())
|
|
|
- <div class="px-6 py-4 border-t dark:border-gray-800">
|
|
|
+ <div class="px-6 py-4 border-t border-gray-200 dark:border-gray-800">
|
|
|
{{ $customers->links() }}
|
|
|
</div>
|
|
|
@endif
|
|
|
</div>
|
|
|
|
|
|
{{-- 调整成长值模态框 --}}
|
|
|
- <div id="adjustModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center">
|
|
|
- <div class="bg-white dark:bg-cherry-900 rounded-lg shadow-xl max-w-md w-full mx-4">
|
|
|
- <div class="px-6 py-4 border-b dark:border-cherry-700">
|
|
|
- <h3 class="text-lg font-bold text-gray-900 dark:text-white">
|
|
|
- 调整成长值
|
|
|
- </h3>
|
|
|
- </div>
|
|
|
+ <div id="adjustModal" class="fixed inset-0 z-50 hidden">
|
|
|
+ <div class="absolute inset-0 bg-black bg-opacity-50 transition-opacity" onclick="closeAdjustModal()"></div>
|
|
|
+ <div class="relative min-h-screen flex items-center justify-center p-4">
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-2xl shadow-2xl max-w-lg w-full transform transition-all duration-300 scale-95 opacity-0" id="modalContent">
|
|
|
+ {{-- 模态框头部 --}}
|
|
|
+ <div class="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700 bg-gradient-to-r from-purple-50 to-white dark:from-purple-900/20 dark:to-gray-900 rounded-t-2xl">
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
+ <div class="w-10 h-10 bg-purple-100 dark:bg-purple-900/50 rounded-xl flex items-center justify-center">
|
|
|
+ <svg class="w-5 h-5 text-purple-600 dark:text-purple-400" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <h3 class="text-xl font-bold text-gray-900 dark:text-white">
|
|
|
+ 调整成长值
|
|
|
+ </h3>
|
|
|
+ </div>
|
|
|
+ <button onclick="closeAdjustModal()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
|
|
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <form id="adjustForm" method="POST" class="p-6 space-y-5">
|
|
|
+ @csrf
|
|
|
|
|
|
- <form id="adjustForm" method="POST">
|
|
|
- @csrf
|
|
|
- <div class="px-6 py-4 space-y-4">
|
|
|
{{-- 客户信息 --}}
|
|
|
<div>
|
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
- 客户
|
|
|
+ 选择客户 <span class="text-red-500">*</span>
|
|
|
</label>
|
|
|
<select
|
|
|
id="customerId"
|
|
|
name="customer_id"
|
|
|
- class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700"
|
|
|
+ class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 dark:bg-gray-800 dark:text-white transition-all"
|
|
|
required
|
|
|
>
|
|
|
<option value="">请选择客户</option>
|
|
|
- @foreach($customers as $customer)
|
|
|
- <option value="{{ $customer->customer_id }}">
|
|
|
- {{ $customer->customer->name ?? 'Unknown' }} ({{ $customer->customer->email ?? '' }})
|
|
|
+ @foreach($allCustomers as $allCustomer)
|
|
|
+ <option value="{{ $allCustomer->customer_id }}">
|
|
|
+ {{ $allCustomer->customer->name ?? 'Unknown' }} ({{ $allCustomer->customer->email ?? '' }}) - {{ number_format($allCustomer->growth_value) }}分
|
|
|
</option>
|
|
|
@endforeach
|
|
|
</select>
|
|
|
</div>
|
|
|
|
|
|
- {{-- 调整数量 --}}
|
|
|
- <div>
|
|
|
- <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
- 调整数量
|
|
|
- </label>
|
|
|
- <input
|
|
|
- type="number"
|
|
|
- name="amount"
|
|
|
- id="amount"
|
|
|
- class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700"
|
|
|
- placeholder="正数增加,负数减少(例如:100 或 -50)"
|
|
|
- required
|
|
|
- />
|
|
|
- <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
|
|
- 输入正数增加成长值,输入负数减少成长值
|
|
|
- </p>
|
|
|
+ {{-- 操作类型和数量 --}}
|
|
|
+ <div class="grid grid-cols-2 gap-4">
|
|
|
+ <div>
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
+ 操作类型 <span class="text-red-500">*</span>
|
|
|
+ </label>
|
|
|
+ <div class="flex gap-2">
|
|
|
+ <label class="flex-1 cursor-pointer">
|
|
|
+ <input type="radio" name="action" value="add" class="peer sr-only" checked onchange="updateAmountField()">
|
|
|
+ <div class="text-center px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg peer-checked:bg-purple-50 peer-checked:border-purple-500 peer-checked:text-purple-700 dark:peer-checked:bg-purple-900/30 transition-all">
|
|
|
+ <span class="text-sm font-medium">➕ 增加</span>
|
|
|
+ </div>
|
|
|
+ </label>
|
|
|
+ <label class="flex-1 cursor-pointer">
|
|
|
+ <input type="radio" name="action" value="deduct" class="peer sr-only" onchange="updateAmountField()">
|
|
|
+ <div class="text-center px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg peer-checked:bg-red-50 peer-checked:border-red-500 peer-checked:text-red-700 dark:peer-checked:bg-red-900/30 transition-all">
|
|
|
+ <span class="text-sm font-medium">➖ 减少</span>
|
|
|
+ </div>
|
|
|
+ </label>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
+ 数量 <span class="text-red-500">*</span>
|
|
|
+ </label>
|
|
|
+ <input
|
|
|
+ type="number"
|
|
|
+ name="amount"
|
|
|
+ id="amount"
|
|
|
+ min="1"
|
|
|
+ class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 dark:bg-gray-800 dark:text-white transition-all"
|
|
|
+ placeholder="输入数量"
|
|
|
+ required
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
{{-- 调整原因 --}}
|
|
|
@@ -322,95 +396,383 @@
|
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
|
调整原因
|
|
|
</label>
|
|
|
- <textarea
|
|
|
- name="description"
|
|
|
- id="description"
|
|
|
- rows="3"
|
|
|
- class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700"
|
|
|
- placeholder="请输入调整原因..."
|
|
|
- ></textarea>
|
|
|
+ <div class="relative">
|
|
|
+ <span class="absolute left-3 top-2.5 text-gray-400">📝</span>
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ name="description"
|
|
|
+ id="description"
|
|
|
+ class="w-full pl-9 pr-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 dark:bg-gray-800 dark:text-white transition-all"
|
|
|
+ placeholder="例如:管理员手动调整"
|
|
|
+ value="管理员调整"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <div class="px-6 py-4 border-t dark:border-cherry-700 flex justify-end gap-2">
|
|
|
- <button
|
|
|
- type="button"
|
|
|
- onclick="closeAdjustModal()"
|
|
|
- class="secondary-button"
|
|
|
- >
|
|
|
- 取消
|
|
|
- </button>
|
|
|
- <button
|
|
|
- type="submit"
|
|
|
- class="primary-button"
|
|
|
- >
|
|
|
- 提交
|
|
|
+ {{-- 提示信息 --}}
|
|
|
+ <div class="bg-gradient-to-r from-purple-50 to-purple-100 dark:from-purple-900/20 dark:to-purple-800/20 border-l-4 border-purple-500 rounded-lg p-3">
|
|
|
+ <div class="flex items-start gap-2">
|
|
|
+ <svg class="w-5 h-5 text-purple-500 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
|
|
|
+ </svg>
|
|
|
+ <div class="flex-1">
|
|
|
+ <p class="text-sm font-medium text-purple-800 dark:text-purple-300">
|
|
|
+ 温馨提示
|
|
|
+ </p>
|
|
|
+ <p class="text-xs text-purple-700 dark:text-purple-400 mt-0.5">
|
|
|
+ 系统会自动计算并更新会员等级
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 底部按钮 --}}
|
|
|
+ <div class="flex justify-end gap-3 pt-2">
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ onclick="closeAdjustModal()"
|
|
|
+ class="px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-all"
|
|
|
+ >
|
|
|
+ 取消
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ type="submit"
|
|
|
+ class="px-4 py-2 bg-gradient-to-r from-purple-600 to-purple-700 text-white rounded-lg hover:from-purple-700 hover:to-purple-800 transition-all shadow-md"
|
|
|
+ >
|
|
|
+ 确认调整
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {{-- 详情模态框 --}}
|
|
|
+ <div id="detailModal" class="fixed inset-0 z-50 hidden">
|
|
|
+ <div class="absolute inset-0 bg-black bg-opacity-50 transition-opacity" onclick="closeDetailModal()"></div>
|
|
|
+ <div class="relative min-h-screen flex items-center justify-center p-4">
|
|
|
+ <div class="bg-white dark:bg-gray-900 rounded-2xl shadow-2xl max-w-2xl w-full transform transition-all duration-300 scale-95 opacity-0" id="detailModalContent">
|
|
|
+ <div class="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700 bg-gradient-to-r from-blue-50 to-white dark:from-blue-900/20 dark:to-gray-900 rounded-t-2xl">
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
+ <div class="w-10 h-10 bg-blue-100 dark:bg-blue-900/50 rounded-xl flex items-center justify-center">
|
|
|
+ <svg class="w-5 h-5 text-blue-600 dark:text-blue-400" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <h3 class="text-xl font-bold text-gray-900 dark:text-white" id="detailTitle">
|
|
|
+ 会员详情
|
|
|
+ </h3>
|
|
|
+ </div>
|
|
|
+ <button onclick="closeDetailModal()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
|
|
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
|
+ </svg>
|
|
|
</button>
|
|
|
</div>
|
|
|
- </form>
|
|
|
+ <div id="detailContent" class="p-6">
|
|
|
+ <!-- 动态内容 -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
// 打开调整模态框
|
|
|
function openAdjustModal() {
|
|
|
- document.getElementById('adjustModal').classList.remove('hidden');
|
|
|
+ const modal = document.getElementById('adjustModal');
|
|
|
+ const modalContent = document.getElementById('modalContent');
|
|
|
+ modal.classList.remove('hidden');
|
|
|
+ setTimeout(() => {
|
|
|
+ modalContent.classList.remove('scale-95', 'opacity-0');
|
|
|
+ modalContent.classList.add('scale-100', 'opacity-100');
|
|
|
+ }, 10);
|
|
|
document.getElementById('adjustForm').action = '';
|
|
|
document.getElementById('customerId').value = '';
|
|
|
+ document.querySelector('input[name="action"][value="add"]').checked = true;
|
|
|
document.getElementById('amount').value = '';
|
|
|
- document.getElementById('description').value = '';
|
|
|
+ document.getElementById('description').value = '管理员调整';
|
|
|
+ updateAmountField();
|
|
|
}
|
|
|
|
|
|
// 关闭调整模态框
|
|
|
function closeAdjustModal() {
|
|
|
- document.getElementById('adjustModal').classList.add('hidden');
|
|
|
+ const modalContent = document.getElementById('modalContent');
|
|
|
+ modalContent.classList.remove('scale-100', 'opacity-100');
|
|
|
+ modalContent.classList.add('scale-95', 'opacity-0');
|
|
|
+ setTimeout(() => {
|
|
|
+ document.getElementById('adjustModal').classList.add('hidden');
|
|
|
+ }, 200);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新数量字段提示
|
|
|
+ function updateAmountField() {
|
|
|
+ const action = document.querySelector('input[name="action"]:checked');
|
|
|
+ const amountInput = document.getElementById('amount');
|
|
|
+
|
|
|
+ if (action && action.value === 'add') {
|
|
|
+ amountInput.placeholder = '输入增加的数值 (正整数)';
|
|
|
+ } else {
|
|
|
+ amountInput.placeholder = '输入减少的数值 (正整数)';
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 快速调整指定客户
|
|
|
function quickAdjust(customerId, customerName) {
|
|
|
- document.getElementById('adjustModal').classList.remove('hidden');
|
|
|
- document.getElementById('adjustForm').action = "{{ url('admin/reward-points/growth-value') }}/" + customerId + "/adjust";
|
|
|
+ openAdjustModal();
|
|
|
+ document.getElementById('adjustForm').action = "{{ url('admin/growth-value') }}/" + customerId + "/adjust";
|
|
|
document.getElementById('customerId').value = customerId;
|
|
|
- document.getElementById('amount').value = '';
|
|
|
- document.getElementById('description').value = '';
|
|
|
document.getElementById('amount').focus();
|
|
|
+ showSuccessMessage(`正在为 ${customerName} 调整成长值`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查看详情
|
|
|
+ function viewDetails(customerId) {
|
|
|
+ const modal = document.getElementById('detailModal');
|
|
|
+ const modalContent = document.getElementById('detailModalContent');
|
|
|
+ modal.classList.remove('hidden');
|
|
|
+ setTimeout(() => {
|
|
|
+ modalContent.classList.remove('scale-95', 'opacity-0');
|
|
|
+ modalContent.classList.add('scale-100', 'opacity-100');
|
|
|
+ }, 10);
|
|
|
+
|
|
|
+ fetch(`{{ url('admin/growth-value') }}/${customerId}/detail`)
|
|
|
+ .then(response => response.json())
|
|
|
+ .then(data => {
|
|
|
+ if (data.success) {
|
|
|
+ document.getElementById('detailContent').innerHTML = `
|
|
|
+ <div class="space-y-4">
|
|
|
+ <div class="flex items-center gap-4 p-4 bg-gradient-to-r from-purple-50 to-blue-50 dark:from-purple-900/20 dark:to-blue-900/20 rounded-xl">
|
|
|
+ <div class="w-16 h-16 bg-gradient-to-br from-purple-400 to-purple-600 rounded-full flex items-center justify-center text-white text-2xl font-bold">
|
|
|
+ ${data.customer.name ? data.customer.name.charAt(0) : 'U'}
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <h4 class="text-lg font-bold text-gray-900 dark:text-white">${data.customer.name || 'N/A'}</h4>
|
|
|
+ <p class="text-sm text-gray-600 dark:text-gray-400">${data.customer.email || 'N/A'}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="grid grid-cols-2 gap-4">
|
|
|
+ <div class="text-center p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg">
|
|
|
+ <p class="text-sm text-gray-600 dark:text-gray-400">当前成长值</p>
|
|
|
+ <p class="text-2xl font-bold text-blue-600 dark:text-blue-400">${formatNumber(data.growth_value)} 分</p>
|
|
|
+ </div>
|
|
|
+ <div class="text-center p-3 bg-purple-50 dark:bg-purple-900/20 rounded-lg">
|
|
|
+ <p class="text-sm text-gray-600 dark:text-gray-400">当前等级</p>
|
|
|
+ <p class="text-2xl font-bold text-purple-600 dark:text-purple-400">${data.level_name || 'V0'}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ ${data.growth_logs && data.growth_logs.length > 0 ? `
|
|
|
+ <div>
|
|
|
+ <h5 class="font-medium text-gray-900 dark:text-white mb-3">成长值变动记录</h5>
|
|
|
+ <div class="space-y-2 max-h-64 overflow-y-auto">
|
|
|
+ ${data.growth_logs.map(log => `
|
|
|
+ <div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg">
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <span class="text-sm ${log.amount > 0 ? 'text-green-600' : 'text-red-600'} font-medium">
|
|
|
+ ${log.amount > 0 ? '+' : ''}${log.amount}
|
|
|
+ </span>
|
|
|
+ <span class="text-sm text-gray-600 dark:text-gray-400">${log.description || '系统调整'}</span>
|
|
|
+ </div>
|
|
|
+ <span class="text-xs text-gray-500">${log.created_at}</span>
|
|
|
+ </div>
|
|
|
+ `).join('')}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ` : '<p class="text-center text-gray-500 py-4">暂无变动记录</p>'}
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+ } else {
|
|
|
+ document.getElementById('detailContent').innerHTML = `
|
|
|
+ <div class="text-center py-8 text-red-500">
|
|
|
+ 加载失败,请重试
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error('Error:', error);
|
|
|
+ document.getElementById('detailContent').innerHTML = `
|
|
|
+ <div class="text-center py-8 text-red-500">
|
|
|
+ 加载失败,请重试
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 关闭详情模态框
|
|
|
+ function closeDetailModal() {
|
|
|
+ const modalContent = document.getElementById('detailModalContent');
|
|
|
+ modalContent.classList.remove('scale-100', 'opacity-100');
|
|
|
+ modalContent.classList.add('scale-95', 'opacity-0');
|
|
|
+ setTimeout(() => {
|
|
|
+ document.getElementById('detailModal').classList.add('hidden');
|
|
|
+ }, 200);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化数字
|
|
|
+ function formatNumber(num) {
|
|
|
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
|
}
|
|
|
|
|
|
// 表单提交
|
|
|
document.getElementById('adjustForm').addEventListener('submit', function(e) {
|
|
|
e.preventDefault();
|
|
|
|
|
|
- const formData = new FormData(this);
|
|
|
- const action = this.action;
|
|
|
+ const customerId = document.getElementById('customerId').value;
|
|
|
+ if (!customerId) {
|
|
|
+ showErrorMessage('请选择客户');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- fetch(action, {
|
|
|
+ const amount = parseInt(document.getElementById('amount').value);
|
|
|
+ if (!amount || amount <= 0) {
|
|
|
+ showErrorMessage('请输入有效的数量');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const action = document.querySelector('input[name="action"]:checked').value;
|
|
|
+ let finalAmount = amount;
|
|
|
+ if (action === 'deduct') {
|
|
|
+ finalAmount = -Math.abs(amount);
|
|
|
+ }
|
|
|
+
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('_token', '{{ csrf_token() }}');
|
|
|
+ formData.append('customer_id', customerId);
|
|
|
+ formData.append('amount', finalAmount);
|
|
|
+ formData.append('description', document.getElementById('description').value);
|
|
|
+
|
|
|
+ const action_url = this.action || "{{ route('admin.growth-value.adjust') }}";
|
|
|
+
|
|
|
+ fetch(action_url, {
|
|
|
method: 'POST',
|
|
|
body: formData,
|
|
|
headers: {
|
|
|
- 'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
|
+ 'X-Requested-With': 'XMLHttpRequest'
|
|
|
}
|
|
|
})
|
|
|
- .then(response => {
|
|
|
- if (response.ok || response.redirected) {
|
|
|
- alert('调整成功!');
|
|
|
- location.reload();
|
|
|
+ .then(response => response.json())
|
|
|
+ .then(data => {
|
|
|
+ if (data.success) {
|
|
|
+ showSuccessMessage(data.message || '成长值调整成功!');
|
|
|
+ closeAdjustModal();
|
|
|
+ setTimeout(() => {
|
|
|
+ location.reload();
|
|
|
+ }, 1500);
|
|
|
} else {
|
|
|
- return response.text().then(text => {
|
|
|
- throw new Error(text);
|
|
|
- });
|
|
|
+ showErrorMessage(data.message || '调整失败,请重试');
|
|
|
}
|
|
|
})
|
|
|
.catch(error => {
|
|
|
console.error('Error:', error);
|
|
|
- alert('调整失败:' + error.message);
|
|
|
+ showErrorMessage('网络错误,请重试');
|
|
|
});
|
|
|
});
|
|
|
|
|
|
- // 点击模态框外部关闭
|
|
|
- document.getElementById('adjustModal').addEventListener('click', function(e) {
|
|
|
- if (e.target === this) {
|
|
|
- closeAdjustModal();
|
|
|
+ // 显示成功消息
|
|
|
+ function showSuccessMessage(message) {
|
|
|
+ const toast = document.createElement('div');
|
|
|
+ toast.className = 'fixed top-20 right-4 bg-green-500 text-white px-5 py-3 rounded-lg shadow-lg z-50 flex items-center gap-2 animate-fade-in';
|
|
|
+ toast.innerHTML = `
|
|
|
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
|
|
+ </svg>
|
|
|
+ <span>${message}</span>
|
|
|
+ `;
|
|
|
+ document.body.appendChild(toast);
|
|
|
+ setTimeout(() => toast.remove(), 3000);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示错误消息
|
|
|
+ function showErrorMessage(message) {
|
|
|
+ const toast = document.createElement('div');
|
|
|
+ toast.className = 'fixed top-20 right-4 bg-red-500 text-white px-5 py-3 rounded-lg shadow-lg z-50 flex items-center gap-2 animate-fade-in';
|
|
|
+ toast.innerHTML = `
|
|
|
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
|
|
+ </svg>
|
|
|
+ <span>${message}</span>
|
|
|
+ `;
|
|
|
+ document.body.appendChild(toast);
|
|
|
+ setTimeout(() => toast.remove(), 3000);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ESC 键关闭模态框
|
|
|
+ document.addEventListener('keydown', function(e) {
|
|
|
+ if (e.key === 'Escape') {
|
|
|
+ if (!document.getElementById('adjustModal').classList.contains('hidden')) {
|
|
|
+ closeAdjustModal();
|
|
|
+ }
|
|
|
+ if (!document.getElementById('detailModal').classList.contains('hidden')) {
|
|
|
+ closeDetailModal();
|
|
|
+ }
|
|
|
}
|
|
|
});
|
|
|
</script>
|
|
|
+
|
|
|
+ <style>
|
|
|
+ @keyframes fade-in {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(-10px);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .animate-fade-in {
|
|
|
+ animation: fade-in 0.3s ease-out;
|
|
|
+ }
|
|
|
+
|
|
|
+ .scale-95 {
|
|
|
+ transform: scale(0.95);
|
|
|
+ }
|
|
|
+
|
|
|
+ .scale-100 {
|
|
|
+ transform: scale(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ .opacity-0 {
|
|
|
+ opacity: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .opacity-100 {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .transition-all {
|
|
|
+ transition: all 0.2s ease;
|
|
|
+ }
|
|
|
+
|
|
|
+ .duration-300 {
|
|
|
+ transition-duration: 300ms;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ease-out {
|
|
|
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 滚动条美化 */
|
|
|
+ ::-webkit-scrollbar {
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar-track {
|
|
|
+ background: #f1f1f1;
|
|
|
+ border-radius: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar-thumb {
|
|
|
+ background: #c1c1c1;
|
|
|
+ border-radius: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar-thumb:hover {
|
|
|
+ background: #a8a8a8;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
</x-admin::layouts>
|