bianjunhui 1 週間 前
コミット
cf9654d311

+ 2 - 0
packages/Longyi/RewardPoints/README.md

@@ -25,6 +25,8 @@ php artisan migrate
 
 ### 3. 初始化默认设置
 php artisan reward-points:init-settings
+php artisan reward-points:init-growth-settings
+
 ### 4. 清理缓存
 php artisan cache:clear      # 清除应用缓存
 php artisan config:clear     # 清除配置缓存

+ 14 - 4
packages/Longyi/RewardPoints/src/Console/Commands/InitializeGrowthSettings.php

@@ -168,6 +168,16 @@ class InitializeGrowthSettings extends Command
             $this->warn('Growth value menu items already exist in dynamic menu.');
             return;
         }
+        // 创建父级菜单项
+        $parentItem = MenuItem::create([
+            'name' => '用户管理',
+            'key' => 'customers',
+            'route' => 'admin.customers.customers.index',
+            'icon' => 'icon-customer',
+            'sort_order' => 10,
+            'status' => 1,
+            'created_by' => 1,
+        ]);
 
         // 创建子菜单项
         $childItems = [
@@ -176,21 +186,21 @@ class InitializeGrowthSettings extends Command
                 'key' => 'customers.growth-value',
                 'route' => 'admin.growth-value.index',
                 'icon' => 'icon-users',
-                'sort_order' => 4,
+                'sort_order' => 5,
             ],
             [
                 'name' => '会员成长值记录',
                 'key' => 'customers.growth-history',
                 'route' => 'admin.growth-value.history',
                 'icon' => 'icon-list',
-                'sort_order' => 5,
+                'sort_order' => 6,
             ],
             [
                 'name' => '成长值设置',
                 'key' => 'customers.growth-settings',
                 'route' => 'admin.growth-value.settings',
                 'icon' => 'icon-setting',
-                'sort_order' => 6,
+                'sort_order' => 7,
             ],
         ];
 
@@ -201,7 +211,7 @@ class InitializeGrowthSettings extends Command
                 'route' => $item['route'],
                 'icon' => $item['icon'],
                 'sort_order' => $item['sort_order'],
-                'parent_id' => 999,
+                'parent_id' => $parentItem->id,
                 'status' => 1,
                 'created_by' => 1,
             ]);

+ 152 - 33
packages/Longyi/RewardPoints/src/Http/Controllers/Admin/GrowthValueController.php

@@ -5,18 +5,24 @@ namespace Longyi\RewardPoints\Http\Controllers\Admin;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Validator;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+use Carbon\Carbon;
 use Longyi\RewardPoints\Repositories\RewardPointSettingRepository;
 use Longyi\RewardPoints\Services\GrowthValueService;
 use Longyi\RewardPoints\Models\GrowthValueCustomer;
 use Longyi\RewardPoints\Models\GrowthValueHistory;
 use Longyi\RewardPoints\Models\GrowthValueLevel;
 use Webkul\Admin\Http\Controllers\Controller;
+use Webkul\Customer\Models\Customer;
+use Webkul\Customer\Models\CustomerGroup;
 
 class GrowthValueController extends Controller
 {
     protected $growthValueService;
+    protected $settingRepository;
 
-    public function __construct(GrowthValueService $growthValueService,RewardPointSettingRepository $settingRepository)
+    public function __construct(GrowthValueService $growthValueService, RewardPointSettingRepository $settingRepository)
     {
         $this->growthValueService = $growthValueService;
         $this->settingRepository = $settingRepository;
@@ -65,12 +71,6 @@ class GrowthValueController extends Controller
         $totalGrowthValue = GrowthValueCustomer::sum('growth_value') ?? 0;
         $avgGrowthValue = $totalCustomers > 0 ? round($totalGrowthValue / $totalCustomers, 2) : 0;
         $firstOrderCount = GrowthValueCustomer::whereNotNull('first_order_completed_at')->count();
-
-        // 所有客户列表(用于模态框下拉)
-        $allCustomers = GrowthValueCustomer::with('customer')
-            ->orderBy('growth_value', 'desc')
-            ->get();
-
         $view = $this->_config['view'] ?? 'rewardpoints::admin.growth-value.index';
 
         return view($view, compact(
@@ -78,8 +78,7 @@ class GrowthValueController extends Controller
             'totalCustomers',
             'totalGrowthValue',
             'avgGrowthValue',
-            'firstOrderCount',
-            'allCustomers'
+            'firstOrderCount'
         ));
     }
 
@@ -94,6 +93,7 @@ class GrowthValueController extends Controller
 
         return view('rewardpoints::admin.growth-value.settings', compact('groups', 'currentGroup', 'settings', 'groupData'));
     }
+
     /**
      * 保存配置
      */
@@ -123,6 +123,7 @@ class GrowthValueController extends Controller
             return redirect()->back()->withInput();
         }
     }
+
     /**
      * 获取分组数据(包含名称和排序)
      */
@@ -137,7 +138,7 @@ class GrowthValueController extends Controller
         foreach ($groups as $group) {
             $groupData[$group] = [
                 'name' => $this->getGroupName($group),
-                'order' => $groupOrder[$group] ?? 99, // 如果未定义顺序,默认排在最后
+                'order' => $groupOrder[$group] ?? 99,
             ];
         }
 
@@ -148,6 +149,7 @@ class GrowthValueController extends Controller
 
         return $groupData;
     }
+
     /**
      * 获取分组名称
      */
@@ -158,6 +160,7 @@ class GrowthValueController extends Controller
         ];
         return $names[$group] ?? ucfirst($group);
     }
+
     /**
      * 显示某个会员的成长值详情
      */
@@ -167,49 +170,165 @@ class GrowthValueController extends Controller
         $history = GrowthValueHistory::where('customer_id', $customerId)
             ->orderBy('created_at', 'desc')
             ->paginate(20);
-        $customer = \Webkul\Customer\Models\Customer::find($customerId);
+        $customer = Customer::find($customerId);
 
         return view('rewardpoints::admin.growth-value.show', compact('growthValueInfo', 'history', 'customer'));
     }
 
     /**
-     * 手动调整会员成长值(从列表页弹窗调用
+     * 从列表页调整成长值(使用 Eloquent Model
      */
     public function adjustFromList()
     {
-        $validator = Validator::make(request()->all(), [
-            'customer_id' => 'required|exists:customers,id',
-            'action' => 'required|in:add,deduct',
-            'amount' => 'required|integer|min:1',
-            'description' => 'nullable|string|max:255',
-        ]);
-
-        if ($validator->fails()) {
-            return redirect()->back()->withErrors($validator)->withInput();
-        }
-
         try {
-            $customerId = request('customer_id');
+            $identifier = request('customer_identifier');
             $amount = request('amount');
+            $description=request('description', '管理员调整');
+            $customer = null;
+
+            if (filter_var($identifier, FILTER_VALIDATE_EMAIL)) {
+                $customer = \Webkul\Customer\Models\Customer::where('email', $identifier)->first();
+            } elseif (is_numeric($identifier)) {
+                $customer = \Webkul\Customer\Models\Customer::find((int)$identifier);
+            }
+
+            if (!$customer) {
+                return response()->json([
+                    'success' => false,
+                    'message' => '未找到该客户,请检查邮箱或ID是否正确'
+                ], 404);
+            }
 
-            // 如果是减少操作,将金额转为负数
+            $customerId = $customer->id;
             if (request('action') === 'deduct') {
                 $amount = -$amount;
             }
+            DB::beginTransaction();
+
+            // 使用 Eloquent Model 获取成长值记录(带锁)
+            $growthValue = GrowthValueCustomer::where('customer_id', $customerId)
+                ->lockForUpdate()
+                ->first();
+
+            $oldValue = $growthValue ? $growthValue->growth_value : 0;
+            $newValue = max(0, $oldValue + $amount);
+            $oldLevel = $growthValue ? $growthValue->growth_level : 'V0';
+
+            // 计算新等级
+            $newLevel = $this->calculateLevel($newValue);
+            $levelChanged = ($oldLevel !== $newLevel);
+
+            // 获取对应的客户组ID
+            $newCustomerGroupId = $this->getCustomerGroupIdByLevel($newLevel);
+            $oldCustomerGroupId = null;
+
+            if ($growthValue) {
+                // 获取旧的客户组ID
+                $customer = Customer::find($customerId);
+                $oldCustomerGroupId = $customer ? $customer->customer_group_id : null;
+
+                // 使用 Eloquent Model 更新现有记录
+                $growthValue->growth_value = $newValue;
+                if ($levelChanged) {
+                    $growthValue->growth_level = $newLevel;
+                    $growthValue->level_updated_at = Carbon::now();
+                }
+                $growthValue->updated_at = Carbon::now();
+                $growthValue->save();
+            } else {
+                // 使用 Eloquent Model 创建新记录
+                $growthValue = GrowthValueCustomer::create([
+                    'customer_id' => $customerId,
+                    'growth_value' => $newValue,
+                    'growth_level' => $newLevel,
+                    'level_updated_at' => $levelChanged ? Carbon::now() : null,
+                    'created_at' => Carbon::now(),
+                    'updated_at' => Carbon::now(),
+                ]);
+            }
+
+            // 如果等级发生变化,更新用户表的 customer_group_id
+            if ($levelChanged && $newCustomerGroupId) {
+                Customer::where('id', $customerId)->update([
+                    'customer_group_id' => $newCustomerGroupId,
+                    'updated_at' => Carbon::now(),
+                ]);
+            }
 
-            $this->growthValueService->adjustGrowthValue(
-                $customerId,
-                $amount,
-                request('description', '管理员调整')
-            );
+            // 使用 Eloquent Model 记录历史
+            GrowthValueHistory::create([
+                'customer_id' => $customerId,
+                'order_id' => null,
+                'order_amount' => 0,
+                'growth_value_earned' => $amount,
+                'total_growth_value' => $newValue,
+                'level_before' => $levelChanged ? $oldLevel : null,
+                'level_after' => $levelChanged ? $newLevel : null,
+                'event_type' => 'admin_adjust',
+                'description' => $description,
+                'created_at' => Carbon::now(),
+            ]);
+
+            DB::commit();
+
+            return response()->json([
+                'success' => true,
+                'message' => '成长值调整成功',
+                'new_value' => $newValue,
+                'new_level' => $newLevel,
+                'level_changed' => $levelChanged,
+                'old_group_id' => $oldCustomerGroupId,
+                'new_group_id' => $newCustomerGroupId,
+            ]);
 
-            session()->flash('success', '成长值调整成功');
         } catch (\Exception $e) {
-            session()->flash('error', '调整失败:' . $e->getMessage());
+            DB::rollBack();
+            Log::error('成长值调整失败:' . $e->getMessage());
+
+            return response()->json([
+                'success' => false,
+                'message' => '调整失败:' . $e->getMessage(),
+            ], 500);
+        }
+    }
+
+    /**
+     * 根据等级名称获取对应的客户组ID
+     */
+    private function getCustomerGroupIdByLevel($levelName)
+    {
+        // 根据等级名称查找对应的客户组
+        $customerGroup = CustomerGroup::where('growth_level_name', $levelName)->first();
+
+        if ($customerGroup) {
+            return $customerGroup->id;
         }
 
-        return redirect()->route('admin.growth-value.index');
+        // 如果没有找到,尝试根据 code 查找
+        $customerGroup = CustomerGroup::where('code', strtolower($levelName))->first();
+
+        if ($customerGroup) {
+            return $customerGroup->id;
+        }
+
+        // 默认返回 general 组
+        $defaultGroup = CustomerGroup::where('code', 'general')->first();
+        return $defaultGroup ? $defaultGroup->id : null;
     }
 
+    /**
+     * 根据成长值计算等级(使用 Eloquent Model)
+     */
+    private function calculateLevel($growthValue)
+    {
+        // 使用 Eloquent Model 查询等级配置
+        $level = CustomerGroup::where('min_growth_value', '<=', $growthValue)
+            ->orderBy('min_growth_value', 'desc')
+            ->first();
 
+        if ($level && $level->growth_level_name) {
+            return $level->growth_level_name;
+        }
+        return 'V0';
+    }
 }

+ 4 - 0
packages/Longyi/RewardPoints/src/Http/Controllers/Admin/SettingController.php

@@ -79,6 +79,9 @@ class SettingController extends Controller
 
         $groupData = [];
         foreach ($groups as $group) {
+            if($group=='growth_value'){
+                continue;
+            }
             $groupData[$group] = [
                 'name' => $this->getGroupName($group),
                 'order' => $groupOrder[$group] ?? 99, // 如果未定义顺序,默认排在最后
@@ -100,6 +103,7 @@ class SettingController extends Controller
     {
         $names = [
             'general' => '通用设置',
+            'sign_in' => '签到',
         ];
         return $names[$group] ?? ucfirst($group);
     }

+ 39 - 19
packages/Longyi/RewardPoints/src/Http/Controllers/RewardPointsController.php

@@ -61,7 +61,7 @@ class RewardPointsController extends Controller
         if ($lastSign) {
             $lastSignDate = Carbon::parse($lastSign->sign_date);
             $yesterday = Carbon::yesterday();
-            
+
             if ($lastSignDate->toDateString() === $yesterday->toDateString()) {
                 $countDate = $lastSign->count_date + 1;
             } elseif ($lastSignDate->toDateString() !== $today) {
@@ -73,15 +73,10 @@ class RewardPointsController extends Controller
             ->where('status', 1)
             ->first();
 
-        $basePoints = config('rewardpoints.sign_in.base_points', 10);
-        $points = $rule ? $rule->reward_point : $basePoints;
-
-        if ($countDate % 30 == 0) {
-            $bonusPoints = config('rewardpoints.sign_in.month_bonus_points', 100);
-            $points += $bonusPoints;
-        } elseif ($countDate % 7 == 0) {
-            $bonusPoints = config('rewardpoints.sign_in.week_bonus_points', 20);
-            $points += $bonusPoints;
+        if ($rule) {
+            $points = $rule->reward_point;
+        } else {
+            $points = $this->getSignInPointsByDay($countDate);
         }
 
         $sign = RewardPointCustomerSign::create([
@@ -99,7 +94,7 @@ class RewardPointsController extends Controller
             RewardActiveRule::TYPE_SIGN_IN,
             $points,
             null,
-            "Daily sign-in bonus (Day {$countDate})"
+            "每日签到奖励(第 {$countDate} 天)"
         );
 
         return response()->json([
@@ -109,6 +104,31 @@ class RewardPointsController extends Controller
             'total_points' => $this->rewardPointRepository->getCustomerPoints($customer->id)
         ]);
     }
+
+    /**
+     * 根据签到天数获取对应的积分
+     */
+    protected function getSignInPointsByDay($day)
+    {
+        $settingRepository = app(\Longyi\RewardPoints\Repositories\RewardPointSettingRepository::class);
+
+        $dayPointsMap = [
+            1 => $settingRepository->getConfigValue('signin_day1_points', 10),
+            2 => $settingRepository->getConfigValue('signin_day2_points', 10),
+            3 => $settingRepository->getConfigValue('signin_day3_points', 15),
+            4 => $settingRepository->getConfigValue('signin_day4_points', 25),
+            5 => $settingRepository->getConfigValue('signin_day5_points', 50),
+            6 => $settingRepository->getConfigValue('signin_day6_points', 70),
+            7 => $settingRepository->getConfigValue('signin_day7_points', 70),
+        ];
+
+        if ($day <= 7) {
+            return (int) $dayPointsMap[$day];
+        }
+
+        return (int) $settingRepository->getConfigValue('signin_day8_plus_points', 70);
+    }
+
     public function getSignStatus()
     {
         $customer = auth()->guard('customer')->user();
@@ -139,29 +159,29 @@ class RewardPointsController extends Controller
     public function applyPoints(Request $request)
     {
         $points = $request->input('points', 0);
-        
+
         $cartRewardPoints = app('cartrewardpoints');
         $validation = $cartRewardPoints->validatePoints($points);
-        
+
         if ($validation !== true) {
             return response()->json([
                 'success' => false,
                 'message' => $validation
             ], 400);
         }
-        
+
         $result = $cartRewardPoints->applyPoints($points);
-        
+
         if ($result) {
             $discountDetails = $cartRewardPoints->getDiscountDetails();
-            
+
             return response()->json([
                 'success' => true,
                 'message' => 'Reward points applied successfully',
                 'discount' => $discountDetails
             ]);
         }
-        
+
         return response()->json([
             'success' => false,
             'message' => 'Failed to apply reward points'
@@ -175,7 +195,7 @@ class RewardPointsController extends Controller
     {
         $cartRewardPoints = app('cartrewardpoints');
         $cartRewardPoints->removePoints();
-        
+
         return response()->json([
             'success' => true,
             'message' => 'Reward points removed successfully'
@@ -188,7 +208,7 @@ class RewardPointsController extends Controller
     public function getPointsInfo()
     {
         $cartRewardPoints = app('cartrewardpoints');
-        
+
         return response()->json([
             'available_points' => $cartRewardPoints->getAvailablePoints(),
             'points_used' => $cartRewardPoints->getPointsUsed(),

+ 0 - 103
packages/Longyi/RewardPoints/src/Models/GrowthValueLevel.php

@@ -1,103 +0,0 @@
-<?php
-
-namespace Longyi\RewardPoints\Models;
-
-use Illuminate\Database\Eloquent\Model;
-
-/**
- * 成长值等级配置模型
- * 用于操作 ly_customer_groups 表中的成长值相关字段
- */
-class GrowthValueLevel extends Model
-{
-    protected $table = 'customer_groups';
-
-    // 只选择需要的字段
-    protected $fillable = [
-        'min_growth_value',
-        'require_first_order',
-        'growth_level_name',
-        'growth_discount_rate',
-        'growth_benefits',
-        'growth_level_icon',
-    ];
-
-    protected $casts = [
-        'min_growth_value' => 'integer',
-        'require_first_order' => 'boolean',
-        'growth_discount_rate' => 'integer',
-    ];
-
-    public $timestamps = false;
-
-    /**
-     * 获取 benefits 属性
-     */
-    public function getGrowthBenefitsAttribute($value)
-    {
-        return $value ? json_decode($value, true) : [];
-    }
-
-    /**
-     * 设置 benefits 属性
-     */
-    public function setGrowthBenefitsAttribute($value)
-    {
-        $this->attributes['growth_benefits'] = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
-    }
-
-    /**
-     * 根据成长值和首单状态获取对应的会员组
-     */
-    public static function getLevelByGrowthValue($growthValue, $hasFirstOrder = false)
-    {
-        $groups = self::whereNotNull('min_growth_value')
-            ->orderBy('min_growth_value', 'desc')
-            ->get();
-
-        foreach ($groups as $group) {
-            if ($group->require_first_order && !$hasFirstOrder) {
-                continue;
-            }
-
-            if ($growthValue >= $group->min_growth_value) {
-                return $group;
-            }
-        }
-
-        // 默认返回 general 组
-        return self::where('code', 'general')->first();
-    }
-
-    /**
-     * 获取下一个等级
-     */
-    public static function getNextLevel($currentGroupId, $hasFirstOrder = false)
-    {
-        $currentGroup = self::find($currentGroupId);
-
-        if (!$currentGroup || !$currentGroup->min_growth_value) {
-            return null;
-        }
-
-        return self::whereNotNull('min_growth_value')
-            ->where('min_growth_value', '>', $currentGroup->min_growth_value)
-            ->where(function($query) use ($hasFirstOrder) {
-                if (!$hasFirstOrder) {
-                    $query->where('require_first_order', false);
-                }
-            })
-            ->orderBy('min_growth_value', 'asc')
-            ->first();
-    }
-
-    /**
-     * 获取所有配置了成长值的会员组
-     */
-    public static function getAllGrowthLevels()
-    {
-        return self::whereNotNull('min_growth_value')
-            ->orderBy('min_growth_value')
-            ->get();
-    }
-}

+ 99 - 16
packages/Longyi/RewardPoints/src/Repositories/RewardPointSettingRepository.php

@@ -11,7 +11,7 @@ class RewardPointSettingRepository extends Repository
     {
         return RewardPointSetting::class;
     }
-    
+
     /**
      * 获取所有配置分组
      */
@@ -23,7 +23,7 @@ class RewardPointSettingRepository extends Repository
             ->pluck('group')
             ->toArray();
     }
-    
+
     /**
      * 按分组获取配置
      */
@@ -35,21 +35,21 @@ class RewardPointSettingRepository extends Repository
             ->orderBy('sort_order')
             ->get();
     }
-    
+
     /**
      * 获取配置值
      */
     public function getConfigValue($code, $default = null)
     {
         $setting = $this->findOneByField('code', $code);
-        
+
         if (!$setting) {
             return $default;
         }
-        
+
         return $this->castValue($setting->value, $setting->type);
     }
-    
+
     /**
      * 批量获取配置值
      */
@@ -59,15 +59,15 @@ class RewardPointSettingRepository extends Repository
             ->whereIn('code', $codes)
             ->where('is_enabled', true)
             ->get();
-        
+
         $result = [];
         foreach ($settings as $setting) {
             $result[$setting->code] = $this->castValue($setting->value, $setting->type);
         }
-        
+
         return $result;
     }
-    
+
     /**
      * 设置配置值
      */
@@ -78,7 +78,7 @@ class RewardPointSettingRepository extends Repository
             ['value' => $value]
         );
     }
-    
+
     /**
      * 批量设置配置值
      */
@@ -88,7 +88,7 @@ class RewardPointSettingRepository extends Repository
             $this->setConfigValue($code, $value);
         }
     }
-    
+
     /**
      * 类型转换
      */
@@ -97,7 +97,7 @@ class RewardPointSettingRepository extends Repository
         if ($value === null) {
             return null;
         }
-        
+
         switch ($type) {
             case 'boolean':
                 return (bool) $value;
@@ -107,14 +107,14 @@ class RewardPointSettingRepository extends Repository
                 return $value;
         }
     }
-    
+
     /**
      * 初始化默认配置
      */
     public function initializeDefaultSettings()
     {
         $defaultSettings = $this->getDefaultSettings();
-        
+
         foreach ($defaultSettings as $setting) {
             $this->model->firstOrCreate(
                 ['code' => $setting['code']],
@@ -122,7 +122,7 @@ class RewardPointSettingRepository extends Repository
             );
         }
     }
-    
+
     /**
      * 获取默认配置列表
      */
@@ -166,6 +166,89 @@ class RewardPointSettingRepository extends Repository
                 'sort_order' => 4,
                 'description' => '最低可使用的积分数量'
             ],
+
+            // 签到设置
+            [
+                'code' => 'signin_day1_points',
+                'name' => '第一天签到积分',
+                'value' => '10',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 1,
+                'description' => '连续签到第1天获得的积分'
+            ],
+            [
+                'code' => 'signin_day2_points',
+                'name' => '第二天签到积分',
+                'value' => '10',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 2,
+                'description' => '连续签到第2天获得的积分'
+            ],
+            [
+                'code' => 'signin_day3_points',
+                'name' => '第三天签到积分',
+                'value' => '15',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 3,
+                'description' => '连续签到第3天获得的积分'
+            ],
+            [
+                'code' => 'signin_day4_points',
+                'name' => '第四天签到积分',
+                'value' => '25',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 4,
+                'description' => '连续签到第4天获得的积分'
+            ],
+            [
+                'code' => 'signin_day5_points',
+                'name' => '第五天签到积分',
+                'value' => '50',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 5,
+                'description' => '连续签到第5天获得的积分'
+            ],
+            [
+                'code' => 'signin_day6_points',
+                'name' => '第六天签到积分',
+                'value' => '70',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 6,
+                'description' => '连续签到第6天获得的积分'
+            ],
+            [
+                'code' => 'signin_day7_points',
+                'name' => '第七天签到积分',
+                'value' => '70',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 7,
+                'description' => '连续签到第7天获得的积分'
+            ],
+            [
+                'code' => 'signin_day8_plus_points',
+                'name' => '第八天及以后签到积分',
+                'value' => '70',
+                'type' => 'number',
+                'group' => 'sign_in',
+                'sort_order' => 8,
+                'description' => '连续签到第8天及以后每天获得的积分'
+            ],
+            [
+                'code' => 'signin_enabled',
+                'name' => '启用签到功能',
+                'value' => '1',
+                'type' => 'boolean',
+                'group' => 'sign_in',
+                'sort_order' => 9,
+                'description' => '是否启用每日签到功能'
+            ],
         ];
     }
-}
+}

+ 6 - 18
packages/Longyi/RewardPoints/src/Resources/views/admin/growth-value/index.blade.php

@@ -204,13 +204,6 @@
         {{-- 使用原生 alert 确认框代替复杂模态框 --}}
         <script>
             function openAdjustModal() {
-                // 获取客户列表用于选择
-                let customerOptions = '';
-                @foreach($allCustomers as $allCustomer)
-                    customerOptions += `<option value="{{ $allCustomer->customer_id }}">{{ addslashes($allCustomer->customer->name ?? 'Unknown') }} ({{ $allCustomer->customer->email ?? '' }}) - {{ $allCustomer->growth_value }}分</option>`;
-                @endforeach
-
-                // 创建简单但完整的模态框
                 const modalHtml = `
                 <div id="simpleModal" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:99999;display:flex;align-items:center;justify-content:center;">
                     <div style="background:white;border-radius:12px;width:450px;max-width:90%;padding:20px;box-shadow:0 20px 25px -5px rgba(0,0,0,0.1);">
@@ -221,11 +214,9 @@
                         <form id="simpleAdjustForm">
                             <input type="hidden" name="_token" value="{{ csrf_token() }}">
                             <div style="margin-bottom:15px;">
-                                <label style="display:block;font-size:14px;font-weight:500;margin-bottom:5px;color:#374151;">选择客户 *</label>
-                                <select name="customer_id" id="simpleCustomerId" style="width:100%;padding:8px 12px;border:1px solid #d1d5db;border-radius:8px;" required>
-                                    <option value="">请选择客户</option>
-                                    ${customerOptions}
-                                </select>
+                                <label style="display:block;font-size:14px;font-weight:500;margin-bottom:5px;color:#374151;">客户邮箱或ID *</label>
+                                <input type="text" name="customer_identifier" id="simpleCustomerId" style="width:100%;padding:8px 12px;border:1px solid #d1d5db;border-radius:8px;" required placeholder="输入客户邮箱或ID">
+                                <p style="font-size:12px;color:#6b7280;margin-top:5px;">可以直接输入客户邮箱地址或客户ID</p>
                             </div>
                             <div style="margin-bottom:15px;">
                                 <label style="display:block;font-size:14px;font-weight:500;margin-bottom:5px;color:#374151;">操作类型 *</label>
@@ -260,9 +251,6 @@
                 document.getElementById('simpleAdjustForm').addEventListener('submit', function(e) {
                     e.preventDefault();
                     const formData = new FormData(this);
-                    let amount = parseInt(formData.get('amount'));
-                    const action = formData.get('action');
-                    if (action === 'deduct') amount = -amount;
 
                     fetch('{{ route("admin.growth-value.adjust-from-list") }}', {
                         method: 'POST',
@@ -291,7 +279,6 @@
             }
 
             function quickAdjust(customerId, customerName) {
-                // 快速调整:直接使用确认框
                 const amount = prompt(`为 ${customerName} 调整成长值\n输入正数表示增加,负数表示减少`, "100");
                 if (amount === null) return;
 
@@ -303,7 +290,7 @@
 
                 const formData = new FormData();
                 formData.append('_token', '{{ csrf_token() }}');
-                formData.append('customer_id', customerId);
+                formData.append('customer_identifier', customerId);
                 formData.append('amount', finalAmount);
                 formData.append('description', '管理员快速调整');
 
@@ -327,7 +314,7 @@
             }
 
             function viewDetails(customerId) {
-                fetch(`{{ url('admin/growth-value') }}/${customerId}`)
+                fetch(`{{ url('admin/reward-points/growth-value') }}/${customerId}`)
                     .then(response => response.json())
                     .then(data => {
                         if (data.success) {
@@ -357,3 +344,4 @@
             }
         </script>
 </x-admin::layouts>
+

+ 0 - 154
packages/Longyi/RewardPoints/src/Resources/views/admin/growth-value/levels.blade.php

@@ -1,154 +0,0 @@
-<x-admin::layouts>
-    <x-slot:title>
-        等级配置
-        </x-slot>
-
-        <div class="flex gap-4 justify-between items-center max-sm:flex-wrap">
-            <p class="text-xl text-gray-800 dark:text-white font-bold">
-                等级配置
-            </p>
-        </div>
-
-        <div class="mt-4 space-y-4">
-            @foreach($levels as $level)
-                <div class="bg-white dark:bg-cherry-900 rounded-lg p-6 shadow">
-                    <div class="flex justify-between items-start mb-4">
-                        <div>
-                            <h3 class="text-xl font-bold flex items-center gap-2">
-                                @if($level->growth_level_icon)
-                                    <img src="{{ $level->growth_level_icon }}" alt="{{ $level->growth_level_name }}" class="w-8 h-8">
-                                @endif
-                                {{ $level->growth_level_name ?? $level->name }}
-                            </h3>
-                            <p class="text-gray-500 dark:text-gray-400 text-sm mt-1">{{ $level->name }}</p>
-                        </div>
-                        <button
-                            onclick="editLevel({{ $level->id }})"
-                            class="primary-button"
-                        >
-                            编辑
-                        </button>
-                    </div>
-
-                    <div class="grid grid-cols-4 gap-4 mb-4">
-                        <div>
-                            <label class="block text-sm text-gray-500 dark:text-gray-400 mb-1">最低成长值</label>
-                            <p class="text-lg font-semibold">{{ number_format($level->min_growth_value) }}</p>
-                        </div>
-                        <div>
-                            <label class="block text-sm text-gray-500 dark:text-gray-400 mb-1">需要首单</label>
-                            <p class="text-lg font-semibold">{{ $level->require_first_order ? '是' : '否' }}</p>
-                        </div>
-                        <div>
-                            <label class="block text-sm text-gray-500 dark:text-gray-400 mb-1">额外折扣</label>
-                            <p class="text-lg font-semibold text-green-600">{{ $level->growth_discount_rate }}%</p>
-                        </div>
-                        <div>
-                            <label class="block text-sm text-gray-500 dark:text-gray-400 mb-1">会员组代码</label>
-                            <p class="text-lg font-semibold">{{ $level->code }}</p>
-                        </div>
-                    </div>
-
-                    @if(!empty($level->growth_benefits))
-                        <div>
-                            <label class="block text-sm text-gray-500 dark:text-gray-400 mb-2">等级权益</label>
-                            <ul class="space-y-1">
-                                @foreach($level->growth_benefits as $benefit)
-                                    <li class="flex items-center gap-2 text-sm">
-                                        <span class="icon-tick text-green-500"></span>
-                                        <span>{{ $benefit }}</span>
-                                    </li>
-                                @endforeach
-                            </ul>
-                        </div>
-                    @endif
-
-                    <!-- 编辑表单(隐藏) -->
-                    <div id="edit-form-{{ $level->id }}" class="hidden mt-4 pt-4 border-t dark:border-cherry-700">
-                        <form onsubmit="saveLevel(event, {{ $level->id }})">
-                            @csrf
-                            <div class="grid grid-cols-2 gap-4 mb-4">
-                                <div>
-                                    <label class="block text-sm font-medium mb-2">最低成长值</label>
-                                    <input type="number" name="min_growth_value" value="{{ $level->min_growth_value }}" class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700" required>
-                                </div>
-                                <div>
-                                    <label class="block text-sm font-medium mb-2">等级名称</label>
-                                    <input type="text" name="growth_level_name" value="{{ $level->growth_level_name }}" class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700">
-                                </div>
-                            </div>
-
-                            <div class="grid grid-cols-2 gap-4 mb-4">
-                                <div>
-                                    <label class="block text-sm font-medium mb-2">额外折扣率(%)</label>
-                                    <input type="number" name="growth_discount_rate" value="{{ $level->growth_discount_rate }}" min="0" max="100" class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700">
-                                </div>
-                                <div>
-                                    <label class="block text-sm font-medium mb-2">需要首单</label>
-                                    <select name="require_first_order" class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700">
-                                        <option value="0" {{ !$level->require_first_order ? 'selected' : '' }}>否</option>
-                                        <option value="1" {{ $level->require_first_order ? 'selected' : '' }}>是</option>
-                                    </select>
-                                </div>
-                            </div>
-
-                            <div class="mb-4">
-                                <label class="block text-sm font-medium mb-2">权益说明(每行一个)</label>
-                                <textarea name="growth_benefits_text" rows="3" class="border rounded-md px-3 py-2 w-full dark:bg-cherry-800 dark:border-cherry-700" placeholder="每行输入一个权益...">{{ is_array($level->growth_benefits) ? implode("\n", $level->growth_benefits) : '' }}</textarea>
-                            </div>
-
-                            <div class="flex gap-2">
-                                <button type="submit" class="primary-button">保存</button>
-                                <button type="button" onclick="cancelEdit({{ $level->id }})" class="secondary-button">取消</button>
-                            </div>
-                        </form>
-                    </div>
-                </div>
-            @endforeach
-        </div>
-
-        <script>
-            function editLevel(id) {
-                document.getElementById('edit-form-' + id).classList.remove('hidden');
-            }
-
-            function cancelEdit(id) {
-                document.getElementById('edit-form-' + id).classList.add('hidden');
-            }
-
-            function saveLevel(event, id) {
-                event.preventDefault();
-
-                const form = event.target;
-                const formData = new FormData(form);
-                formData.append('id', id);
-
-                // 将文本转换为数组
-                const benefitsText = formData.get('growth_benefits_text');
-                const benefits = benefitsText.split('\n').filter(line => line.trim());
-                formData.set('growth_benefits', JSON.stringify(benefits));
-
-                fetch('{{ route("admin.growth-value.levels.save") }}', {
-                    method: 'POST',
-                    body: formData,
-                    headers: {
-                        'X-CSRF-TOKEN': '{{ csrf_token() }}',
-                        'Accept': 'application/json',
-                    }
-                })
-                    .then(response => response.json())
-                    .then(data => {
-                        if (data.success) {
-                            alert('保存成功!');
-                            location.reload();
-                        } else {
-                            alert('保存失败:' + (data.message || '未知错误'));
-                        }
-                    })
-                    .catch(error => {
-                        console.error('Error:', error);
-                        alert('保存失败,请重试');
-                    });
-            }
-        </script>
-</x-admin::layouts>

+ 2 - 2
packages/Longyi/RewardPoints/src/Resources/views/admin/settings/index.blade.php

@@ -23,7 +23,7 @@
         @endif
 
         {{-- 分组标签页 --}}
-       {{-- <div class="bg-white dark:bg-gray-900 rounded-lg shadow mb-6">
+       <div class="bg-white dark:bg-gray-900 rounded-lg shadow mb-6">
             <div class="flex border-b border-gray-200 dark:border-gray-800 overflow-x-auto">
                 @foreach($groupData as $group => $data)
                     <a href="{{ route('admin.reward-points.settings.index', ['group' => $group]) }}"
@@ -33,7 +33,7 @@
                 @endforeach
             </div>
         </div>
---}}
+
         {{-- 配置表单 --}}
         <div class="bg-white dark:bg-gray-900 rounded-lg shadow">
             <form method="POST" action="{{ route('admin.reward-points.settings.save') }}">

+ 6 - 1
packages/Webkul/Admin/src/DataGrids/Customers/GroupDataGrid.php

@@ -18,7 +18,12 @@ class GroupDataGrid extends DataGrid
             ->select(
                 'id',
                 'code',
-                'name'
+                'name',
+                'growth_level_name',
+                'min_growth_value',
+                'require_first_order',
+                'growth_discount_rate',
+                'growth_benefits'
             );
     }
 

+ 32 - 3
packages/Webkul/Admin/src/Http/Controllers/Customers/CustomerGroupController.php

@@ -50,7 +50,18 @@ class CustomerGroupController extends Controller
         ]), [
             'is_user_defined' => 1,
         ]);
+        // 添加成长值相关字段
+        $growthFields = request()->only([
+            'growth_level_name',
+            'min_growth_value',
+            'require_first_order',
+            'growth_discount_rate',
+            'growth_benefits',
+        ]);
 
+        if (!empty($growthFields)) {
+            $data = array_merge($data, $growthFields);
+        }
         $customerGroup = $this->customerGroupRepository->create($data);
 
         Event::dispatch('customer.customer_group.create.after', $customerGroup);
@@ -70,14 +81,32 @@ class CustomerGroupController extends Controller
         $this->validate(request(), [
             'code' => ['required', 'unique:customer_groups,code,'.$id, new Code],
             'name' => 'required',
+            'min_growth_value' => 'nullable|integer|min:0',
+            'require_first_order' => 'nullable|boolean',
+            'growth_discount_rate' => 'nullable|numeric|min:0|max:100',
+            'growth_benefits' => 'nullable|json',
         ]);
 
-        Event::dispatch('customer.customer_group.update.before', $id);
 
-        $customerGroup = $this->customerGroupRepository->update(request()->only([
+        Event::dispatch('customer.customer_group.update.before', $id);
+        $data = request()->only([
             'code',
             'name',
-        ]), $id);
+        ]);
+
+        // 添加成长值相关字段
+        $growthFields = request()->only([
+            'growth_level_name',
+            'min_growth_value',
+            'require_first_order',
+            'growth_discount_rate',
+            'growth_benefits',
+        ]);
+
+        if (!empty($growthFields)) {
+            $data = array_merge($data, $growthFields);
+        }
+        $customerGroup = $this->customerGroupRepository->update($data, $id);
 
         Event::dispatch('customer.customer_group.update.after', $customerGroup);
 

+ 204 - 45
packages/Webkul/Admin/src/Resources/views/customers/groups/index.blade.php

@@ -122,51 +122,152 @@
                                 </p>
                             </x-slot>
 
-                            <!-- Modal Content -->
-                            <x-slot:content>
-                                <!-- Code -->
-                                <x-admin::form.control-group>
-                                    <x-admin::form.control-group.label class="required">
-                                        @lang('admin::app.customers.groups.index.create.code')
-                                    </x-admin::form.control-group.label>
-
-                                    <x-admin::form.control-group.control
-                                        type="hidden"
-                                        name="id"
-                                    />
-
-                                    <x-admin::form.control-group.control
-                                        type="text"
-                                        id="code"
-                                        name="code"
-                                        rules="required"
-                                        :label="trans('admin::app.customers.groups.index.create.code')"
-                                        :placeholder="trans('admin::app.customers.groups.index.create.code')"
-                                    />
-
-                                    <x-admin::form.control-group.error control-name="code" />
-                                </x-admin::form.control-group>
-
-                                <!-- Last Name -->
-                                <x-admin::form.control-group>
-                                    <x-admin::form.control-group.label class="required">
-                                        @lang('admin::app.customers.groups.index.create.name')
-                                    </x-admin::form.control-group.label>
-
-                                    <x-admin::form.control-group.control
-                                        type="text"
-                                        id="last_name"
-                                        name="name"
-                                        rules="required"
-                                        :label="trans('admin::app.customers.groups.index.create.name')"
-                                        :placeholder="trans('admin::app.customers.groups.index.create.name')"
-                                    />
-
-                                    <x-admin::form.control-group.error control-name="name" />
-                                </x-admin::form.control-group>
-                            </x-slot>
-
-                            <!-- Modal Footer -->
+                                <!-- Modal Content -->
+                                <x-slot:content>
+                                    <!-- Code -->
+                                    <x-admin::form.control-group>
+                                        <x-admin::form.control-group.label class="required">
+                                            @lang('admin::app.customers.groups.index.create.code')
+                                        </x-admin::form.control-group.label>
+
+                                        <x-admin::form.control-group.control
+                                            type="hidden"
+                                            name="id"
+                                        />
+
+                                        <x-admin::form.control-group.control
+                                            type="text"
+                                            id="code"
+                                            name="code"
+                                            rules="required"
+                                            :label="trans('admin::app.customers.groups.index.create.code')"
+                                            :placeholder="trans('admin::app.customers.groups.index.create.code')"
+                                        />
+
+                                        <x-admin::form.control-group.error control-name="code" />
+                                    </x-admin::form.control-group>
+
+                                    <!-- Name -->
+                                    <x-admin::form.control-group>
+                                        <x-admin::form.control-group.label class="required">
+                                            @lang('admin::app.customers.groups.index.create.name')
+                                        </x-admin::form.control-group.label>
+
+                                        <x-admin::form.control-group.control
+                                            type="text"
+                                            id="name"
+                                            name="name"
+                                            rules="required"
+                                            :label="trans('admin::app.customers.groups.index.create.name')"
+                                            :placeholder="trans('admin::app.customers.groups.index.create.name')"
+                                        />
+
+                                        <x-admin::form.control-group.error control-name="name" />
+                                    </x-admin::form.control-group>
+
+                                    {{-- 成长值设置区域 --}}
+                                    <div class="border-t dark:border-gray-800 pt-4 mt-4">
+                                        <p class="text-sm font-semibold text-gray-800 dark:text-white mb-3 flex items-center gap-2">
+                                            <svg class="w-4 h-4 text-purple-500" 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>
+                                            成长值等级设置
+                                        </p>
+
+                                        <!-- 成长值等级名称 -->
+                                        <x-admin::form.control-group>
+                                            <x-admin::form.control-group.label>
+                                                成长值等级名称
+                                            </x-admin::form.control-group.label>
+
+                                            <x-admin::form.control-group.control
+                                                type="text"
+                                                id="growth_level_name"
+                                                name="growth_level_name"
+                                                :label="'成长值等级名称'"
+                                                :placeholder="'例如:V1、V2'"
+                                            />
+
+                                            <x-admin::form.control-group.error control-name="growth_level_name" />
+                                        </x-admin::form.control-group>
+
+                                        <!-- 最低成长值要求 -->
+                                        <x-admin::form.control-group>
+                                            <x-admin::form.control-group.label>
+                                                最低成长值要求
+                                            </x-admin::form.control-group.label>
+
+                                            <x-admin::form.control-group.control
+                                                type="number"
+                                                id="min_growth_value"
+                                                name="min_growth_value"
+                                                :label="'最低成长值要求'"
+                                                :placeholder="'0'"
+                                                min="0"
+                                            />
+
+                                            <x-admin::form.control-group.error control-name="min_growth_value" />
+                                        </x-admin::form.control-group>
+
+                                        <!-- 需要完成首单 -->
+                                        <x-admin::form.control-group>
+                                            <x-admin::form.control-group.label>
+                                                需要完成首单
+                                            </x-admin::form.control-group.label>
+
+                                            <x-admin::form.control-group.control
+                                                type="select"
+                                                id="require_first_order"
+                                                name="require_first_order"
+                                                :label="'需要完成首单'"
+                                            >
+                                                <option value="0">否</option>
+                                                <option value="1">是</option>
+                                            </x-admin::form.control-group.control>
+
+                                            <x-admin::form.control-group.error control-name="require_first_order" />
+                                        </x-admin::form.control-group>
+
+                                        <!-- 额外折扣率 -->
+                                        <x-admin::form.control-group>
+                                            <x-admin::form.control-group.label>
+                                                额外折扣率(%)
+                                            </x-admin::form.control-group.label>
+
+                                            <x-admin::form.control-group.control
+                                                type="number"
+                                                id="growth_discount_rate"
+                                                name="growth_discount_rate"
+                                                :label="'额外折扣率(%)'"
+                                                :placeholder="'0'"
+                                                min="0"
+                                                max="100"
+                                            />
+
+                                            <x-admin::form.control-group.error control-name="growth_discount_rate" />
+                                        </x-admin::form.control-group>
+
+                                        <!-- 等级权益说明 -->
+                                        <x-admin::form.control-group>
+                                            <x-admin::form.control-group.label>
+                                                等级权益说明
+                                            </x-admin::form.control-group.label>
+
+                                            <x-admin::form.control-group.control
+                                                type="textarea"
+                                                id="growth_benefits_text"
+                                                name="growth_benefits_text"
+                                                :label="'等级权益说明'"
+                                                :placeholder="'每行输入一个权益,例如:&#10;享受2%额外折扣&#10;优先客服支持'"
+                                                rows="3"
+                                            />
+
+                                            <x-admin::form.control-group.error control-name="growth_benefits_text" />
+                                        </x-admin::form.control-group>
+                                    </div>
+                                    </x-slot>
+
+                                    <!-- Modal Footer -->
                             <x-slot:footer>
                                 <!-- Save Button -->
                                 <x-admin::button
@@ -220,6 +321,15 @@
                         if (params.id) {
                             formData.append('_method', 'put');
                         }
+                        // 处理成长值权益文本,转换为 JSON 数组
+                        const benefitsText = formData.get('growth_benefits_text');
+                        if (benefitsText) {
+                            const benefits = benefitsText.split('\n')
+                                .map(line => line.trim())
+                                .filter(line => line.length > 0);
+                            formData.set('growth_benefits', JSON.stringify(benefits));
+                            formData.delete('growth_benefits_text');
+                        }
 
                         this.$axios.post(params.id ? "{{ route('admin.customers.groups.update') }}" : "{{ route('admin.customers.groups.store') }}", formData)
                             .then((response) => {
@@ -246,6 +356,55 @@
                         this.$refs.groupUpdateOrCreateModal.toggle();
 
                         this.$refs.modalForm.setValues(value);
+                        // 如果是编辑模式,加载成长值权益数据和其他字段
+                        setTimeout(() => {
+                            // 设置成长值等级名称
+                            if (value.growth_level_name) {
+                                const levelNameInput = document.getElementById('growth_level_name');
+                                if (levelNameInput) {
+                                    levelNameInput.value = value.growth_level_name;
+                                }
+                            }
+
+                            // 设置最低成长值
+                            if (value.min_growth_value !== undefined) {
+                                const minValueInput = document.getElementById('min_growth_value');
+                                if (minValueInput) {
+                                    minValueInput.value = value.min_growth_value;
+                                }
+                            }
+
+                            // 设置需要完成首单
+                            if (value.require_first_order !== undefined) {
+                                const firstOrderSelect = document.getElementById('require_first_order');
+                                if (firstOrderSelect) {
+                                    firstOrderSelect.value = value.require_first_order ? '1' : '0';
+                                }
+                            }
+
+                            // 设置额外折扣率
+                            if (value.growth_discount_rate !== undefined) {
+                                const discountRateInput = document.getElementById('growth_discount_rate');
+                                if (discountRateInput) {
+                                    discountRateInput.value = value.growth_discount_rate;
+                                }
+                            }
+
+                            // 设置成长值权益说明
+                            if (value.growth_benefits && typeof value.growth_benefits === 'string') {
+                                try {
+                                    const benefits = JSON.parse(value.growth_benefits);
+                                    if (Array.isArray(benefits)) {
+                                        const textarea = document.getElementById('growth_benefits_text');
+                                        if (textarea) {
+                                            textarea.value = benefits.join('\n');
+                                        }
+                                    }
+                                } catch (e) {
+                                    console.error('解析成长值权益失败:', e);
+                                }
+                            }
+                        }, 100);
                     },
                 }
             })

+ 5 - 0
packages/Webkul/Customer/src/Models/CustomerGroup.php

@@ -29,6 +29,11 @@ class CustomerGroup extends Model implements CustomerGroupContract
         'name',
         'code',
         'is_user_defined',
+        'growth_level_name',
+        'min_growth_value',
+        'require_first_order',
+        'growth_discount_rate',
+        'growth_benefits',
     ];
 
     /**