model = new \app\admin\model\app\physical\Goods; $this->skuModel = new \app\admin\model\app\physical\Sku; $this->skuPriceModel = new \app\admin\model\app\physical\SkuPrice; } /** * 查看 */ public function index() { $this->request->filter(['strip_tags', 'trim']); list($where, $sort, $order, $offset, $limit) = $this->buildparams(); $query = $this->model ->where($where) ->where([ 'uniacid'=>UNIACID ]); // 处理分类搜索 $hasCategoryId = $this->request->has('category_id'); if ($hasCategoryId) { $categoryIds = $this->request->post('category_id/a', []); // 如果是空数组,返回空结果 if (empty($categoryIds)) { $query->where('1=0'); } else { // 获取所有分类及其子分类 $allCategoryIds = []; foreach ($categoryIds as $categoryId) { $childIds = $this->getCategoryChildIds($categoryId); $allCategoryIds = array_merge($allCategoryIds, $childIds); } $allCategoryIds = array_unique($allCategoryIds); $query->where(function ($q) use ($allCategoryIds) { foreach ($allCategoryIds as $cid) { $q->whereOrRaw("find_in_set($cid, category_id)"); } }); } } $list = $query->order($sort, $order)->paginate($limit); // 获取商品ID列表 $goodsIds = []; foreach ($list as $item) { $goodsIds[] = $item['id']; } // 批量获取SKU价格数据 $skuPrices = []; if (!empty($goodsIds)) { $skuPriceList = $this->skuPriceModel ->where('goods_id', 'in', $goodsIds) ->where('uniacid', UNIACID) ->select(); foreach ($skuPriceList as $skuPrice) { $skuPrices[$skuPrice['goods_id']][] = $skuPrice; } } // 处理列表数据 $rows = []; foreach ($list as $item) { $item = $item->toArray(); $goodsId = $item['id']; // 获取该商品的SKU价格列表 $goodsSkuPrices = $skuPrices[$goodsId] ?? []; // 计算总库存(只计算status=1的规格) $totalStock = 0; foreach ($goodsSkuPrices as $skuPrice) { if (isset($skuPrice['status']) && $skuPrice['status'] == 1) { $totalStock += $skuPrice['stock']; } } $item['total_stock'] = $totalStock; // SKU价格列表(用于编辑) $item['sku_price_list'] = $goodsSkuPrices; // 价格范围(从商品表获取价格,如果为空则从SKU计算) $item['price'] = $item['price'] ?? 0; if (!empty($goodsSkuPrices)) { $prices = array_column($goodsSkuPrices, 'price'); $item['price_min'] = min($prices); $item['price_max'] = max($prices); } else { $item['price_min'] = $item['price']; $item['price_max'] = $item['price']; } $rows[] = $item; } $result = array("total" => $list->total(), "rows" => $rows,'attr'=>[ 'status'=>$this->model->getStatusList(), 'specType'=>$this->model->getSpecTypeList(), 'isHidden'=>$this->model->getIsHiddenList() ]); return $this->success("获取成功",$result); } /** * 获取分类及其所有子分类ID * @param int|array $categoryId 分类ID或分类ID数组 * @return array */ protected function getCategoryChildIds($categoryId) { $categoryIds = []; // 支持数组或单个ID $categoryIdArray = is_array($categoryId) ? $categoryId : [$categoryId]; foreach ($categoryIdArray as $cid) { $categoryIds[] = $cid; // 递归获取所有子分类 $this->getChildCategoryIdsById($cid, $categoryIds); } return array_unique($categoryIds); } /** * 递归获取子分类ID * @param int $parentId * @param array $categoryIds */ protected function getChildCategoryIdsById($parentId, &$categoryIds) { $categoryModel = new \app\admin\model\app\physical\Category(); $children = $categoryModel ->where('parent_id', $parentId) ->where('uniacid', UNIACID) ->column('id'); foreach ($children as $childId) { $categoryIds[] = $childId; $this->getChildCategoryIdsById($childId, $categoryIds); } } /** * 递归获取子分类ID(兼容旧代码) * @param object $model * @param int $parentId * @param array $categoryIds */ protected function getChildCategoryIds($model, $parentId, &$categoryIds) { $children = $model ->where('parent_id', $parentId) ->where('uniacid', UNIACID) ->column('id'); foreach ($children as $childId) { $categoryIds[] = $childId; $this->getChildCategoryIds($model, $childId, $categoryIds); } } /** * 表单验证 */ protected function validateGoods($params, $skuList = [], $specType = 'single') { // 验证发货时间 if (!isset($params['delivery_time'])) { $this->error('发货时间不能为空'); } // 验证单次限购 if (isset($params['single_limit'])) { if (!is_numeric($params['single_limit'])) { $this->error('单次限购数量必须是数字'); } if ($params['single_limit'] < 0) { $this->error('单次限购数量不能小于0'); } } // 验证终身限购 if (isset($params['lifetime_limit'])) { if (!is_numeric($params['lifetime_limit'])) { $this->error('终身限购数量必须是数字'); } if ($params['lifetime_limit'] < 0) { $this->error('终身限购数量不能小于0'); } } // 多规格验证 if ($specType == 'multi' && !empty($skuList)) { $skuPrices = $skuList['sku_prices'] ?? []; $skuNames = $skuList['sku_names'] ?? []; // 验证每个规格都有规格值 if (!empty($skuNames)) { foreach ($skuNames as $index => $skuName) { if (empty($skuName['name'])) { $this->error('规格名称不能为空'); } if (empty($skuName['values']) || !is_array($skuName['values'])) { $this->error('规格【' . $skuName['name'] . '】必须有规格值'); } } } // 验证SKU价格 if (!empty($skuPrices)) { foreach ($skuPrices as $index => $skuPrice) { if (!isset($skuPrice['price']) || $skuPrice['price'] === '' || $skuPrice['price'] === null) { $this->error('规格【' . ($skuPrice['sku_text'] ?? '第' . ($index + 1) . '个') . '】价格不能为空'); } if (!is_numeric($skuPrice['price']) || $skuPrice['price'] < 0) { $this->error('规格【' . ($skuPrice['sku_text'] ?? '第' . ($index + 1) . '个') . '】价格必须大于等于0'); } } } } } /** * 添加 */ public function add() { $params = $this->request->param('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); $specType = $params['spec_type'] ?? 'single'; $skus = $params['skus'] ?? []; $skuList = $params['sku_list'] ?? []; unset($params['skus'], $params['sku_list']); // 表单验证 $this->validateGoods($params, $skuList, $specType); // 处理轮播图 $carousel = $params['carousel'] ?? []; if (is_array($carousel)) { if (count($carousel) > 10) { $this->error('轮播图最多只能上传10张'); } $params['carousel'] = json_encode($carousel); } // 处理分类ID if (isset($params['category_id']) && is_array($params['category_id'])) { $params['category_id'] = implode(',', $params['category_id']); } $params['createtime'] = time(); $params['updatetime'] = time(); $params['uniacid'] = UNIACID; // 设置限购字段默认值 if (!isset($params['single_limit'])) { $params['single_limit'] = 0; } if (!isset($params['lifetime_limit'])) { $params['lifetime_limit'] = 0; } Db::startTrans(); try { $result = $this->model->allowField(true)->save($params); if ($result && !empty($skuList)) { $this->saveSkuData($this->model->id, $skuList, $specType); // 计算并更新商品价格 $this->updateGoodsPrice($this->model->id, $specType); // 计算并更新商品库存 $this->updateGoodsStock($this->model->id, $specType); } Db::commit(); } catch (ValidateException|PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($result !== false) { $this->success("添加成功"); } else { $this->error(__('No rows were inserted')); } } /** * 编辑 */ public function edit($ids = null) { $params = $this->request->param('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); $specType = $params['spec_type'] ?? 'single'; $skuList = $params['sku_list'] ?? []; unset($params['sku_list']); // 表单验证 $this->validateGoods($params, $skuList, $specType); // 处理轮播图 $carousel = $params['carousel'] ?? []; if (is_array($carousel)) { if (count($carousel) > 10) { $this->error('轮播图最多只能上传10张'); } $params['carousel'] = json_encode($carousel); } // 处理分类ID if (isset($params['category_id']) && is_array($params['category_id'])) { $params['category_id'] = implode(',', $params['category_id']); } // 设置限购字段默认值 if (!isset($params['single_limit'])) { $params['single_limit'] = 0; } if (!isset($params['lifetime_limit'])) { $params['lifetime_limit'] = 0; } $params['updatetime'] = time(); Db::startTrans(); try { $row = $this->model->where('id', $ids)->where('uniacid', UNIACID)->find(); if (!$row) { $this->error(__('No Results were found')); } $result = $row->allowField(true)->save($params); if ($result && !empty($skuList)) { $this->saveSkuData($ids, $skuList, $specType); // 计算并更新商品价格 $this->updateGoodsPrice($ids, $specType); // 计算并更新商品库存 $this->updateGoodsStock($ids, $specType); } Db::commit(); } catch (ValidateException|PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($result !== false) { $this->success("更新成功"); } else { $this->error(__('No rows were updated')); } } /** * 生成唯一SKU编码 * 格式: SP + 13位随机字符 */ protected function generateSkuSn() { $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; do { $sn = 'SP'; for ($i = 0; $i < 13; $i++) { $sn .= $chars[mt_rand(0, strlen($chars) - 1)]; } // 检查是否已存在 $exists = $this->skuPriceModel->where('sn', $sn)->find(); } while ($exists); return $sn; } /** * 保存规格和SKU数据 * @param int $goodsId 商品ID * @param array $skuData SKU数据 * @param string $specType 规格类型:single=单规格,multi=多规格 */ protected function saveSkuData($goodsId, $skuData, $specType = 'multi') { if ($specType == 'single') { // 单规格处理 $this->saveSingleSku($goodsId, $skuData); } else { // 多规格处理 $this->saveMultiSku($goodsId, $skuData); } } /** * 保存单规格SKU */ protected function saveSingleSku($goodsId, $skuData) { $skuPrices = $skuData['sku_prices'] ?? []; if (empty($skuPrices) || !isset($skuPrices[0])) { // 如果没有提供单规格数据,直接删除所有规格数据 $this->skuModel->where('goods_id', $goodsId)->where('uniacid', UNIACID)->delete(); $this->skuPriceModel->where('goods_id', $goodsId)->where('uniacid', UNIACID)->delete(); return; } $skuPrice = $skuPrices[0]; // 查询是否已存在SKU价格记录 $existingSkuPrice = $this->skuPriceModel ->where('goods_id', $goodsId) ->where('uniacid', UNIACID) ->order('id', 'asc') ->find(); // 删除多余的规格项(多规格转单规格时) $this->skuModel->where('goods_id', $goodsId)->where('uniacid', UNIACID)->delete(); // 准备单规格数据 $data = [ 'goods_id' => $goodsId, 'uniacid' => UNIACID, 'goods_sku_ids' => null, 'goods_sku_text' => null, 'image' => $skuPrice['image'] ?? '', 'stock' => $skuPrice['stock'] ?? 0, 'stock_warning' => $skuPrice['stock_warning'] ?? null, 'sales' => $skuPrice['sales'] ?? 0, 'sn' => $skuPrice['sn'] ?? '', 'weight' => $skuPrice['weight'] ?? 0, 'volume' => $skuPrice['volume'] ?? 0, 'cost_price' => $skuPrice['cost_price'] ?? 0, 'original_price' => $skuPrice['original_price'] ?? 0, 'price' => $skuPrice['price'] ?? 0, 'status' => $skuPrice['status'] ?? 1, 'weigh' => $skuPrice['weigh'] ?? 0, 'updatetime' => time() ]; if ($existingSkuPrice) { // 更新现有记录 // 删除该商品的其他SKU价格记录(防止多规格改单规格遗留数据) $this->skuPriceModel ->where('goods_id', $goodsId) ->where('uniacid', UNIACID) ->where('id', '<>', $existingSkuPrice['id']) ->delete(); // 更新记录(不更新销量,销量是累计的) unset($data['sales']); $this->skuPriceModel->where('id', $existingSkuPrice['id'])->update($data); } else { // 新增记录 $data['createtime'] = time(); // 自动生成SKU编码(如果为空) if (empty($data['sn'])) { $data['sn'] = $this->generateSkuSn(); } // 先删除所有旧的SKU价格记录 $this->skuPriceModel->where('goods_id', $goodsId)->where('uniacid', UNIACID)->delete(); $this->skuPriceModel->insert($data); } } /** * 保存多规格SKU */ protected function saveMultiSku($goodsId, $skuData) { // 先删除所有旧的规格数据 $this->skuModel->where('goods_id', $goodsId)->where('uniacid', UNIACID)->delete(); $this->skuPriceModel->where('goods_id', $goodsId)->where('uniacid', UNIACID)->delete(); if (empty($skuData)) { return; } $skuNames = $skuData['sku_names'] ?? []; $skuPrices = $skuData['sku_prices'] ?? []; $skuIdMap = []; // 保存规格名称和规格值 if (!empty($skuNames)) { foreach ($skuNames as $skuName) { $specId = $this->skuModel->insertGetId([ 'goods_id' => $goodsId, 'uniacid' => UNIACID, 'name' => $skuName['name'] ?? '', 'parent_id' => 0, 'weigh' => $skuName['weigh'] ?? 0, 'createtime' => time(), 'updatetime' => time() ]); if (!empty($skuName['values'])) { foreach ($skuName['values'] as $index => $value) { $childId = $this->skuModel->insertGetId([ 'goods_id' => $goodsId, 'uniacid' => UNIACID, 'name' => $value, 'parent_id' => $specId, 'weigh' => $index, 'createtime' => time(), 'updatetime' => time() ]); $skuIdMap[$skuName['name']][$value] = $childId; } } } } // 保存SKU价格 if (!empty($skuPrices)) { foreach ($skuPrices as $skuPrice) { $skuIds = $skuPrice['sku_ids'] ?? []; $skuText = $skuPrice['sku_text'] ?? ''; $skuIdStr = ''; if (is_array($skuIds)) { $skuIdStr = implode(',', $skuIds); } // 自动生成SKU编码(如果为空) $sn = $skuPrice['sn'] ?? ''; if (empty($sn)) { $sn = $this->generateSkuSn(); } $this->skuPriceModel->insert([ 'goods_id' => $goodsId, 'uniacid' => UNIACID, 'goods_sku_ids' => $skuIdStr, 'goods_sku_text' => $skuText, 'image' => $skuPrice['image'] ?? '', 'stock' => $skuPrice['stock'] ?? 0, 'stock_warning' => $skuPrice['stock_warning'] ?? null, 'sales' => $skuPrice['sales'] ?? 0, 'sn' => $sn, 'weight' => $skuPrice['weight'] ?? 0, 'volume' => $skuPrice['volume'] ?? 0, 'cost_price' => $skuPrice['cost_price'] ?? 0, 'original_price' => $skuPrice['original_price'] ?? 0, 'price' => $skuPrice['price'] ?? 0, 'status' => $skuPrice['status'] ?? 1, 'weigh' => $skuPrice['weigh'] ?? 0, 'createtime' => time(), 'updatetime' => time() ]); } } } /** * 详情 */ public function detail($ids = null) { $row = $this->model->where('id', $ids)->where('uniacid', UNIACID)->find(); if (!$row) { $this->error(__('No Results were found')); } // 处理分类ID if (isset($row['category_id']) && !empty($row['category_id'])) { $row['category_id'] = explode(',', $row['category_id']); // 转换为整数数组 $row['category_id'] = array_map('intval', $row['category_id']); } else { $row['category_id'] = []; } $specType = $row['spec_type'] ?? 'single'; if ($specType == 'single') { // 单规格商品,从sku_price表读取第一条记录 $skuPrice = $this->skuPriceModel ->where('goods_id', $ids) ->where('uniacid', UNIACID) ->order('id', 'asc') ->find(); $row['sku_tree'] = []; if ($skuPrice) { $row['sku_prices'] = [$skuPrice]; } else { // 如果没有找到sku_price记录,返回空结构 $row['sku_prices'] = []; } } else { // 多规格商品,从sku表读取数据 $skuTree = $this->skuModel->getTree($ids); $skuPrices = $this->skuPriceModel->where('goods_id', $ids)->where('uniacid', UNIACID)->select(); $row['sku_tree'] = $skuTree; $row['sku_prices'] = $skuPrices; } $this->success("获取成功", $row); } /** * 更新商品价格 * 单规格:取单一价格 * 多规格:取最低价格 * @param int $goodsId 商品ID * @param string $specType 规格类型:single=单规格,multi=多规格 */ protected function updateGoodsPrice($goodsId, $specType = 'single') { $price = 0; if ($specType == 'single') { // 单规格:取第一个SKU的价格 $skuPrice = $this->skuPriceModel ->where('goods_id', $goodsId) ->where('uniacid', UNIACID) ->order('id', 'asc') ->find(); if ($skuPrice) { $price = $skuPrice['price'] ?? 0; } } else { // 多规格:取最低价格 $minPrice = $this->skuPriceModel ->where('goods_id', $goodsId) ->where('uniacid', UNIACID) ->min('price'); $price = $minPrice ?? 0; } // 更新商品价格 $this->model->where('id', $goodsId)->update([ 'price' => $price, 'updatetime' => time() ]); } /** * 更新商品库存 * 单规格:取单一库存(status=1) * 多规格:取所有规格库存之和(status=1) * @param int $goodsId 商品ID * @param string $specType 规格类型:single=单规格,multi=多规格 */ protected function updateGoodsStock($goodsId, $specType = 'single') { if (empty($goodsId)) { return; } $stock = 0; if ($specType == 'single') { $skuPrice = $this->skuPriceModel ->where('goods_id', $goodsId) ->where('uniacid', UNIACID) ->where('status', 1) ->order('id', 'asc') ->find(); if ($skuPrice) { $stock = $skuPrice['stock'] ?? 0; } } else { $totalStock = $this->skuPriceModel ->where('goods_id', $goodsId) ->where('uniacid', UNIACID) ->where('status', 1) ->sum('stock'); $stock = $totalStock ?? 0; } // 更新商品库存 $this->model->where('id', $goodsId)->where('uniacid', UNIACID)->update([ 'stock' => $stock, 'updatetime' => time() ]); } /** * 删除 */ public function del($ids = "") { if ($ids) { Db::startTrans(); try { $count = $this->model->where('id', 'in', $ids)->where('uniacid', UNIACID)->delete(); $this->skuModel->where('goods_id', 'in', $ids)->where('uniacid', UNIACID)->delete(); $this->skuPriceModel->where('goods_id', 'in', $ids)->where('uniacid', UNIACID)->delete(); Db::commit(); } catch (PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($count) { $this->success("删除成功"); } else { $this->error(__('No rows were deleted')); } } $this->error(__('Parameter %s can not be empty', 'ids')); } /** * 批量更新 */ public function multi($ids = "") { $ids = $ids ? $ids : $this->request->param("ids"); if ($ids) { if ($this->request->has('params')) { parse_str($this->request->post("params"), $values); $values = $this->preExcludeFields($values); $values['updatetime'] = time(); $result = $this->model->where('id', 'in', $ids)->where('uniacid', UNIACID)->update($values); if ($result) { $this->success("操作成功"); } else { $this->error(__('No rows were updated')); } } } $this->error(__('Parameter %s can not be empty', 'ids')); } /** * 批量更新SKU价格和库存 * 用于列表页快速编辑 */ public function updateSkuPrice() { $params = $this->request->param(); $goodsId = $params['goods_id'] ?? 0; $skuPrices = $params['sku_prices'] ?? []; if (empty($goodsId)) { $this->error('商品ID不能为空'); } if (empty($skuPrices) || !is_array($skuPrices)) { $this->error('SKU价格数据不能为空'); } Db::startTrans(); try { foreach ($skuPrices as $skuPrice) { $skuPriceId = $skuPrice['id'] ?? 0; if (empty($skuPriceId)) { continue; } $updateData = []; // 更新价格 if (isset($skuPrice['price'])) { $updateData['price'] = floatval($skuPrice['price']); } // 更新库存(支持增减) if (isset($skuPrice['stock_change'])) { $stockChange = intval($skuPrice['stock_change']); if ($stockChange > 0) { // 增加库存 $this->skuPriceModel->where('id', $skuPriceId) ->where('uniacid', UNIACID) ->setInc('stock', $stockChange); } elseif ($stockChange < 0) { // 减少库存 $this->skuPriceModel->where('id', $skuPriceId) ->where('uniacid', UNIACID) ->setDec('stock', abs($stockChange)); } } // 直接设置库存 if (isset($skuPrice['stock'])) { $updateData['stock'] = intval($skuPrice['stock']); } // 更新其他字段 if (!empty($updateData)) { $updateData['updatetime'] = time(); $this->skuPriceModel->where('id', $skuPriceId) ->where('uniacid', UNIACID) ->update($updateData); } } // 更新商品价格 $goods = $this->model->where('id', $goodsId)->where('uniacid', UNIACID)->find(); if ($goods) { $specType = $goods['spec_type'] ?? 'single'; $this->updateGoodsPrice($goodsId, $specType); } Db::commit(); $this->success('更新成功'); } catch (\Exception $e) { Db::rollback(); $this->error($e->getMessage()); } } /** * 获取状态列表 */ public function getStatusList() { $this->success("获取成功", $this->model->getStatusList()); } /** * 获取规格类型列表 */ public function getSpecTypeList() { $this->success("获取成功", $this->model->getSpecTypeList()); } /** * 获取隐藏状态列表 */ public function getIsHiddenList() { $this->success("获取成功", $this->model->getIsHiddenList()); } }