You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
9.9 KiB
273 lines
9.9 KiB
11 months ago
|
<?php
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | Author: 萤火科技 <admin@yiovo.com>
|
||
|
// +----------------------------------------------------------------------
|
||
|
declare (strict_types=1);
|
||
|
|
||
|
namespace app\store\model\sharp;
|
||
|
|
||
|
use app\store\model\Goods as GoodsModel;
|
||
|
use app\store\model\sharp\GoodsSku as GoodsSkuModel;
|
||
|
use app\store\model\GoodsSpecRel as GoodsSpecRelModel;
|
||
|
use app\store\model\sharp\ActiveGoods as ActiveGoodsModel;
|
||
|
use app\common\model\sharp\Goods as SharpGoodsModel;
|
||
|
use app\common\enum\goods\SpecType as SpecTypeEnum;
|
||
|
use app\common\library\helper;
|
||
|
use cores\exception\BaseException;
|
||
|
|
||
|
/**
|
||
|
* 整点秒杀-商品模型
|
||
|
* Class Goods
|
||
|
* @package app\store\model\sharp
|
||
|
*/
|
||
|
class Goods extends SharpGoodsModel
|
||
|
{
|
||
|
const EVENT_ADD = 'add';
|
||
|
const EVENT_EDIT = 'edit';
|
||
|
|
||
|
/**
|
||
|
* 获取列表数据
|
||
|
* @param string $search
|
||
|
* @return mixed
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
public function getList(string $search = '')
|
||
|
{
|
||
|
// 设置基础查询条件
|
||
|
$query = $this->setBaseQuery($this->alias, [['goods', 'goods_id']]);
|
||
|
// 检索查询条件
|
||
|
!empty($search) && $query->where('goods.goods_name', 'like', "%{$search}%");
|
||
|
// 获取活动列表
|
||
|
$list = $query->where("{$this->alias}.is_delete", '=', 0)
|
||
|
->order(["{$this->alias}.sort" => 'asc', "{$this->alias}.create_time" => 'desc'])
|
||
|
->paginate(15);
|
||
|
// 设置商品数据
|
||
|
return !$list->isEmpty() ? $this->setGoodsListData($list, true) : $list;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 获取秒杀商品详情
|
||
|
* @param int $sharpGoodsId 秒杀商品ID
|
||
|
* @return Goods|array|null
|
||
|
* @throws BaseException
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
public function getDetail(int $sharpGoodsId)
|
||
|
{
|
||
|
// 获取商品记录
|
||
|
$goodsInfo = static::detail($sharpGoodsId, ['skuList']);
|
||
|
empty($goodsInfo) && throwError('很抱歉,商品信息不存在');
|
||
|
// 商品多规格处理
|
||
|
if ($goodsInfo['spec_type'] == SpecTypeEnum::MULTI) {
|
||
|
// 秒杀商品SKU填充主商品参数(商品价格、库存数量、商品sku编码)
|
||
|
$goodsInfo['skuList'] = GoodsSkuModel::getCommonSkuList($goodsInfo['skuList'], $goodsInfo['goods_id']);
|
||
|
// 商品规格属性列表
|
||
|
$goodsInfo['specList'] = GoodsSpecRelModel::getSpecList($goodsInfo['goods_id']);
|
||
|
}
|
||
|
return $goodsInfo;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 根据商品ID集获取商品列表
|
||
|
* @param array $goodsIds
|
||
|
* @param array $param
|
||
|
* @return mixed
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
public function getListByIds(array $goodsIds, array $param = [])
|
||
|
{
|
||
|
// 获取商品列表数据
|
||
|
return parent::getListByIds($goodsIds, $param);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 添加秒杀商品
|
||
|
* @param array $data
|
||
|
* @return bool
|
||
|
* @throws BaseException
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
public function add(array $data): bool
|
||
|
{
|
||
|
// 验证主商品能否被添加为秒杀商品
|
||
|
if (!$this->validateGoodsId((int)$data['goods_id'])) {
|
||
|
return false;
|
||
|
}
|
||
|
// 获取主商品基本信息
|
||
|
$goodsInfo = (new GoodsModel)->getBasic((int)$data['goods_id']);
|
||
|
// 记录商品ID、规格类型、秒杀价格及库存
|
||
|
$data['goods_id'] = $goodsInfo['goods_id'];
|
||
|
$data['spec_type'] = $goodsInfo['spec_type'];
|
||
|
$data['seckill_price'] = $goodsInfo['goods_price_min'];
|
||
|
$data['seckill_stock'] = $goodsInfo['stock_total'];
|
||
|
// 创建秒杀商品数据
|
||
|
$data = $this->createData($data, self::EVENT_ADD);
|
||
|
// 事务处理
|
||
|
$this->transaction(function () use ($data) {
|
||
|
// 添加商品
|
||
|
$this->save($data);
|
||
|
// 更新商品sku信息
|
||
|
GoodsSkuModel::add((int)$this['sharp_goods_id'], $this['spec_type'], $data['newSkuList']);
|
||
|
});
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 编辑商品
|
||
|
* @param array $data
|
||
|
* @return bool
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
public function edit(array $data): bool
|
||
|
{
|
||
|
// 记录商品ID和规格类型
|
||
|
$data['goods_id'] = $this['goods_id'];
|
||
|
$data['spec_type'] = $this['spec_type'];
|
||
|
// 创建秒杀商品数据
|
||
|
$data = $this->createData($data, self::EVENT_EDIT);
|
||
|
// 事务处理
|
||
|
$this->transaction(function () use ($data) {
|
||
|
// 更新商品
|
||
|
$this->save($data);
|
||
|
// 更新商品sku信息
|
||
|
GoodsSkuModel::edit((int)$this['sharp_goods_id'], $this['spec_type'], $data['newSkuList']);
|
||
|
});
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 创建商品数据
|
||
|
* @param array $data
|
||
|
* @param string $event
|
||
|
* @return array
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
private function createData(array $data, string $event = self::EVENT_ADD): array
|
||
|
{
|
||
|
// 默认数据
|
||
|
$data = array_merge($data, [
|
||
|
'newSkuList' => [],
|
||
|
'store_id' => self::$storeId,
|
||
|
]);
|
||
|
// 规格和sku数据处理
|
||
|
$data['newSkuList'] = $this->getNewSkuList($data, $event);
|
||
|
// 库存总量 seckill_stock
|
||
|
// 商品价格 最低最高
|
||
|
if ($data['spec_type'] == SpecTypeEnum::MULTI) {
|
||
|
$data['seckill_stock'] = GoodsSkuModel::getStockTotal($data['newSkuList']);
|
||
|
[$data['seckill_price_min'], $data['seckill_price_max']] = GoodsSkuModel::getGoodsPrices($data['newSkuList']);
|
||
|
} elseif ($data['spec_type'] == SpecTypeEnum::SINGLE) {
|
||
|
$data['seckill_price_min'] = $data['seckill_price_max'] = $data['seckill_price'];
|
||
|
// $data['seckill_stock'] = $data['seckill_stock'];
|
||
|
}
|
||
|
return $data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 生成新的SKU列表数据
|
||
|
* @param array $data
|
||
|
* @param string $event
|
||
|
* @return array
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
private function getNewSkuList(array $data, string $event = self::EVENT_ADD): array
|
||
|
{
|
||
|
if ($event === self::EVENT_ADD) {
|
||
|
// 生成默认的skuList
|
||
|
if ($data['spec_type'] == SpecTypeEnum::MULTI) {
|
||
|
return GoodsSkuModel::getDefaultSkuList($data['goods_id']);
|
||
|
}
|
||
|
return helper::pick($data, ['seckill_price', 'seckill_stock']);
|
||
|
}
|
||
|
return $this->getNewSkuListByEdit($data, $event);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 生成新的SKU列表数据(用于编辑事件)
|
||
|
* @param array $data
|
||
|
* @param string $event
|
||
|
* @return array
|
||
|
* @throws \think\db\exception\DataNotFoundException
|
||
|
* @throws \think\db\exception\DbException
|
||
|
* @throws \think\db\exception\ModelNotFoundException
|
||
|
*/
|
||
|
private function getNewSkuListByEdit(array $data, string $event = self::EVENT_ADD): array
|
||
|
{
|
||
|
// 规格和sku数据处理
|
||
|
if ($data['spec_type'] == SpecTypeEnum::MULTI) {
|
||
|
// 生成skuList ( 携带goods_sku_id )
|
||
|
return GoodsSkuModel::getNewSkuList($data['goods_id'], $data['specData']['skuList']);
|
||
|
} elseif ($data['spec_type'] == SpecTypeEnum::SINGLE) {
|
||
|
// 生成skuItem
|
||
|
return helper::pick($data, ['seckill_price', 'seckill_stock']);
|
||
|
}
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 验证主商品能否被添加为秒杀商品
|
||
|
* @param int $goodsId 主商品ID
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function validateGoodsId(int $goodsId): bool
|
||
|
{
|
||
|
if (empty($goodsId)) {
|
||
|
$this->error = '很抱歉,您还没有选择商品';
|
||
|
return false;
|
||
|
}
|
||
|
// 验证是否存在秒杀商品
|
||
|
if ($this->isExistGoodsId($goodsId)) {
|
||
|
$this->error = '很抱歉,该商品已存在,无需重复添加';
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 验证指定商品是否已添加秒杀商品
|
||
|
* @param int $goodsId 主商品ID
|
||
|
* @return bool
|
||
|
*/
|
||
|
public static function isExistGoodsId(int $goodsId): bool
|
||
|
{
|
||
|
return (bool)(new static)->where('goods_id', '=', $goodsId)
|
||
|
->where('is_delete', '=', 0)
|
||
|
->value('sharp_goods_id');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 软删除
|
||
|
* @return mixed
|
||
|
*/
|
||
|
public function setDelete()
|
||
|
{
|
||
|
return $this->transaction(function () {
|
||
|
// 同步删除活动会场与商品关联记录
|
||
|
ActiveGoodsModel::deleteSharpGoods((int)$this['sharp_goods_id']);
|
||
|
// 删除所有的sku记录
|
||
|
GoodsSkuModel::deleteAll(['sharp_goods_id' => $this['sharp_goods_id']]);
|
||
|
// 标记当前秒杀商品已删除
|
||
|
return $this->save(['is_delete' => 1]);
|
||
|
});
|
||
|
}
|
||
|
}
|