{{wikiTitle}}
商品流程说明
目录:
CRMEB多店系统商品流程说明
概述
本文档详细介绍CRMEB多店系统的商品管理流程,包括商品的增删改查、上下架、库存管理、分类管理等核心业务逻辑。
商品服务类位置
app/services/product/
├── product/
│ ├── StoreProductServices.php # 商品核心服务
│ ├── StoreProductAttrServices.php # 商品规格服务
│ ├── StoreProductAttrValueServices.php # 商品规格值服务
│ ├── StoreProductDescriptionServices.php # 商品详情服务
│ ├── StoreProductRelationServices.php # 商品关联服务
│ ├── StoreProductReplyServices.php # 商品评价服务
│ └── ...
├── category/
│ └── StoreCategoryServices.php # 商品分类服务
├── brand/
│ └── StoreBrandServices.php # 商品品牌服务
├── sku/
│ └── StoreProductAttrValueServices.php # SKU服务
├── shipping/
│ └── ShippingTemplatesServices.php # 运费模板服务
└── ...
商品数据模型
商品主表模型
// app/model/product/product/StoreProduct.php
class StoreProduct extends BaseModel
{
protected $name = 'store_product';
protected $pk = 'id';
// 关联规格
public function attr()
{
return $this->hasMany(StoreProductAttr::class, 'product_id', 'id');
}
// 关联规格值
public function attrValue()
{
return $this->hasMany(StoreProductAttrValue::class, 'product_id', 'id');
}
// 关联分类
public function cates()
{
return $this->hasMany(StoreProductCate::class, 'product_id', 'id');
}
// 关联品牌
public function brand()
{
return $this->hasOne(StoreBrand::class, 'id', 'brand_id');
}
// 关联详情
public function description()
{
return $this->hasOne(StoreProductDescription::class, 'product_id', 'id');
}
}
商品创建流程
1. 后台创建商品
// 服务: StoreProductServices.php
public function save(array $data)
{
return $this->transaction(function() use ($data) {
// 1. 处理商品基本信息
$productData = $this->setProductData($data);
// 2. 保存商品主表
$product = $this->dao->save($productData);
$productId = $product->id;
// 3. 保存商品规格
if ($data['spec_type'] == 1) {
$this->saveProductAttr($productId, $data['items'], $data['attrs']);
} else {
$this->saveProductAttrSingle($productId, $data);
}
// 4. 保存商品详情
$this->saveDescription($productId, $data['description']);
// 5. 保存商品分类关联
$this->saveProductCate($productId, $data['cate_id']);
// 6. 保存商品标签
$this->saveProductLabel($productId, $data['label_id'] ?? []);
// 7. 保存商品保障服务
$this->saveProductEnsure($productId, $data['ensure_id'] ?? []);
// 8. 触发商品创建事件
event('product.create', [$product]);
return $product;
});
}
2. 商品数据处理
protected function setProductData(array $data)
{
return [
'type' => $data['type'] ?? 0, // 商品类型
'relation_id' => $data['relation_id'] ?? 0, // 关联ID
'store_name' => $data['store_name'], // 商品名称
'store_info' => $data['store_info'] ?? '', // 商品简介
'keyword' => $data['keyword'] ?? '', // 关键字
'bar_code' => $data['bar_code'] ?? '', // 条码
'cate_id' => implode(',', $data['cate_id']), // 分类ID
'brand_id' => $data['brand_id'] ?? 0, // 品牌ID
'unit_name' => $data['unit_name'] ?? '件', // 单位
'sort' => $data['sort'] ?? 0, // 排序
'sales' => $data['sales'] ?? 0, // 销量
'ficti' => $data['ficti'] ?? 0, // 虚拟销量
'stock' => $data['stock'] ?? 0, // 库存
'price' => $data['price'] ?? 0, // 价格
'ot_price' => $data['ot_price'] ?? 0, // 原价
'cost' => $data['cost'] ?? 0, // 成本价
'vip_price' => $data['vip_price'] ?? 0, // 会员价
'postage' => $data['postage'] ?? 0, // 邮费
'give_integral' => $data['give_integral'] ?? 0, // 赠送积分
'is_show' => $data['is_show'] ?? 0, // 上架状态
'is_hot' => $data['is_hot'] ?? 0, // 热卖
'is_benefit' => $data['is_benefit'] ?? 0, // 促销
'is_best' => $data['is_best'] ?? 0, // 精品
'is_new' => $data['is_new'] ?? 0, // 新品
'is_good' => $data['is_good'] ?? 0, // 优品推荐
'is_sub' => $data['is_sub'] ?? 0, // 分销
'is_vip' => $data['is_vip'] ?? 0, // 会员价设置
'spec_type' => $data['spec_type'] ?? 0, // 规格类型
'temp_id' => $data['temp_id'] ?? 0, // 运费模板
'image' => $data['image'], // 主图
'slider_image' => json_encode($data['slider_image']), // 轮播图
'video_link' => $data['video_link'] ?? '', // 视频
'add_time' => time(),
];
}
3. 保存商品规格
// 多规格商品
protected function saveProductAttr($productId, $items, $attrs)
{
// 保存规格项
foreach ($items as $item) {
$attrData = [
'product_id' => $productId,
'attr_name' => $item['value'],
'attr_values' => implode(',', $item['detail']),
];
StoreProductAttr::create($attrData);
}
// 保存规格值(SKU)
foreach ($attrs as $attr) {
$attrValueData = [
'product_id' => $productId,
'suk' => $attr['detail'], // 规格组合
'unique' => $this->getAttrUnique(), // 唯一标识
'price' => $attr['price'], // 价格
'cost' => $attr['cost'], // 成本价
'ot_price' => $attr['ot_price'], // 原价
'stock' => $attr['stock'], // 库存
'image' => $attr['pic'] ?? '', // 规格图片
'bar_code' => $attr['bar_code'] ?? '', // 条码
'weight' => $attr['weight'] ?? 0, // 重量
'volume' => $attr['volume'] ?? 0, // 体积
];
StoreProductAttrValue::create($attrValueData);
}
}
// 单规格商品
protected function saveProductAttrSingle($productId, $data)
{
$attrValueData = [
'product_id' => $productId,
'suk' => '默认',
'unique' => $this->getAttrUnique(),
'price' => $data['price'],
'cost' => $data['cost'],
'ot_price' => $data['ot_price'],
'stock' => $data['stock'],
'image' => $data['image'],
'bar_code' => $data['bar_code'] ?? '',
'weight' => $data['weight'] ?? 0,
'volume' => $data['volume'] ?? 0,
];
StoreProductAttrValue::create($attrValueData);
}
商品修改流程
public function update(int $id, array $data)
{
return $this->transaction(function() use ($id, $data) {
// 1. 更新商品基本信息
$productData = $this->setProductData($data);
$this->dao->update($id, $productData);
// 2. 删除旧规格数据
$this->deleteProductAttr($id);
// 3. 保存新规格数据
if ($data['spec_type'] == 1) {
$this->saveProductAttr($id, $data['items'], $data['attrs']);
} else {
$this->saveProductAttrSingle($id, $data);
}
// 4. 更新商品详情
$this->updateDescription($id, $data['description']);
// 5. 更新商品分类关联
$this->updateProductCate($id, $data['cate_id']);
// 6. 触发商品更新事件
event('product.update', [$id, $data]);
return true;
});
}
商品上下架
上架商品
public function setShow(int $id, int $isShow)
{
$product = $this->dao->get($id);
if (!$product) {
throw new ValidateException('商品不存在');
}
// 验证商品信息完整性
if ($isShow == 1) {
$this->validateProductInfo($product);
}
// 更新上架状态
$this->dao->update($id, ['is_show' => $isShow]);
// 触发状态变更事件
event('product.status', [$id, $isShow]);
return true;
}
批量上下架
public function setShowBatch(array $ids, int $isShow)
{
foreach ($ids as $id) {
$this->setShow($id, $isShow);
}
return true;
}
商品删除流程
移入回收站
public function del(int $id)
{
$product = $this->dao->get($id);
if (!$product) {
throw new ValidateException('商品不存在');
}
// 软删除(移入回收站)
$this->dao->update($id, ['is_del' => 1]);
// 触发删除事件
event('product.delete', [$id]);
return true;
}
彻底删除
public function destroy(int $id)
{
return $this->transaction(function() use ($id) {
// 删除商品主表
$this->dao->delete($id);
// 删除规格
StoreProductAttr::where('product_id', $id)->delete();
StoreProductAttrValue::where('product_id', $id)->delete();
// 删除详情
StoreProductDescription::where('product_id', $id)->delete();
// 删除分类关联
StoreProductCate::where('product_id', $id)->delete();
return true;
});
}
恢复商品
public function restore(int $id)
{
$this->dao->update($id, ['is_del' => 0]);
return true;
}
库存管理
扣减库存
public function decProductStock(int $productId, string $unique, int $num)
{
return $this->transaction(function() use ($productId, $unique, $num) {
// 扣减SKU库存
$attrValue = StoreProductAttrValue::where('product_id', $productId)
->where('unique', $unique)
->find();
if ($attrValue->stock < $num) {
throw new ValidateException('库存不足');
}
$attrValue->dec('stock', $num)->update();
// 扣减商品总库存
$this->dao->decStock($productId, $num);
// 增加销量
$this->dao->incSales($productId, $num);
return true;
});
}
回退库存
public function incProductStock(int $productId, string $unique, int $num)
{
return $this->transaction(function() use ($productId, $unique, $num) {
// 增加SKU库存
StoreProductAttrValue::where('product_id', $productId)
->where('unique', $unique)
->inc('stock', $num)
->update();
// 增加商品总库存
$this->dao->incStock($productId, $num);
// 减少销量
$this->dao->decSales($productId, $num);
return true;
});
}
库存预警
public function getStockWarningList(int $limit = 10)
{
$warningStock = sys_config('store_stock', 2);
return $this->dao->getList([
'stock' => ['<', $warningStock],
'is_del' => 0,
'is_show' => 1,
], 0, $limit);
}
分类管理
分类服务
// app/services/product/category/StoreCategoryServices.php
class StoreCategoryServices extends BaseServices
{
// 获取分类树
public function getCateTree()
{
$list = $this->dao->getList(['is_del' => 0], 0, 0, 'sort desc, id desc');
return $this->buildTree($list);
}
// 构建树形结构
protected function buildTree($list, $pid = 0)
{
$tree = [];
foreach ($list as $item) {
if ($item['pid'] == $pid) {
$item['children'] = $this->buildTree($list, $item['id']);
$tree[] = $item;
}
}
return $tree;
}
// 创建分类
public function create(array $data)
{
return $this->dao->save([
'pid' => $data['pid'] ?? 0,
'cate_name' => $data['cate_name'],
'pic' => $data['pic'] ?? '',
'sort' => $data['sort'] ?? 0,
'is_show' => $data['is_show'] ?? 1,
]);
}
// 更新分类
public function update(int $id, array $data)
{
return $this->dao->update($id, [
'pid' => $data['pid'] ?? 0,
'cate_name' => $data['cate_name'],
'pic' => $data['pic'] ?? '',
'sort' => $data['sort'] ?? 0,
'is_show' => $data['is_show'] ?? 1,
]);
}
// 删除分类
public function delete(int $id)
{
// 检查是否有子分类
if ($this->dao->count(['pid' => $id])) {
throw new ValidateException('存在子分类,无法删除');
}
// 检查是否有关联商品
if (StoreProductCate::where('cate_id', $id)->count()) {
throw new ValidateException('分类下存在商品,无法删除');
}
return $this->dao->delete($id);
}
}
商品搜索与筛选
public function getProductList(array $where, int $page, int $limit)
{
// 构建查询条件
$conditions = [];
// 关键词搜索
if (!empty($where['keyword'])) {
$conditions[] = ['store_name|keyword', 'like', '%' . $where['keyword'] . '%'];
}
// 分类筛选
if (!empty($where['cate_id'])) {
$productIds = StoreProductCate::where('cate_id', $where['cate_id'])
->column('product_id');
$conditions[] = ['id', 'in', $productIds];
}
// 品牌筛选
if (!empty($where['brand_id'])) {
$conditions[] = ['brand_id', '=', $where['brand_id']];
}
// 价格区间
if (!empty($where['price_min'])) {
$conditions[] = ['price', '>=', $where['price_min']];
}
if (!empty($where['price_max'])) {
$conditions[] = ['price', '<=', $where['price_max']];
}
// 上架状态
$conditions[] = ['is_show', '=', 1];
$conditions[] = ['is_del', '=', 0];
// 排序
$order = $this->getOrderBy($where['order'] ?? 'default');
return $this->dao->getList($conditions, $page, $limit, $order);
}
protected function getOrderBy($type)
{
switch ($type) {
case 'sales':
return 'sales desc, id desc';
case 'price_asc':
return 'price asc, id desc';
case 'price_desc':
return 'price desc, id desc';
case 'new':
return 'id desc';
default:
return 'sort desc, id desc';
}
}
商品评价管理
// app/services/product/product/StoreProductReplyServices.php
// 获取商品评价列表
public function getReplyList(int $productId, int $page, int $limit)
{
return $this->dao->getList([
'product_id' => $productId,
'is_del' => 0,
], $page, $limit);
}
// 获取评价统计
public function getReplyStatistics(int $productId)
{
$total = $this->dao->count(['product_id' => $productId, 'is_del' => 0]);
$good = $this->dao->count(['product_id' => $productId, 'is_del' => 0, 'product_score' => ['>=', 4]]);
$medium = $this->dao->count(['product_id' => $productId, 'is_del' => 0, 'product_score' => ['between', [2, 3]]]);
$bad = $this->dao->count(['product_id' => $productId, 'is_del' => 0, 'product_score' => ['<', 2]]);
return [
'total' => $total,
'good' => $good,
'medium' => $medium,
'bad' => $bad,
'good_rate' => $total > 0 ? round($good / $total * 100, 1) : 100,
];
}
// 创建评价
public function createReply(int $uid, int $orderId, array $data)
{
return $this->transaction(function() use ($uid, $orderId, $data) {
foreach ($data as $item) {
$replyData = [
'uid' => $uid,
'oid' => $orderId,
'product_id' => $item['product_id'],
'unique' => $item['unique'] ?? '',
'product_score' => $item['product_score'],
'service_score' => $item['service_score'],
'comment' => $item['comment'],
'pics' => json_encode($item['pics'] ?? []),
'add_time' => time(),
];
$this->dao->save($replyData);
// 触发评价事件
event('product.reply', [$replyData]);
}
return true;
});
}
商品相关事件
| 事件名称 | 说明 |
|---|---|
| product.create | 商品创建 |
| product.update | 商品更新 |
| product.delete | 商品删除 |
| product.status | 商品状态变更 |
| product.reply | 商品评价 |
| product.collect | 商品收藏 |
API接口列表
后台接口
| 方法 | 路由 | 说明 |
|---|---|---|
| GET | /adminapi/product/product | 商品列表 |
| GET | /adminapi/product/product/:id | 商品详情 |
| POST | /adminapi/product/product | 创建商品 |
| PUT | /adminapi/product/product/:id | 更新商品 |
| DELETE | /adminapi/product/product/:id | 删除商品 |
| PUT | /adminapi/product/product/set_show/:id | 上下架 |
前端接口
| 方法 | 路由 | 说明 |
|---|---|---|
| GET | /api/products | 商品列表 |
| GET | /api/product/detail/:id | 商品详情 |
| GET | /api/reply/list/:id | 商品评价列表 |
| GET | /api/category | 商品分类 |
注意事项
- 库存安全:库存操作需要使用事务和乐观锁
- 规格管理:修改规格时需要同步更新订单商品信息
- 缓存清理:商品修改后需清理相关缓存
- 图片处理:商品图片需要压缩处理优化加载速度
- SEO优化:合理设置商品关键词提升搜索排名
评论({{cateWiki.comment_num}})
{{commentWhere.order ? '评论从旧到新':'评论从新到旧'}}
{{cateWiki.page_view_num}}人看过该文档
评论(0)
{{commentWhere.order ? '评论从旧到新':'评论从新到旧'}}
13人看过该文档
{{item.user ? item.user.nickname : ''}}
(自评)
{{item.content}}
{{item.create_time}}
删除
搜索结果
为您找到{{wikiCount}}条结果
{{item.page_view_num}}
{{item.like ? item.like.like_num : 0}}
{{item.comment ? item.comment.comment_num : 0}}
位置:
{{path.name}}
{{(i+1) == item.catalogue.path_data.length ? '':'/'}}