request->get('name'))) { $name = $this->request->get('name'); $where[] = ['p.name', 'like', '%' . $name . '%']; } // 套餐类型筛选 if (!empty($this->request->get('type'))) { $type = $this->request->get('type'); $where['p.type'] = $type; } // 状态筛选 if (!empty($this->request->get('status'))) { $status = $this->request->get('status'); $where['p.status'] = $status; } // 排序 $order = []; if (!empty($this->request->get('order'))) { $order_a = $this->request->get('order'); $order_a = explode(',', $order_a); $order[$order_a[0]] = $order_a[1]; } else { $order['sort'] = 'asc'; $order['id'] = 'desc'; } // 分页 $page = $this->request->get('page', 1); $limit = $this->request->get('limit', 20); // 查询套餐列表并计算库存状态 $packageList = Db::name('package') ->where($where) ->order($order) ->paginate([ 'list_rows' => $limit, 'page' => $page ]); // 为每个套餐计算库存状态 $list = $packageList->items(); foreach ($list as &$package) { // 获取该套餐的所有规格 $specs = Db::name('package_price') ->where('package_id', $package['id']) ->select() ->toArray(); // 计算总库存和总已售 $totalStock = 0; $totalSold = 0; foreach ($specs as $spec) { $totalStock += $spec['stock']; $totalSold += $spec['sold_count']; } // 根据库存设置库存状态 if ($totalStock == 0) { $package['stock_status'] = '售罄'; } elseif ($totalStock <= 10) { $package['stock_status'] = '即将售罄'; } else { $package['stock_status'] = '充足'; } $package['remaining_stock'] = $totalStock; $package['sold_count'] = $totalSold; $package['spec_count'] = count($specs); } $this->success('查询成功', [ 'list' => $list, 'total' => $packageList->total() ]); } /** * 新增/编辑套餐 * @return void */ public function edit():void { $id = $this->request->post('id'); $name = $this->request->post('name'); $description = $this->request->post('description', ''); $sort = $this->request->post('sort', 0); $status = $this->request->post('status', 1); if (empty($name)) { $this->error(__('套餐名称不能为空')); } // 验证套餐名称是否已存在(编辑时排除自己) $checkName = Db::name('package') ->where('name', $name); if (!empty($id)) { $checkName->where('id', '<>', $id); } if ($checkName->find()) { $this->error(__('套餐名称已存在')); } $data = [ 'name' => $name, 'description' => $description, 'sort' => $sort, 'status' => $status, 'update_time' => date('Y-m-d H:i:s') ]; try { if (!empty($id)) { // 编辑 $packageInfo = Db::name('package') ->where('id', $id) ->find(); if (!$packageInfo) { $this->error(__('套餐不存在')); } $result = Db::name('package') ->where('id', $id) ->update($data); $message = '编辑成功'; } else { // 新增 $data['create_time'] = date('Y-m-d H:i:s'); $result = Db::name('package') ->insert($data); $id = Db::name('package')->getLastInsID(); $message = '新增成功'; } } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } if ($result) { $this->success($message, ['id' => $id]); } else { $this->error(__('操作失败')); } } /** * 删除套餐 * @return void */ public function delete():void { $id = $this->request->post('id'); if (empty($id)) { $this->error(__('参数错误')); } // 检查是否有规格存在 $hasSpec = Db::name('package_price') ->where('package_id', $id) ->count(); if ($hasSpec > 0) { $this->error(__('该套餐下有关联的规格,请先删除规格')); } // 检查是否有用户购买记录(如果user_package表存在) try { $hasUserPackage = Db::name('user_package') ->where('package_id', $id) ->count(); if ($hasUserPackage > 0) { $this->error(__('该套餐已有用户购买记录,不能删除')); } } catch (\Exception $e) { // 表不存在,跳过检查 } // 检查是否有企业购买记录(如果company_package表存在) try { $hasCompanyPackage = Db::name('company_package') ->where('package_id', $id) ->count(); if ($hasCompanyPackage > 0) { $this->error(__('该套餐已有企业购买记录,不能删除')); } } catch (\Exception $e) { // 表不存在,跳过检查 } try { $result = Db::name('package') ->where('id', $id) ->delete(); } catch (\Exception $e) { $this->error('删除失败: ' . $e->getMessage()); } if ($result) { $this->success('删除成功'); } else { $this->error(__('删除失败')); } } /** * 套餐详情 * @return void */ public function detail():void { $id = $this->request->get('id'); if (empty($id)) { $this->error(__('参数错误')); } // 获取套餐基础信息 $packageInfo = Db::name('package') ->where('id', $id) ->find(); if (!$packageInfo) { $this->error(__('套餐不存在')); } // 获取套餐规格列表 $specList = Db::name('package_price') ->where('package_id', $id) ->order('sort', 'asc') ->select() ->toArray(); // 计算规格库存状态和汇总数据 $totalStock = 0; $totalSold = 0; $cardTypeMap = [ 1 => '次卡', 2 => '按积分', 3 => '日卡', 4 => '周卡', 5 => '季卡', 6 => '月卡', 7 => '年卡' ]; $typeMap = [ 1 => '个人套餐', 2 => '团队套餐', ]; foreach ($specList as &$spec) { // 计算库存状态 if ($spec['stock'] == 0) { $spec['stock_status'] = '售罄'; } elseif ($spec['stock'] <= 10) { $spec['stock_status'] = '即将售罄'; } else { $spec['stock_status'] = '充足'; } // 翻译类型和卡类型 $spec['type_text'] = $typeMap[$spec['type']] ?? '未知'; $spec['card_type_text'] = $cardTypeMap[$spec['card_type']] ?? '未知'; // 格式化收费方式显示 if ($spec['card_type'] == 1 && $spec['unit_value'] > 0) { $spec['charge_text'] = '按次数:' . $spec['unit_value'] . '次'; } elseif ($spec['card_type'] == 2 && $spec['points_value'] > 0) { $spec['charge_text'] = '按积分:' . $spec['points_value'] . '积分'; } else { $spec['charge_text'] = $spec['card_type_text']; } $totalStock += $spec['stock']; $totalSold += $spec['sold_count']; } $result = [ 'package_info' => $packageInfo, 'spec_list' => $specList, 'statistics' => [ 'total_stock' => $totalStock, 'total_sold' => $totalSold, 'spec_count' => count($specList) ] ]; $this->success('查询成功', $result); } /** * 添加/编辑套餐规格 * @return void */ public function editSpec():void { $id = $this->request->post('id'); $packageId = $this->request->post('package_id'); $specName = $this->request->post('spec_name'); $price = $this->request->post('price', 0); $stock = $this->request->post('stock', 0); $type = $this->request->post('type', 1); $cardType = $this->request->post('card_type', 1); $unitValue = $this->request->post('unit_value', 0); $pointsValue = $this->request->post('points_value', 0); $description = $this->request->post('description', ''); $image = $this->request->post('image', ''); $sort = $this->request->post('sort', 0); if (empty($packageId) || empty($specName)) { $this->error(__('参数不完整')); } if ($price <= 0) { $this->error(__('价格必须大于0')); } // 验证条件 if ($cardType == 1 && $unitValue <= 0) { $this->error(__('次卡类型必须填写有效次数')); } if ($cardType == 2 && $pointsValue <= 0) { $this->error(__('积分类型必须填写有效积分数量')); } // 检查套餐是否存在 $packageInfo = Db::name('package') ->where('id', $packageId) ->find(); if (!$packageInfo) { $this->error(__('套餐不存在')); } // 验证规格名称是否已存在(同一套餐下不能重复) $checkSpec = Db::name('package_price') ->where('package_id', $packageId) ->where('spec_name', $specName); if (!empty($id)) { $checkSpec->where('id', '<>', $id); } if ($checkSpec->find()) { $this->error(__('同一套餐下规格名称不能重复')); } $data = [ 'package_id' => $packageId, 'spec_name' => $specName, 'price' => $price, 'stock' => $stock, 'type' => $type, 'image' => $image, 'card_type' => $cardType, 'unit_value' => $unitValue, 'points_value' => $pointsValue, 'description' => $description, 'sort' => $sort, 'update_time' => date('Y-m-d H:i:s') ]; try { if (!empty($id)) { // 编辑 $result = Db::name('package_price') ->where('id', $id) ->update($data); $message = '编辑成功'; } else { // 新增 $data['create_time'] = date('Y-m-d H:i:s'); $result = Db::name('package_price') ->insert($data); $id = Db::name('package_price')->getLastInsID(); $message = '新增成功'; } } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } if ($result) { $this->success($message, ['id' => $id]); } else { $this->error(__('操作失败')); } } /** * 删除套餐规格 * @return void */ public function deleteSpec():void { $id = $this->request->post('id'); if (empty($id)) { $this->error(__('参数错误')); } // 检查是否有用户购买记录 try { $hasPurchase = Db::name('user_package') ->where('package_price_id', $id) ->count(); if ($hasPurchase > 0) { $this->error(__('该规格已有用户购买记录,不能删除')); } } catch (\Exception $e) { // 表不存在,跳过检查 } // 检查是否有企业购买记录 try { $hasPurchase = Db::name('company_package') ->where('package_price_id', $id) ->count(); if ($hasPurchase > 0) { $this->error(__('该规格已有企业购买记录,不能删除')); } } catch (\Exception $e) { // 表不存在,跳过检查 } try { $result = Db::name('package_price') ->where('id', $id) ->delete(); } catch (\Exception $e) { $this->error('删除失败: ' . $e->getMessage()); } if ($result) { $this->success('删除成功'); } else { $this->error(__('删除失败')); } } /** * 获取套餐规格列表 * @return void */ public function specList():void { $packageId = $this->request->get('package_id'); if (empty($packageId)) { $this->error(__('参数错误')); } $specList = Db::name('package_price') ->where('package_id', $packageId) ->order('sort', 'asc') ->select() ->toArray(); $this->success('查询成功', $specList); } /** * 批量更新套餐状态 * @return void */ public function batchStatus():void { $ids = $this->request->post('ids'); $status = $this->request->post('status'); if (empty($ids) || empty($status)) { $this->error(__('参数错误')); } if (!is_array($ids)) { $ids = explode(',', $ids); } try { $result = Db::name('package') ->whereIn('id', $ids) ->update([ 'status' => $status, 'update_time' => date('Y-m-d H:i:s') ]); } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } if ($result) { $statusText = $status == 1 ? '启用' : '禁用'; $this->success("成功{$statusText}{$result}个套餐"); } else { $this->error(__('操作失败')); } } /** * 批量更新规格库存 * @return void */ public function batchUpdateStock():void { $ids = $this->request->post('ids'); $stock = $this->request->post('stock'); if (empty($ids) || $stock === null) { $this->error(__('参数错误')); } if (!is_array($ids)) { $ids = explode(',', $ids); } try { $result = Db::name('package_price') ->whereIn('id', $ids) ->update([ 'stock' => $stock, 'update_time' => date('Y-m-d H:i:s') ]); } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } if ($result) { $this->success("成功更新{$result}个规格的库存"); } else { $this->error(__('操作失败')); } } /** * 获取套餐类型选项 * @return void */ public function typeOptions():void { $options = [ ['value' => 1, 'label' => '个人套餐'], ['value' => 2, 'label' => '团队套餐'], ['value' => 3, 'label' => '企业套餐'] ]; $this->success('获取成功', $options); } /** * 获取套餐状态选项 * @return void */ public function statusOptions():void { $options = [ ['value' => 1, 'label' => '启用'], ['value' => 2, 'label' => '禁用'] ]; $this->success('获取成功', $options); } /** * 获取卡类型选项 * @return void */ public function cardTypeOptions():void { $options = [ ['value' => 1, 'label' => '次卡'], ['value' => 2, 'label' => '按积分'], ['value' => 3, 'label' => '日卡'], ['value' => 4, 'label' => '周卡'], ['value' => 5, 'label' => '季卡'], ['value' => 6, 'label' => '月卡'], ['value' => 7, 'label' => '年卡'] ]; $this->success('获取成功', $options); } /** * 套餐统计信息 * @return void */ public function statistics():void { // 套餐总数 $totalPackage = Db::name('package')->count(); // 启用套餐数 $activePackage = Db::name('package') ->where('status', 1) ->count(); // 规格总数 $totalSpec = Db::name('package_price')->count(); // 总库存 $totalStock = Db::name('package_price') ->sum('stock'); // 总已售 $totalSold = Db::name('package_price') ->sum('sold_count'); $stats = [ 'total_package' => $totalPackage, 'active_package' => $activePackage, 'total_spec' => $totalSpec, 'total_stock' => $totalStock, 'total_sold' => $totalSold ]; $this->success('获取成功', $stats); } /** * 获取所有套餐选项(用于下拉选择) * @return void */ public function selectOptions():void { $packageList = Db::name('package') ->where('status', 1) ->field('id as value, name as label') ->order('sort', 'asc') ->order('id', 'asc') ->select() ->toArray(); $this->success('获取成功', $packageList); } /** * 获取套餐规格选项(用于购买时选择) * @return void */ public function specOptions():void { $packageId = $this->request->get('package_id'); if (empty($packageId)) { $this->error(__('参数错误')); } $specList = Db::name('package_price') ->where('package_id', $packageId) ->where('stock', '>', 0) // 只显示有库存的规格 ->field('id as value, spec_name as label, price, stock, type, card_type, unit_value, points_value, description') ->order('sort', 'asc') ->select() ->toArray(); $this->success('获取成功', $specList); } /** * 更新规格销售数量(模拟用户购买) * @return void */ public function updateSoldCount():void { $id = $this->request->post('id'); $quantity = $this->request->post('quantity', 1); if (empty($id) || $quantity <= 0) { $this->error(__('参数错误')); } try { Db::startTrans(); // 获取当前规格信息 $specInfo = Db::name('package_price') ->where('id', $id) ->lock(true) ->find(); if (!$specInfo) { throw new \Exception('规格不存在'); } if ($specInfo['stock'] < $quantity) { throw new \Exception('库存不足'); } // 更新库存和销售数量 $result = Db::name('package_price') ->where('id', $id) ->update([ 'stock' => Db::raw('stock - ' . $quantity), 'sold_count' => Db::raw('sold_count + ' . $quantity), 'update_time' => date('Y-m-d H:i:s') ]); // 如果库存为0,自动标记为售罄 if ($specInfo['stock'] - $quantity <= 0) { Db::name('package_price') ->where('id', $id) ->update([ 'status' => 2, // 售罄 'update_time' => date('Y-m-d H:i:s') ]); } Db::commit(); } catch (\Exception $e) { Db::rollback(); $this->error('操作失败: ' . $e->getMessage()); } if ($result) { $this->success('更新成功'); } else { $this->error(__('更新失败')); } } }