帮助文档
{{userInfo.nickname}}
用户设置 退出登录

{{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 商品分类

注意事项

  1. 库存安全:库存操作需要使用事务和乐观锁
  2. 规格管理:修改规格时需要同步更新订单商品信息
  3. 缓存清理:商品修改后需清理相关缓存
  4. 图片处理:商品图片需要压缩处理优化加载速度
  5. SEO优化:合理设置商品关键词提升搜索排名
{{cateWiki.like_num}}人点赞
0人点赞
评论({{cateWiki.comment_num}}) {{commentWhere.order ? '评论从旧到新':'评论从新到旧'}} {{cateWiki.page_view_num}}人看过该文档
评论(0) {{commentWhere.order ? '评论从旧到新':'评论从新到旧'}} 13人看过该文档
评论
{{item.user ? item.user.nickname : ''}} (自评)
{{item.content}}
{{item.create_time}} 删除
{{item.like ? item.like.like_num : 0}} {{replyIndex == index ? '取消回复' : '回复'}}
评论
{{items.user ? items.user.nickname : '暂无昵称'}} (自评)
{{items.content}}
{{items.create_time}} 删除
{{items.like ? items.like.like_num : 0}} {{replyIndexJ == (index+'|'+indexJ) ? '取消回复' : '回复'}}
评论
目录
  • {{item}}