get([ 'name', 'spu', 'category_id', 'created_at', 'is_show', 'page/d' => 1, 'size/d' => 10 ]); $validate = new ProductValidate(); if (!$validate->scene('index')->check($param)) { return error($validate->getError()); } $products = ProductModel::field([ 'id', 'name', 'cover_image', 'spu', 'category_id', 'sort', 'is_new', 'is_hot', 'is_sale', 'is_show', 'stock_qty', 'status', 'created_at' ]) ->with('category') ->language(request()->lang_id) ->withSearch(['name_nullable', 'spu_nullable', 'created_at_nullable'], [ 'name_nullable' => $param['name']??null, 'spu_nullable' => $param['spu']??null, 'created_at_nullable' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null, ]) ->categoryNullable($param['category_id']??null) ->isShowNullable(isset($param['is_show']) ? (bool)$param['is_show'] : null) ->order(['sort' => 'asc', 'id' => 'desc']) ->paginate([ 'list_rows' => $param['size'], 'page' => $param['page'], ]) ->bindAttr('category', ['category_name' => 'name']) ->hidden(['category_id', 'category']) ?->each(fn($item) => $item->cover_image = thumb($item->cover_image)); return success('获取成功', $products); } // 产品详情 public function read() { $product = ProductModel::with(['category' => function($query) { $query->field(['id', 'name' => 'category_name']); }]) ->withoutField([ 'language_id', 'created_at', 'updated_at', 'deleted_at' ]) ->bypk(request()->param('id')) ->find() ->bindAttr('category', ['category_name']) ->hidden(['category']); if (empty($product)) { return error('产品不存在'); } // 获取产品参数 $params = []; $product_params = ProductParamsModel::productId($product->id)->select(); foreach ($product_params as $val) { $params[] = implode(":", [$val->name, $val->value]); } $product->params = implode(PHP_EOL, $params); // 获取sku数据 $product->skus = ProductSkuModel::withoutField(['created_at', 'updated_at']) ->with(['attrs' => function($query) { $query->hidden(['sku_id']); }]) ->productId($product->id) ->select() ->hidden(['id', 'product_id']); // 获取关联产品 $product->related = ProductRelatedModel::field([ 'related_product_id', 'sort' ]) ->with(['product' => function($query) { $query->field(['id', 'spu']); }]) ->productId($product->id) ->select() ->bindAttr('product', ['spu']) ->hidden(['product']); return success('获取成功', $product); } // 更新 public function update() { $id = request()->param('id'); $put = request()->put([ 'category_id', 'spu', 'name', 'short_name', 'cover_image', 'desc', 'video_img', 'video_url', 'is_sale', 'is_new', 'is_hot', 'is_show', 'sort', 'detail', 'params' => '', 'skus' => '', 'related' => '', 'seo_title', 'seo_keywords', 'seo_desc' ]); $put = array_merge( $put, ['skus' => json_decode($put['skus'], true)], ['related' => json_decode($put['related'], true)], ); $validate = new ProductValidate(); $check_data = array_merge($put, ['id' => $id, 'language_id' => request()->lang_id]); if (!$validate->scene('update')->check($check_data)) { return error($validate->getError()); } $product = ProductModel::bypk($id)->find(); if (is_null($product)) { return error('请确认操作对象是否存在'); } if (!$product->save($put)) { return error('操作失败'); } // 更新产品参数 if ($put['params'] != "") { ProductParamsModel::productId($id)->delete(); if (preg_match_all('/(\S+):(.[^\s]+)/', $put['params'], $match_result)) { $params = []; for ($i = 0; $i < count($match_result[0]); $i++) { $params[] = [ 'product_id' => $id, 'name' => $match_result[1][$i], 'value' => $match_result[2][$i] ]; } if (!empty($params)) { ProductParamsModel::insertAll($params); } } } // 更新SKU if (!empty($put['skus'])) { $skus = []; $attrs_group = []; foreach ($put['skus'] as $val) { $skus[] = [ 'product_id' => $id, 'sku' => $val['sku'], 'main_image' => $val['main_image'], 'photo_album' => $val['photo_album'], 'sort' => $val['sort']??0 ]; foreach ($val['attrs'] as $v) { $attrs_group[$val['sku']][] = [ 'attr_id' => $v['attr_id'], 'attr_value' => $v['attr_value'] ]; } } if (!empty($skus)) { $sku_model = new ProductSkuModel; // 删除原有SKU $sku_model->productId($id)->delete(); // 添加SKU $save_ret = $sku_model->saveAll($skus); if (!$save_ret->isEmpty()) { $sku_map = []; foreach ($save_ret as $val) { $sku_map[$val->sku] = $val->id; } $attrs = []; foreach ($attrs_group as $sku => $sku_attrs) { if (empty($sku_map[$sku])) { unset($attrs_group[$sku]); continue; } foreach ($sku_attrs as $k => $v) { $attrs[] = array_merge($v, ['sku_id' => $sku_map[$sku]]); } } (new ProductSkuAttrModel)->saveAll($attrs); } } } // 更新关联产品 if (!empty($put['related'])) { // 删除原有关联产品 ProductRelatedModel::productId($id)->delete(); // 添加关联产品 $related = []; foreach ($put['related'] as $val) { $related[] = [ 'product_id' => $id, 'related_product_id' => $val['related_product_id'], 'sort' => $val['sort'] ]; } if (!empty($related)) { ProductRelatedModel::insertAll($related); } } return success('操作成功'); } // 设置排序值 public function sort() { $id = request()->param('id'); $sort = request()->post('sort'); $product = ProductModel::bypk($id)->find(); if (empty($product)) { return error('请确认操作对象是否存在'); } if ($sort != $product->sort) { $product->sort = $sort; if (!$product->save()) { return error('操作失败'); } } return success('操作成功'); } // 上下架操作 public function updownShelves() { $id = request()->param('id'); $product = ProductModel::bypk($id)->find(); if (empty($product)) { return error('请确认操作对象是否存在'); } $product->is_show = (int)!$product->is_show; if (!$product->save()) { return error('操作失败'); } return success('操作成功'); } // 删除 public function delete() { $product = ProductModel::bypk(request()->param('id'))->find(); if (empty($product)) { return error('请确认操作对象是否存在'); } // 软删除 if (!$product->delete()) { return error('操作失败'); } return success('操作成功'); } // 导出 public function export() { $schema = [ 'id' => 'ID', 'category_name' => '分类名称', 'spu' => '规格型号', 'name' => '产品名称', 'short_name' => '简称(产品副标题)', 'cover_image' => '产品封面图片', 'desc' => '描述', 'video_img' => '视频封面图片', 'video_url' => '视频地址', 'is_sale' => '是否在售', 'is_new' => '是否新品', 'is_hot' => '是否热销', 'is_show' => '上下架状态', 'stock_qty' => '库存数量', 'sort' => '排序值', 'detail' => '产品详情', 'params' => '产品参数', 'related' => '关联产品', 'status' => '状态', 'seo_title' => 'seo标题', 'seo_keywords' => 'seo关键词', 'seo_desc' => 'seo描述', 'created_at' => '添加时间', 'updated_at' => '最后更新时间' ]; // 获取导出数据 $data = $this->getExportProductData(); // 导出 return xlsx_writer($data, $schema, '产品列表' . date('YmdHis')); } // 获取产品导出数据 private function getExportProductData() { $server = request()->server(); $image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . config('filesystem.disks.public.url') . '/'; $param = request()->param([ 'name', 'spu', 'category_id', 'created_at', 'is_show', ]); $products = ProductModel::field([ 'id', 'category_id', 'spu', 'name', 'short_name', 'CONCAT("' . $image_host . '", `cover_image`)' => 'cover_image', 'desc', 'CONCAT("' . $image_host . '", `video_img`)' => 'video_img', 'CONCAT("' . $image_host . '", `video_url`)' => 'video_url', 'CASE WHEN is_new = 1 THEN "是" ELSE "否" END' => 'is_new', 'CASE WHEN is_hot = 1 THEN "是" ELSE "否" END' => 'is_hot', 'CASE WHEN is_sale = 1 THEN "是" ELSE "否" END' => 'is_sale', 'CASE WHEN is_show = 1 THEN "上架" ELSE "下架" END' => 'is_show', 'stock_qty', 'sort', 'detail', 'CASE WHEN status = 1 THEN "启用" WHEN status = -1 THEN "禁用" END' => 'status', 'seo_title', 'seo_keywords', 'seo_desc', 'created_at', 'updated_at', ]) ->with('category') ->language(request()->lang_id) ->withSearch(['name_nullable', 'spu_nullable', 'created_at_nullable'], [ 'name_nullable' => $param['name']??null, 'spu_nullable' => $param['spu']??null, 'created_at_nullable' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null, ]) ->categoryNullable($param['category_id']??null) ->isShowNullable(isset($param['is_show']) ? (bool)$param['is_show'] : null) ->order(['id' => 'asc']) ->select() ->bindAttr('category', ['category_name' => 'name']) ->hidden(['category_id', 'category']); if (!$products->isEmpty()) { // 产品参数 $product_params = ProductParamsModel::withoutField(['id', 'created_at', 'updated_at']) ->productId($products->column('id')) ->select(); if (!$product_params->isEmpty()) { $params = []; foreach ($product_params as $item) { $params[$item['product_id']][] = $item->name . ':' . $item->value; } $products->each(function($product) use($params) { if (empty($params[$product->id])) { return; } $product->params = implode(PHP_EOL, $params[$product->id]); }); } // 关联产品 $product_related = ProductRelatedModel::withoutField(['id', 'created_at', 'updated_at']) ->with(['product' => function($query) { $query->field(['id', 'spu']); }]) ->productId($products->column('id')) ->order(['sort' => 'asc']) ->select(); if (!$product_related->isEmpty()) { $related = []; foreach ($product_related as $item) { if (!empty($item->product)) { $related[$item['product_id']][] = $item->product->spu; } } $products->each(function($product) use($related) { if (empty($related[$product->id])) { return; } $product->related = implode(',', $related[$product->id]); }); } } return $products->toArray(); } }