Goods.php 10.4 KB
<?php

namespace addons\groupon\model;

use think\Model;
use addons\groupon\exception\Exception;
use addons\groupon\model\GoodsSku;
use addons\groupon\model\GoodsSkuPrice;
use think\Db;
use traits\model\SoftDelete;
use addons\groupon\library\traits\model\goods\GoodsActivity;

/**
 * 商品模型
 */
class Goods extends Model
{
    use SoftDelete, GoodsActivity;

    // 表名,不含前缀
    protected $name = 'groupon_goods';
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';
    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    protected $deleteTime = 'deletetime';

    protected $hidden = ['createtime', 'updatetime', 'status'];
    //列表动态隐藏字段
    public static $list_hidden = ['content', 'params', 'images', 'service_ids'];

    // 追加属性
    protected $append = [
        'activity_status',
        'tags_arr',
        'limit_rules_arr'
    ];


    /**
     * params 请求参数
     * is_page 是否分页
     */
    public static function getGoodsList($params, $is_page = true)
    {
        extract($params);
        $where = [
            'status' => ['in', ((isset($type) && $type == 'all') ? ['up', 'hidden'] : ['up'])],     // type = all 查询全部
        ];
        //排序字段
        if (isset($order)) {
            $order = self::getGoodsListOrder($order);

        }else{
            $order = 'weigh desc';
        }
        if (isset($keywords) && $keywords !== '') {
            $where['title|subtitle'] = ['like', "%$keywords%"];
        }

        if (isset($goods_ids) && $goods_ids !== '') {
            $order = 'field(id, ' . $goods_ids . ')';       // 如果传了 goods_ids 就按照里面的 id 进行排序
            $goodsIdsArray = explode(',', $goods_ids);
            $where['id'] = ['in', $goodsIdsArray];
        }

        $category_ids = [];
        if (isset($category_id) && $category_id != 0) {
            // 查询分类所有子分类,包括自己
            $category_ids = Category::getCategoryIds($category_id);
        }

        $goods = self::where($where)->where(function ($query) use ($category_ids) {
            // 所有子分类使用 find_in_set or 匹配,亲测速度并不慢
            foreach($category_ids as $key => $category_id) {
                $category_id = filter_sql($category_id);
                $query->whereOrRaw("find_in_set($category_id, category_ids)");
            }
        });

        $order = filter_sql($order);
        $goods = $goods->field('*,(sales + show_sales) as total_sales')->orderRaw($order);

        $cacheKey = 'goodslist-' . ($is_page ? 'page' : 'all') . '-' . md5(json_encode($params));

        // 判断缓存
        $goodsCache = cache($cacheKey);
        if ($goodsCache) {
            // 存在缓存直接 返回
            $goodsCache = json_decode($goodsCache, true);
            return $goodsCache ? : [];
        } 

        if ($is_page) {
            $goods = $goods->paginate($per_page ?? 10);
            $goodsData = $goods->items();
        } else {
            $goods = $goodsData = $goods->select();
        }

        $data = [];
        if ($goodsData) {
            $collection = collection($goodsData);
            $data = $collection->hidden(self::$list_hidden);
            
            // 处理活动
            // load_relation($data, 'skuPrice');        // 只针对数组
            $data->load('skuPrice');        // 延迟预加载

            // 默认查询活动, no_activity 的时候这里也要执行一下,这里计算了销量规格等信息
            foreach ($data as $key => $g) {
                $data[$key] = self::operActivity($g, $g['sku_price']);
            }
        }

        if ($is_page) {
            $goods->data = $data;
        } else {
            $goods = $data;
            
            // 目前只缓存不分页的请求, 
            // 缓存暂时注释,如果需要,可以打开,请注意后台更新商品记得清除缓存
            // cache($cacheKey, json_encode($goods), (600 + mt_rand(0, 300)));
        }

        return $goods;
    }


    /**
     * 根据商品 id 获取所有商品,分页
     *
     * @param string $goodsIds
     * @return array
     */
    public static function getGoodsListByIds($goodsIds)
    {
        $goodsIdsArray = explode(',', $goodsIds);
        $where = [
            'status' => 'up',
            'deletetime' => null,
            'id' => ['in', $goodsIdsArray]
        ];
        $goods = self::where($where)->paginate(10);

        if ($goods->items()) {
            $collection = collection($goods->items());
            $data = $collection->hidden(self::$list_hidden);

            // 处理活动
            // load_relation($data, 'skuPrice');        // 只针对数组
            $data->load('skuPrice');        // 延迟预加载
            foreach ($data as $key => $g) {
                $data[$key] = self::operActivity($g, $g['sku_price']);
            }

            $goods->data = $data;
        }
        return $goods;
    }

    public static function getFavoriteGoodsList($type = 'normal', $status = 'up')
    {
        $where = [
            'type' => $type,
            'status' => $status,
            'deletetime' => null,
        ];

        $goods = self::where($where)->paginate(10);

        if ($goods->items()) {
            $collection = collection($goods->items());
            $data = $collection->hidden(self::$list_hidden);
            $goods->data = $data;
        }
        return $goods;

    }



    /**
     * 获取商品详情
     *
     * @param int $id
     * @return object
     */
    public static function getGoodsDetail($id)
    {
        $user = User::info();

        $detail = (new self)->where('id', $id)->with(['favorite' => function ($query) use ($user) {
            $user_id = empty($user) ? 0 : $user->id;
            return $query->where(['user_id' => $user_id]);
        }])->find();

        if (!$detail || $detail->status === 'down') {
            throw new Exception('商品不存在或已下架');
        }
        
        $detail = $detail->append(['service', 'sku', 'coupons']);

        // 处理活动规格
        $detail = self::operActivity($detail, $detail->sku_price);
        
        return $detail;
    }



    



    public function getCouponsAttr($value, $data)
    {
        $goods_id = $data['id'];

        $coupons = Coupons::where(function ($query) use ($goods_id) {
            $query->where('find_in_set('. $goods_id .',goods_ids)')
                ->whereOr('goods_ids', 0);
        })->select();

        return $coupons;
    }


    protected function getSkuAttr($value, $data)
    {
        $sku = GoodsSku::all([
            'goods_id'=>$data['id'],
            'pid' => 0,
        ]);
        foreach ($sku as $s => &$k) {
            $sku[$s]['content'] = GoodsSku::all([
                'goods_id' => $data['id'],
                'pid' => $k['id']
            ]);
        }
        return $sku;
    }

    private static function getSkuPrice($value, $data)
    {
        return GoodsSkuPrice::all([
            'goods_id' => $data['id'],
            'status' => 'up',
            'deletetime' => null
        ]);
    }

    public function getActivityStatusAttr($value, $data) {
        $activity_status = null;
        if ($data['activity_starttime'] > time()) {
            $activity_status = 'waiting';
        } else if ($data['activity_endtime'] && $data['activity_endtime'] < time()) {
            $activity_status = 'ended';
        } else if ($data['activity_starttime'] < time() && $data['activity_endtime'] > time()) {
            $activity_status = 'ing';
        }
        return $activity_status;
    }

    public function getParamsAttr($value, $data)
    {
        return $value ? json_decode($value, true) : [];
    }


    public function getLimitRulesArrAttr($value, $data)
    {
        return $data['limit_rules'] ? json_decode($data['limit_rules'], true) : [];
    }


    public function getServiceAttr($value, $data)
    {
        $value = $data['service_ids'];
        $serviceData = [];
        if (!empty($value)) {
            $serviceArray = explode(',', $value);
            $serviceData = [];
            foreach ($serviceArray as $v) {
                $serviceData[] = \addons\groupon\model\GoodsService::get($v);
            }
        }
        return $serviceData;
    }

    public function getImageAttr($value, $data)
    {
        if (!empty($value)) return cdnurl($value, true);

    }

    public function getImagesAttr($value, $data)
    {
        $imagesArray = [];
        if (!empty($value)) {
            $imagesArray = explode(',', $value);
            foreach ($imagesArray as &$v) {
                $v = cdnurl($v, true);
            }
            return $imagesArray;
        }
        return $imagesArray;
    }


    public function getContentAttr($value, $data)
    {
        $content = $data['content'];
        $content = str_replace("<img src=\"/uploads", "<img style=\"width: 100%;!important\" src=\"" . cdnurl("/uploads", true), $content);
        $content = str_replace("<video src=\"/uploads", "<video style=\"width: 100%;!important\" src=\"" . cdnurl("/uploads", true), $content);
        return $content;

    }


    public function getTagsArrAttr($value, $data) {
        return $data['tags'] ? array_filter(explode(',', $data['tags'])) : [];
    }

    public function favorite()
    {
        return $this->hasOne(\addons\groupon\model\UserFavorite::class, 'goods_id', 'id');
    }


    public function skuPrice()
    {
        return $this->hasMany(\addons\groupon\model\GoodsSkuPrice::class, 'goods_id', 'id')
                ->order('id', 'asc');
    }

    //商品列表排序
    private static function getGoodsListOrder($orderStr)
    {
        $order = 'weigh desc';
        $orderList = json_decode(htmlspecialchars_decode($orderStr), true);
        extract($orderList);
        if (isset($defaultOrder) && $defaultOrder === 1) {
            $order = 'weigh desc';
        }
        if (isset($priceOrder) && $priceOrder === 1) {
            $order = "convert(`price`, DECIMAL(10, 2)) asc";
        }elseif (isset($priceOrder) && $priceOrder === 2) {
            $order = "convert(`price`, DECIMAL(10, 2)) desc";
        }
        if (isset($salesOrder) && $salesOrder === 1){
            $order = 'total_sales desc';
        }
        if (isset($newProdcutOrder) && $newProdcutOrder === 1){
            $order = 'id desc';
        }
        return $order;

    }
}