// +---------------------------------------------------------------------- namespace app\common\model\store\product; use app\common\dao\store\StoreSeckillActiveDao; use app\common\model\BaseModel; use app\common\model\store\coupon\StoreCouponProduct; use app\common\model\store\Guarantee; use app\common\model\store\GuaranteeTemplate; use app\common\model\store\GuaranteeValue; use app\common\model\store\parameter\ParameterValue; use app\common\model\store\shipping\ShippingTemplate; use app\common\model\store\StoreBrand; use app\common\model\store\StoreCategory; use app\common\model\store\StoreSeckillActive; use app\common\model\store\StoreSeckillTime; use app\common\model\system\form\Form; use app\common\model\system\merchant\Merchant; use app\common\repositories\store\StoreCategoryRepository; use crmeb\services\VicWordService; use Darabonba\GatewaySpi\Models\InterceptorContext\request; use think\db\BaseQuery; use think\facade\Db; use think\model\concern\SoftDelete; class Product extends BaseModel { use SoftDelete; protected $deleteTime = 'is_del'; protected $defaultSoftDelete = 0; /** * @Author:Qinii * @Date: 2020/5/8 * @return string */ public static function tablePk(): string { return 'product_id'; } /** * @Author:Qinii * @Date: 2020/5/8 * @return string */ public static function tableName(): string { return 'store_product'; } /* * ----------------------------------------------------------------------------------------------------------------- * 属性 * ----------------------------------------------------------------------------------------------------------------- */ public function getSliderImageAttr($value) { return $value ? explode(',', $value) : []; } public function getGiveCouponIdsAttr($value) { return $value ? explode(',', $value) : []; } public function getMaxExtensionAttr($value) { if ($this->extension_type) { $org_extension = ($this->attrValue()->order('extension_one DESC')->value('extension_one')); } else { $org_extension = bcmul(($this->attrValue()->order('price DESC')->value('price')), systemConfig('extension_one_rate'), 2); } $spreadUser = (request()->hasMacro('isLogin') && request()->isLogin() && request()->userType() == 1) ? request()->userInfo() : null; if ($spreadUser && $spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); } return $org_extension; } public function getMinExtensionAttr($value) { if ($this->extension_type) { $org_extension = ($this->attrValue()->order('extension_two ASC')->value('extension_two')); } else { $org_extension = bcmul(($this->attrValue()->order('price ASC')->value('price')), systemConfig('extension_two_rate'), 2); } $spreadUser = (request()->hasMacro('isLogin') && request()->isLogin() && request()->userType() == 1) ? request()->userInfo() : null; if ($spreadUser && $spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); } return $org_extension; } public function check() { if (!$this || !$this->is_show || !$this->is_used || !$this->status || $this->is_del || !$this->mer_status) return false; return true; } /** * TODO 秒杀商品结束时间 * @return false|int * @author Qinii * @day 2020-08-15 */ public function getEndTimeAttr() { if ($this->product_type !== 1) return true; $end_day = strtotime($this->seckillActive['end_day']); if ($end_day > time()) { return strtotime($this->seckillActive['end_day']); } else { return time(); } } /** * TODO 自动上架时间转换 * @param $value * @param $data * @return string */ public function getAutoOnTimeAttr($value,$data) { if($value){ return date('Y-m-d H:i:s',$value); } } /** * TODO 自动下架时间转换 * @param $value * @param $data * @return string */ public function getAutoOffTimeAttr($value,$data) { if($value){ return date('Y-m-d H:i:s',$value); } } /** * 秒杀商品状态 * @return int|true * FerryZhao 2024/4/25 */ public function getSeckillStatusAttr($value,$data) { if ($this->product_type !== 1) return true; if ($this->seckillActive && $this->seckillActive['active_status'] !== -1) { $end_day = strtotime($this->seckillActive->getData('end_day')); if ($end_day <= time()) return -1;//已结束 $start_day = strtotime($this->seckillActive['start_day']); if ($start_day <= time()) { $currentHour = date('G', time()); $data = StoreSeckillTime::whereIn('seckill_time_id',$this->seckillActive->seckill_time_ids) ->where('start_time','<=',$currentHour)->where('end_time','>',$currentHour) ->where('status',1) ->find(); if ($data) { return 1; } else { return 0; } } else { //还未开始 return 0; } } //已结束 return -1; } public function getImageAttr($value) { if (is_int(strpos($value, 'http'))) { return $value; } else { return rtrim(systemConfig('site_url'), '/') . $value; } } public function getTopReplyAttr() { $res = []; if (systemConfig('sys_reply_status')) { $res = ProductReply::where('product_id', $this->product_id)->where('is_del', 0)->with(['orderProduct'])->field('reply_id,uid,nickname,merchant_reply_content,avatar,order_product_id,product_id,product_score,service_score,postage_score,comment,pics,rate,create_time') ->order('sort DESC,create_time DESC')->limit(1)->find(); if (!$res) return null; if ($res['orderProduct']) $res['sku'] = $res['orderProduct']['cart_info']['productAttr']['sku']; unset($res['orderProduct']); if (strlen($res['nickname']) > 1) { $str = mb_substr($res['nickname'], 0, 1) . '*'; if (strlen($res['nickname']) > 2) { $str .= mb_substr($res['nickname'], -1, 1); } $res['nickname'] = $str; } } return $res; } public function getUsStatusAttr() { return ($this->status == 1) ? ($this->is_used == 1 ? ($this->mer_status == 1 && $this->is_show == 1 ? 1 : 0) : -1) : -1; } public function getGuaranteeTemplateAttr() { $gua = GuaranteeTemplate::where('guarantee_template_id', $this->guarantee_template_id)->where('status', 1)->where('is_del', 0)->find(); if (!$gua) return []; $guarantee_id = GuaranteeValue::where('guarantee_template_id', $this->guarantee_template_id)->column('guarantee_id'); return Guarantee::where('guarantee_id', 'in', $guarantee_id)->where('status', 1)->where('is_del', 0)->select(); } public function getMaxIntegralAttr() { if (systemConfig('integral_status') && merchantConfig($this->mer_id, 'mer_integral_status')) { $price = ($this->attrValue()->order('price DESC')->value('price')); $rate = ($this->integral_rate < 0) ? merchantConfig($this->mer_id, 'mer_integral_rate') : $this->integral_rate; $rate = $rate > 0 ? $rate / 100 : 0; return bcmul($price, $rate, 2); } return '0'; } public function getHotRankingAttr() { if ($this->product_type == 0) { $where = [ 'is_show' => 1, 'status' => 1, 'is_used' => 1, 'product_type' => 0, 'mer_status' => 1, 'is_gift_bag' => 0, 'cate_id' => $this->cate_id ]; self::where($where)->order('sales DESC'); } } public function getOtPriceAttr($value) { if ($this->product_type == 20) { return (int)$value; } return $value; } /** * TODO 商品参数 * @author Qinii * @day 2022/11/24 */ public function getParamsAttr() { if (in_array($this->product_type, [0, 2])) { $product_id = $this->product_id; } else { $product_id = $this->old_product_id; } return ParameterValue::where('product_id', $product_id)->order('parameter_value_id ASC')->select(); } public function getParamTempIdAttr($value) { return $value ? explode(',', $value) : $value; } /** * TODO 是否是会员 * @return bool * @author Qinii * @day 2023/1/4 */ public function getIsVipAttr() { if (request()->hasMacro('isLogin') && request()->isLogin()) { if (request()->userType() == 1) { $userInfo = request()->userInfo(); return $userInfo->is_svip > 0 ? true : false; } else { return true; } } return false; } /** * TODO 是否展示会员价 * @return bool * @author Qinii * @day 2023/1/4 */ public function getShowSvipPriceAttr() { if ($this->mer_svip_status != 0 && (systemConfig('svip_show_price') != 1 || $this->is_vip) && $this->svip_price_type > 0) { return true; } return false; } /** * TODO 是否显示会员价等信息 * @return array * @author Qinii * @day 2022/11/24 */ public function getShowSvipInfoAttr() { $res = [ 'show_svip' => true, //是否展示会员入口 'is_svip' => false, //当前用户是否是会员 'show_svip_price' => false, //是否展示会员价 'save_money' => 0, //当前商品会员优化多少钱 ]; if ($this->product_type == 0) { if (!systemConfig('svip_switch_status')) { $res['show_svip'] = false; } else { $res['is_svip'] = $this->is_vip; if ($this->show_svip_price) { $res['show_svip_price'] = true; $res['save_money'] = bcsub($this->price, $this->svip_price, 2); } } } return $res; } /** * TODO 获取会员价 * @return int|string * @author Qinii * @day 2023/1/4 */ public function getSvipPriceAttr() { if ($this->product_type == 0 && $this->mer_svip_status != 0 && $this->show_svip_price) { //默认比例 if ($this->svip_price_type == 1) { $rate = merchantConfig($this->mer_id, 'svip_store_rate'); $svip_store_rate = $rate > 0 ? bcdiv($rate, 100, 2) : 0; $price = $this->attrValue()->order('price ASC')->value('price'); return bcmul($price, $svip_store_rate, 2); } //自定义 if ($this->svip_price_type == 2) { return $this->getData('svip_price'); } } return 0; } public function getIsSvipPriceAttr() { if ($this->product_type == 0 && $this->mer_svip_status != 0) { //默认比例 if ($this->svip_price_type == 1) { $rate = merchantConfig($this->mer_id, 'svip_store_rate'); $svip_store_rate = $rate > 0 ? bcdiv($rate, 100, 2) : 0; $price = $this->attrValue()->order('price ASC')->value('price'); return bcmul($price, $svip_store_rate, 2); } //自定义 if ($this->svip_price_type == 2) { return $this->getData('svip_price'); } } return 0; } public function getGoodIdsAttr($value, $data) { if (empty($value)) { return []; } return explode(',', $value); } /* * ----------------------------------------------------------------------------------------------------------------- * 关联模型 * ----------------------------------------------------------------------------------------------------------------- */ public function merCateId() { return $this->hasMany(ProductCate::class, 'product_id', 'product_id')->field('product_id,mer_cate_id'); } public function attr() { return $this->hasMany(ProductAttr::class, 'product_id', 'product_id'); } public function attrValue() { return $this->hasMany(ProductAttrValue::class, 'product_id', 'product_id'); } public function oldAttrValue() { return $this->hasMany(ProductAttrValue::class, 'product_id', 'old_product_id'); } public function content() { return $this->hasOne(ProductContent::class, 'product_id', 'product_id'); } protected function temp() { return $this->hasOne(ShippingTemplate::class, 'shipping_template_id', 'temp_id'); } public function storeCategory() { return $this->hasOne(StoreCategory::class, 'store_category_id', 'cate_id')->field('store_category_id,cate_name'); } public function merchant() { return $this->hasOne(Merchant::class, 'mer_id', 'mer_id')->field('is_trader,type_id,mer_id,mer_name,mer_avatar,product_score,service_score,postage_score,service_phone,care_count,is_margin'); } public function reply() { return $this->hasMany(ProductReply::class, 'product_id', 'product_id')->order('create_time DESC'); } public function brand() { return $this->hasOne(StoreBrand::class, 'brand_id', 'brand_id')->field('brand_id,brand_name'); } public function seckillActive() { return $this->hasOne(StoreSeckillActive::class, 'seckill_active_id', 'active_id'); } public function issetCoupon() { return $this->hasOne(StoreCouponProduct::class, 'product_id', 'product_id')->alias('A') ->rightJoin('StoreCoupon B', 'A.coupon_id = B.coupon_id')->where(function (BaseQuery $query) { $query->where('B.is_limited', 0)->whereOr(function (BaseQuery $query) { $query->where('B.is_limited', 1)->where('B.remain_count', '>', 0); }); })->where(function (BaseQuery $query) { $query->where('B.is_timeout', 0)->whereOr(function (BaseQuery $query) { $time = date('Y-m-d H:i:s'); $query->where('B.is_timeout', 1)->where('B.start_time', '<', $time)->where('B.end_time', '>', $time); }); })->field('A.product_id,B.*')->where('status', 1)->where('type', 1)->where('send_type', 0)->where('is_del', 0) ->order('sort DESC,coupon_id DESC')->hidden(['is_del', 'status']); } public function assist() { return $this->hasOne(ProductAssist::class, 'product_id', 'product_id'); } public function productGroup() { return $this->hasOne(ProductGroup::class, 'product_id', 'product_id'); } public function guarantee() { return $this->hasOne(GuaranteeTemplate::class, 'guarantee_template_id', 'guarantee_template_id')->where('status', 1)->where('is_del', 0); } public function getForm() { return $this->hasOne(Form::class, 'form_id', 'mer_form_id'); } public function getFormName() { return $this->hasOne(Form::class, 'form_id', 'mer_form_id')->bind(['mer_form_name' => 'name']); } /* * ----------------------------------------------------------------------------------------------------------------- * 搜索器 * ----------------------------------------------------------------------------------------------------------------- */ public function searchMerCateIdAttr($query, $value) { $cate_ids = (StoreCategory::where('path', 'like', '%/' . $value . '/%'))->column('store_category_id'); $cate_ids[] = intval($value); $product_id = ProductCate::whereIn('mer_cate_id', $cate_ids)->column('product_id'); $query->whereIn('Product.product_id', $product_id); } public function searchKeywordAttr($query, $value) { if (!$value) return; if (is_numeric($value)) { $query->whereLike("Product.store_name|Product.keyword|bar_code|Product.product_id", "%{$value}%"); } else if (is_array($value)) { $query->where(function ($query) use ($value) { foreach ($value as $item) { $query->whereOr('Product.store_name|Product.keyword', 'LIKE', "%$item%"); } }); } else { $word = app()->make(VicWordService::class)->getWord($value); $query->where(function ($query) use ($word, $value) { foreach ($word as $item) { $query->whereOr('Product.store_name|Product.keyword', 'LIKE', "%$item%"); } $query->order(Db::raw('REPLACE(Product.store_name,\'' . $value . '\',\'\')')); }); } } public function searchStatusAttr($query, $value) { if ($value === -1) { $query->where('Product.status', 'in', [-1, -2]); } else { $query->where('Product.status', $value); } } public function searchCatePidAttr($query, $value) { $query->when($value, function ($query) use ($value) { $storeCategoryRepository = app()->make(StoreCategoryRepository::class); if (is_array($value)) { $cateIds = $storeCategoryRepository->selectChildrenId($value); } else { $cateIds = $storeCategoryRepository->findChildrenId((int)$value); $cateIds[] = $value; } $query->whereIn('cate_id', $cateIds); }); } public function searchCateIdAttr($query, $value) { $query->where('cate_id', $value); } public function searchCateIdsAttr($query, $value) { $query->whereIn('cate_id', $value); } public function searchIsShowAttr($query, $value) { if($value == 0){ $query->whereIn('is_show',[0,2]); }else{ $query->where('is_show', $value); } } public function searchPidAttr($query, $value) { $childrenId = app()->make(StoreCategoryRepository::class)->findChildrenId((int)$value); $ids = array_merge($childrenId, [(int)$value]); $query->whereIn('cate_id', $ids); } public function searchStockAttr($query, $value) { $value ? $query->where('stock', '<=', $value) : $query->where('stock', $value); } public function searchIsNewAttr($query, $value) { $query->where('is_new', $value); } public function searchPriceAttr($query, $value) { if (empty($value[0]) && !empty($value[1])) $query->where('price', '<', $value[1]); if (!empty($value[0]) && empty($value[1])) $query->where('price', '>', $value[0]); if (!empty($value[0]) && !empty($value[1])) $query->whereBetween('price', [$value[0], $value[1]]); } public function searchBrandIdAttr($query, $value) { $query->whereIn('brand_id', $value); } public function searchIsGiftBagAttr($query, $value) { $query->where('is_gift_bag', $value); } public function searchIsGoodAttr($query, $value) { $query->where('is_good', $value); } public function searchIsUsedAttr($query, $value) { $query->where('is_used', $value); } public function searchProductTypeAttr($query, $value) { $query->where('Product.product_type', $value); } // public function searchSeckillStatusAttr($query, $value) // { // $product_id = (new StoreSeckillActiveDao())->getStatus($value)->column('product_id'); // $query->whereIn('Product.product_id', $product_id); // } public function searchStoreNameAttr($query, $value) { $query->where('Product.store_name', 'like', '%' . $value . '%'); } public function searchMerStatusAttr($query, $value) { $query->where('mer_status', $value); } public function searchProductIdAttr($query, $value) { $query->where('Product.product_id', $value); } public function searchProductIdsAttr($query, $value) { $query->whereIn('Product.product_id', $value); } public function searchNotProductIdAttr($query, $value) { if (!empty($value)) { if (is_array($value)) { $query->whereNotIn('Product.product_id', $value); } else { $query->where('Product.product_id', '<>', $value); } } } public function searchPriceOnAttr($query, $value) { $query->where('price', '>=', $value); } public function searchPriceOffAttr($query, $value) { $query->where('price', '<=', $value); } public function searchisFictiAttr($query, $value) { $query->where('type', $value); } public function searchGuaranteeTemplateIdAttr($query, $value) { $query->whereIn('guarantee_template_id', $value); } public function searchTempIdAttr($query, $value) { $query->whereIn('Product.temp_id', $value); } public function searchDateAttr($query, $value) { getModelTime($query, $value, 'Product.create_time'); } public function searchFormIdAttr($query, $value) { if ($value !== '') { $query->whereIn('Product.mer_form_id', $value); } } public function searchMerFormIdAttr($query, $value) { if ($value !== '') { $query->whereIn('Product.mer_form_id', $value); } } }