['name' => 'Order', 'icon' => 'icon-shopping-cart', 'color' => 'blue'], 2 => ['name' => 'Registration', 'icon' => 'icon-user', 'color' => 'green'], 4 => ['name' => 'Product Review', 'icon' => 'icon-star', 'color' => 'yellow'], 9 => ['name' => 'Login', 'icon' => 'icon-calendar', 'color' => 'purple'], 5 => ['name' => 'Referral', 'icon' => 'icon-share', 'color' => 'indigo'], 6 => ['name' => 'Birthday', 'icon' => 'icon-gift', 'color' => 'pink'], 7 => ['name' => 'Share', 'icon' => 'icon-share-alt', 'color' => 'orange'], 8 => ['name' => 'Subscribe', 'icon' => 'icon-envelope', 'color' => 'orange'], ]; /** * Valid transaction type IDs */ private const VALID_TRANSACTION_TYPES = [1, 2, 3, 4, 5, 6, 7, 8]; /** * Color classes mapping for transaction types */ private const COLOR_CLASSES = [ 'blue' => 'bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-300', 'green' => 'bg-green-100 dark:bg-green-900 text-green-700 dark:text-green-300', 'yellow' => 'bg-yellow-100 dark:bg-yellow-900 text-yellow-700 dark:text-yellow-300', 'purple' => 'bg-purple-100 dark:bg-purple-900 text-purple-700 dark:text-purple-300', 'indigo' => 'bg-indigo-100 dark:bg-indigo-900 text-indigo-700 dark:text-indigo-300', 'pink' => 'bg-pink-100 dark:bg-pink-900 text-pink-700 dark:text-pink-300', 'orange' => 'bg-orange-100 dark:bg-orange-900 text-orange-700 dark:text-orange-300', 'gray' => 'bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400', ]; protected RewardPointRepository $rewardPointRepository; protected array $_config; public function __construct(RewardPointRepository $rewardPointRepository) { $this->rewardPointRepository = $rewardPointRepository; $this->_config = request('_config', []); } /** * Display a listing of reward rules */ public function index(): View { $rules = RewardActiveRule::query() ->orderBy('rule_id', 'desc') ->paginate(15); $customerGroupsList = $this->getCustomerGroups(); $transactionTypes = self::TRANSACTION_TYPES; $colorClasses = self::COLOR_CLASSES; $view = $this->_config['view'] ?? 'rewardpoints::admin.rules.index'; return view($view, compact('rules', 'customerGroupsList', 'transactionTypes', 'colorClasses')); } /** * Show the form for creating a new reward rule */ public function create(): View { $view = $this->_config['view'] ?? 'rewardpoints::admin.rules.create'; return view($view, [ 'transactionTypes' => self::TRANSACTION_TYPES, 'storeViews' => $this->getStoreViews(), 'customerGroups' => $this->getCustomerGroups(), 'colorClasses' => self::COLOR_CLASSES, ]); } /** * Show the form for editing the specified reward rule */ public function edit(int $id): View { $rule = RewardActiveRule::findOrFail($id); // 处理 Store Views 数据 $selectedStoreViews = $this->parseStoreViews($rule); // 如果规则适用于所有店铺(store_view = '0'),则转换为 'all' 选项 $selectedStoreViewsForSelect = []; if ($rule->store_view === '0' || empty($selectedStoreViews)) { $selectedStoreViewsForSelect = ['all']; } else { $selectedStoreViewsForSelect = $selectedStoreViews; } // 处理客户群组数据 $selectedCustomerGroupsArray = $this->parseCustomerGroups($rule); $selectedCustomerGroupsPoints = $rule->enable_different_points_by_group ? (json_decode($rule->customer_group_ids, true) ?: []) : []; $view = $this->_config['view'] ?? 'rewardpoints::admin.rules.edit'; return view($view, [ 'rule' => $rule, 'transactionTypes' => self::TRANSACTION_TYPES, 'storeViews' => $this->getStoreViews(), 'customerGroups' => $this->getCustomerGroups(), 'selectedStoreViewsForSelect' => $selectedStoreViewsForSelect, 'selectedCustomerGroupsArray' => $selectedCustomerGroupsArray, 'selectedCustomerGroupsPoints' => $selectedCustomerGroupsPoints, 'colorClasses' => self::COLOR_CLASSES, ]); } /** * Store a newly created reward rule */ public function store(Request $request): RedirectResponse { $validated = $this->validateStoreRequest($request); try { $data = $this->prepareDataForSave($request, $validated); RewardActiveRule::create($data); session()->flash('success', 'Reward rule created successfully.'); return $this->redirectToIndex(); } catch (Exception $e) { session()->flash('error', 'Error creating reward rule: ' . $e->getMessage()); return redirect()->back()->withInput(); } } /** * Update the specified reward rule */ public function update(Request $request, int $id): RedirectResponse { $validated = $this->validateUpdateRequest($request); $rule = RewardActiveRule::findOrFail($id); try { $data = $this->prepareDataForSave($request, $validated); // 确保 enable_different_points_by_group 字段被正确设置 $data['enable_different_points_by_group'] = $request->boolean('enable_different_points_by_group'); $rule->update($data); session()->flash('success', 'Reward rule updated successfully.'); return $this->redirectToIndex(); } catch (Exception $e) { session()->flash('error', 'Error updating reward rule: ' . $e->getMessage()); return redirect()->back()->withInput(); } } /** * Remove the specified reward rule */ public function destroy(int $id): JsonResponse|RedirectResponse { try { $rule = RewardActiveRule::findOrFail($id); $rule->delete(); $message = 'Reward rule deleted successfully.'; session()->flash('success', $message); if (request()->ajax()) { return response()->json(['status' => true, 'message' => $message]); } return $this->redirectToIndex(); } catch (Exception $e) { $message = 'Error deleting reward rule: ' . $e->getMessage(); session()->flash('error', $message); if (request()->ajax()) { return response()->json(['status' => false, 'message' => 'Error deleting reward rule.'], 500); } return $this->redirectToIndex()->with('error', $message); } } /** * Update rule status */ public function updateStatus(int $id, Request $request): JsonResponse { try { $rule = RewardActiveRule::findOrFail($id); $rule->status = $request->input('status', 0); $rule->save(); return response()->json([ 'status' => true, 'message' => 'Rule status updated successfully.', ]); } catch (Exception $e) { return response()->json([ 'status' => false, 'message' => 'Error updating rule status.', ], 500); } } /** * Validate store request */ private function validateStoreRequest(Request $request): array { $rules = [ 'rule_name' => 'required|string|max:255', 'type_of_transaction' => ['required', 'integer', Rule::in(self::VALID_TRANSACTION_TYPES)], 'status' => 'required|boolean', 'enable_different_points_by_group' => 'nullable|boolean', 'expired_day' => 'nullable|integer|min:0', 'comment' => 'nullable|string|max:500', 'store_view' => 'nullable|array', 'store_view.*' => 'nullable|string', ]; return $request->validate($rules); } /** * Validate update request */ private function validateUpdateRequest(Request $request): array { $rules = [ 'rule_name' => 'required|string|max:255', 'type_of_transaction' => ['required', 'integer', Rule::in(self::VALID_TRANSACTION_TYPES)], 'status' => 'required|boolean', 'enable_different_points_by_group' => 'nullable|boolean', 'default_expired' => 'nullable|boolean', 'expired_day' => 'nullable|integer|min:0', 'coupon_code' => 'nullable|string|max:255', 'comment' => 'nullable|string|max:500', 'store_view' => 'nullable|array', 'store_view.*' => 'nullable|string', ]; return $request->validate($rules); } /** * Prepare data for saving */ private function prepareDataForSave(Request $request, array $validated): array { $data = array_intersect_key($validated, array_flip([ 'rule_name', 'type_of_transaction', 'default_expired', 'expired_day', 'date_event', 'comment', 'coupon_code', 'status', 'enable_different_points_by_group', ])); // Handle store views - 修复:确保正确处理 store_view $storeViews = $request->get('store_view', []); $data['store_view'] = $this->formatStoreViews($storeViews); // Handle points configuration $this->handlePointsConfiguration($request, $data); return $data; } /** * Format store views for database storage */ private function formatStoreViews($storeViews): string { // 如果 storeViews 为空或为 '0',返回 '0' 表示所有店铺 if (empty($storeViews) || $storeViews === '0') { return '0'; } // 如果是单个值,直接返回 if (is_scalar($storeViews) && !empty($storeViews)) { return (string)$storeViews; } return '0'; } /** * Handle points configuration based on group settings */ private function handlePointsConfiguration(Request $request, array &$data): void { if ($request->boolean('enable_different_points_by_group')) { $groupPoints = $request->get('group_points', []); // 确保 $groupPoints 是数组 if (!is_array($groupPoints)) { $groupPoints = []; } // 过滤并处理群组积分数据,确保键是字符串或整数 $filteredPoints = []; foreach ($groupPoints as $groupId => $points) { // 确保键是标量类型且不为空 if (is_scalar($groupId) && !empty($groupId)) { // 确保积分值是数字 $pointsValue = is_numeric($points) ? (int)$points : 0; if ($pointsValue >= 0) { $filteredPoints[(string)$groupId] = $pointsValue; } } } $data['customer_group_ids'] = !empty($filteredPoints) ? json_encode($filteredPoints) : '{}'; $data['reward_point'] = 0; } else { $request->validate([ 'reward_point' => 'required|integer|min:0', ]); $data['reward_point'] = (int)$request->get('reward_point'); $data['customer_group_ids'] = $this->formatCustomerGroups($request->get('customer_group_ids', [])); } } /** * Format customer groups for database storage */ private function formatCustomerGroups($customerGroups): string { if (is_array($customerGroups) && !empty($customerGroups)) { // 过滤掉空值并确保所有值都是标量 $filtered = []; foreach ($customerGroups as $groupId) { if (is_scalar($groupId) && !empty($groupId)) { $filtered[] = (string)$groupId; } } return !empty($filtered) ? implode(',', array_unique($filtered)) : ''; } return ''; } /** * Parse store views from rule */ private function parseStoreViews(RewardActiveRule $rule): array { if ($rule->store_view && $rule->store_view !== '0') { $views = explode(',', $rule->store_view); // 过滤空值 return array_filter($views, function($view) { return !empty($view); }); } return []; } /** * Parse customer groups from rule */ private function parseCustomerGroups(RewardActiveRule $rule): array { if ($rule->enable_different_points_by_group) { $decoded = json_decode($rule->customer_group_ids, true); if (is_array($decoded)) { // 确保解码后的数据格式正确 $result = []; foreach ($decoded as $groupId => $points) { if (is_scalar($groupId) && !empty($groupId)) { $result[(string)$groupId] = is_numeric($points) ? (int)$points : 0; } } return $result; } return []; } if ($rule->customer_group_ids && $rule->customer_group_ids !== '') { $groups = explode(',', $rule->customer_group_ids); // 过滤空值 return array_filter($groups, function($group) { return !empty($group); }); } return []; } /** * Get all store views */ protected function getStoreViews(): array { try { $channels = Channel::all(); $storeViews = []; foreach ($channels as $channel) { $storeViews[$channel->code] = $channel->name; } return $storeViews; } catch (Exception $e) { return ['0' => 'All Stores']; } } /** * Get all customer groups */ protected function getCustomerGroups(): array { try { $groups = CustomerGroup::orderBy('id')->get(); $customerGroups = []; foreach ($groups as $group) { $customerGroups[$group->id] = $group->name; } return $customerGroups; } catch (Exception $e) { return ['0' => 'All Groups']; } } /** * Get transaction type configuration */ public function getTransactionTypeConfig(): array { return self::TRANSACTION_TYPES; } /** * Get transaction type name */ protected function getTransactionTypeName(int $typeId): string { return self::TRANSACTION_TYPES[$typeId]['name'] ?? 'Unknown'; } /** * Get transaction type color classes */ protected function getTransactionTypeColorClass(int $typeId): string { $color = self::TRANSACTION_TYPES[$typeId]['color'] ?? 'gray'; return self::COLOR_CLASSES[$color] ?? self::COLOR_CLASSES['gray']; } /** * Redirect to index route */ private function redirectToIndex(): RedirectResponse { $route = $this->_config['redirect'] ?? 'admin.reward-points.rules.index'; return redirect()->route($route); } }