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['p.sort'] = 'asc'; $order['p.id'] = 'desc'; } // 分页 $page = $this->request->get('page', 1); $limit = $this->request->get('limit', 20); // 查询数据(统计规格数量和已售总数) $specCountSubQuery = Db::name('package_price') ->field('package_id, COUNT(*) as spec_count, SUM(sold_count) as total_sold') ->where('status', 1) ->group('package_id') ->buildSql(); $packageList = Db::name('package') ->alias('p') ->leftJoin([$specCountSubQuery => 'sc'], 'p.id = sc.package_id') ->field('p.*, IFNULL(sc.spec_count, 0) as spec_count, IFNULL(sc.total_sold, 0) as total_sold') ->where($where) ->order($order) ->paginate([ 'list_rows' => $limit, 'page' => $page ]); // 转换功能特性字段 $list = $packageList->items(); foreach ($list as &$item) { if (!empty($item['features'])) { $item['features'] = json_decode($item['features'], true); } else { $item['features'] = []; } } $this->success('查询成功', [ 'list' => $list, 'total' => $packageList->total() ]); } /** * 新增/编辑套餐 * @return void */ public function edit() { $id = $this->request->post('id'); $name = $this->request->post('name'); $type = $this->request->post('type', 1); $description = $this->request->post('description', ''); $features = $this->request->post('features', []); $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(__('套餐名称已存在')); } // 处理功能特性字段 if (!is_array($features)) { $features = []; } $data = [ 'name' => $name, 'type' => $type, 'description' => $description, 'features' => json_encode($features, JSON_UNESCAPED_UNICODE), '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 = '新增成功'; } if ($result) { $this->success($message, ['id' => $id]); } else { $this->error(__('操作失败')); } } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } } /** * 删除套餐 * @return void */ public function delete() { $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(); if ($result) { $this->success('删除成功'); } else { $this->error(__('删除失败')); } } catch (\Exception $e) { $this->error('删除失败: ' . $e->getMessage()); } } /** * 套餐详情 * @return void */ public function detail() { $id = $this->request->get('id'); if (empty($id)) { $this->error(__('参数错误')); } // 获取套餐基础信息 $packageInfo = Db::name('package') ->where('id', $id) ->find(); if (!$packageInfo) { $this->error(__('套餐不存在')); } // 处理功能特性字段 if (!empty($packageInfo['features'])) { $packageInfo['features'] = json_decode($packageInfo['features'], true); } else { $packageInfo['features'] = []; } // 获取套餐规格列表 $specList = Db::name('package_price') ->where('package_id', $id) ->order('sort', 'asc') ->select() ->toArray(); // 统计库存和销售情况 $totalStock = 0; $totalSold = 0; foreach ($specList as $spec) { $totalStock += $spec['stock']; $totalSold += $spec['sold_count']; } // 统计用户购买数量(如果user_package表存在) $userPurchaseCount = 0; try { $userPurchaseCount = Db::name('user_package') ->where('package_id', $id) ->count(); } catch (\Exception $e) { // 表不存在,设为0 } // 统计企业购买数量(如果company_package表存在) $companyPurchaseCount = 0; try { $companyPurchaseCount = Db::name('company_package') ->where('package_id', $id) ->count(); } catch (\Exception $e) { // 表不存在,设为0 } $result = [ 'package_info' => $packageInfo, 'spec_list' => $specList, 'statistics' => [ 'spec_count' => count($specList), 'total_stock' => $totalStock, 'total_sold' => $totalSold, 'user_purchase_count' => $userPurchaseCount, 'company_purchase_count' => $companyPurchaseCount ] ]; $this->success('查询成功', $result); } /** * 添加/编辑套餐规格 * @return void */ public function editSpec() { $id = $this->request->post('id'); $packageId = $this->request->post('package_id'); $specName = $this->request->post('spec_name'); $price = $this->request->post('price', 0); $originalPrice = $this->request->post('original_price', 0); $stock = $this->request->post('stock', 0); $unitValue = $this->request->post('unit_value', ''); $description = $this->request->post('description', ''); $sort = $this->request->post('sort', 0); if (empty($packageId) || empty($specName)) { $this->error(__('参数不完整')); } if ($price <= 0) { $this->error(__('价格必须大于0')); } // 检查套餐是否存在 $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, 'original_price' => $originalPrice, 'stock' => $stock, 'unit_value' => $unitValue, '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 = '新增成功'; } if ($result) { $this->success($message, ['id' => $id]); } else { $this->error(__('操作失败')); } } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } } /** * 删除套餐规格 * @return void */ public function deleteSpec() { $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(); if ($result) { $this->success('删除成功'); } else { $this->error(__('删除失败')); } } catch (\Exception $e) { $this->error('删除失败: ' . $e->getMessage()); } } /** * 获取套餐规格列表 * @return void */ public function specList() { $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() { $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') ]); if ($result) { $statusText = $status == 1 ? '启用' : '禁用'; $this->success("成功{$statusText}{$result}个套餐"); } else { $this->error(__('操作失败')); } } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } } /** * 批量更新规格库存 * @return void */ public function batchUpdateStock() { $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') ]); if ($result) { $this->success("成功更新{$result}个规格的库存"); } else { $this->error(__('操作失败')); } } catch (\Exception $e) { $this->error('操作失败: ' . $e->getMessage()); } } /** * 获取套餐类型选项 * @return void */ public function typeOptions() { $options = [ ['value' => 1, 'label' => '个人套餐'], ['value' => 2, 'label' => '团队套餐'], ['value' => 3, 'label' => '企业套餐'] ]; $this->success('获取成功', $options); } /** * 获取套餐状态选项 * @return void */ public function statusOptions() { $options = [ ['value' => 1, 'label' => '启用'], ['value' => 2, 'label' => '禁用'] ]; $this->success('获取成功', $options); } /** * 获取规格状态选项 * @return void */ public function specStatusOptions() { $options = [ ['value' => 1, 'label' => '正常'], ['value' => 2, 'label' => '售罄'] ]; $this->success('获取成功', $options); } /** * 套餐统计信息 * @return void */ public function statistics() { // 套餐总数 $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'); // 按类型统计 $typeStats = Db::name('package') ->field('type, COUNT(*) as count') ->where('status', 1) ->group('type') ->select() ->toArray(); $stats = [ 'total_package' => $totalPackage, 'active_package' => $activePackage, 'total_spec' => $totalSpec, 'total_stock' => $totalStock, 'total_sold' => $totalSold, 'type_stats' => $typeStats ]; $this->success('获取成功', $stats); } /** * 导出套餐数据 * @return void */ public function export() { $where = []; // 根据筛选条件构建查询条件 if (!empty($this->request->get('name'))) { $name = $this->request->get('name'); $where[] = ['name', 'like', '%' . $name . '%']; } if (!empty($this->request->get('status'))) { $status = $this->request->get('status'); $where['status'] = $status; } // 查询数据 $packageList = Db::name('package') ->where($where) ->order('sort', 'asc') ->order('id', 'desc') ->select() ->toArray(); // 状态映射 $typeMap = [1 => '个人套餐', 2 => '团队套餐', 3 => '企业套餐']; $statusMap = [1 => '启用', 2 => '禁用']; foreach ($packageList as &$item) { $item['type'] = $typeMap[$item['type']] ?? '未知'; $item['status'] = $statusMap[$item['status']] ?? '未知'; // 获取规格信息 $specs = Db::name('package_price') ->where('package_id', $item['id']) ->order('sort', 'asc') ->select() ->toArray(); $specInfo = []; foreach ($specs as $spec) { $specInfo[] = "{$spec['spec_name']} - ¥{$spec['price']} (库存:{$spec['stock']})"; } $item['spec_info'] = implode('; ', $specInfo); } $this->success('查询成功', $packageList); } /** * 获取所有套餐选项(用于下拉选择) * @return void */ public function selectOptions() { $packageList = Db::name('package') ->where('status', 1) ->field('id as value, name as label, type') ->order('sort', 'asc') ->order('id', 'asc') ->select() ->toArray(); $this->success('获取成功', $packageList); } /** * 获取套餐规格选项(用于购买时选择) * @return void */ public function specOptions() { $packageId = $this->request->get('package_id'); if (empty($packageId)) { $this->error(__('参数错误')); } $specList = Db::name('package_price') ->where('package_id', $packageId) ->where('status', 1) ->where('stock', '>', 0) // 只显示有库存的规格 ->field('id as value, spec_name as label, price, stock, unit_value, description') ->order('sort', 'asc') ->select() ->toArray(); $this->success('获取成功', $specList); } /** * 更新规格销售数量(模拟用户购买) * @return void */ public function updateSoldCount() { $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(); if ($result) { $this->success('更新成功'); } else { $this->error(__('更新失败')); } } catch (\Exception $e) { Db::rollback(); $this->error('操作失败: ' . $e->getMessage()); } } }